Index over opgaver i denne lektion   Alfabetisk indeks   Kursets hjemmeside   

Opgaver og løsninger
Kontrolstrukturer


3.1   Inden i eller uden for en cirkel  

Det er ofte nyttigt at kunne afgøre, om et punkt i et koordinatsystem er placeret inden i eller udenfor en bestemt cirkel.

Skriv et program med tre doubles r, x og y.   r fortolkes som radius af en cirkel omkring punktet (0,0). x og y er koordinaterne (x, y) af et punkt.

Programmet skal afgøre om punktet (x, y) er placeret inden i cirklen, på cirkelperiferien, eller uden for cirklen. Der er altså tre tilfælde. I bedes have tre logiske udtryk, assignet til tre logiske variable, som afspejler de tre forskellige situationer.

Kan I lave én printf med brug af betingede udtryk (?:), der udskriver 'inden i'/'uden for' og 'på' cirklen, baseret på de logiske udtryks værdi?

Hint: Det kan være svært at ramme periferien eksakt, fordi vi regner med doubles. Derfor kan I antage at punktet er 'på periferien' hvis det er ganske tæt på periferien. Indfør en symbolsk konstant DELTA, der fortæller hvor meget vi ønsker at kunne afvige fra et "perfect hit".

Løsning

Her er et muligt program, der løser opgaven:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define DELTA 0.000001

int main(void){
  double r = 0.0, x = 0.0, y = 0.0;

  /* Prompt for input: */
  printf("Enter radius, x, and y:\n");
  scanf(" %lf %lf %lf", &r, &x, &y);

  if (fabs(x*x + y*y - r*r) < DELTA)
    printf("The point (%1.4f,%1.4f) is on the circle\n", x, y);
  else if (x*x + y*y < r*r)
    printf("The point (%1.4f,%1.4f) is inside the circle\n", x, y);
  else
    printf("The point (%1.4f,%1.4f) is outside the circle\n", x, y);

  return EXIT_SUCCESS;
}

Her er en udgave som kun har print-detaljerne én gang, og som gør brug af nogle logiske assignments (til on-circle, inside og outside):

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define DELTA 0.000001

int main(void){
  double r = 0.0, x = 0.0, y = 0.0;
  int inside = 0, on_circle = 0, outside = 0;

  /* Prompt for input: */
  printf("Enter radius, x, and y:\n");
  scanf(" %lf %lf %lf", &r, &x, &y);

  /* Calculate inside, on circle, or outside */
  on_circle = fabs(x*x + y*y - r*r) < DELTA;
  inside = x*x + y*y < r*r;
  outside = !(inside || on_circle);

  /* Print results: */
  printf("The point (%1.4f,%1.4f) is %s with center point (0,0).\n",
         x, y, 
         on_circle ? "on circle" : inside ? "inside circle" : "outside circle");
  
  return EXIT_SUCCESS;
}


3.2   Operator prioriteter i logiske udtryk  

Denne opgaver giver dig træning i at anvende operator prioritering i logiske udtryk. Det er ikke nødvendigt at beregne værdierne af udtrykkene. Lad blot computeren foretage de faktiske beregninger.

Se på følgende C program:

#include <stdio.h>

int main(void){

  int a = 1, b = 2, c = 3;
  double x = 1.0;

  int res1, res2, res3, res4;

  res1 = a > b && c < x;
  res2 = a < ! b || ! ! a;
  res3 = a + b < ! c + c;
  res4 = a - x || b * c && b / a;

  printf("res1 = %d, res2 = %d, res3 = %d,  res4 = %d \n", 
	 res1, res2, res3, res4);

  return 0;
}

Sæt parenteres i de fire sammensatte, logiske udtryk, hvis værdier assignes til variablene res1, ..., res4. Ved at sætte parenteser bliver det klart, hvorledes de sammensatte udtryk beregnes. Vær sikker på at du anvender operator prioriteringerne i C, for at sætte parenteserne korrekt.

Check at overstående program, og dit modificerede program, er ækvivalente (giver det samme output når værdierne af res1, ..., res4 udskrives).

Løsning

Her er både det oprindelige program og tilføjelser, som sætter de ønskede parenteser:

#include <stdio.h>

int main(void){

  int a = 1, b = 2, c = 3;
  double x = 1.0;

  int res1, res2, res3, res4;
  int res1_equiv, res2_equiv, res3_equiv, res4_equiv;

  res1 = a > b && c < x;
  res2 = a < ! b || ! ! a;
  res3 = a + b < ! c + c;
  res4 = a - x || b * c && b / a;

  printf("res1 = %d, res2 = %d, res3 = %d,  res4 = %d \n", 
	 res1, res2, res3, res4);

  res1_equiv = (a > b) && (c < x);
  res2_equiv = (a < (! b)) || (! (! a));
  res3_equiv = (a + b) < ((! c) + c);
  res4_equiv = (a - x) || ((b * c) && (b / a));

  printf("res1 = %d, res2 = %d, res3 = %d,  res4 = %d \n", 
	 res1_equiv, res2_equiv, res3_equiv, res4_equiv);

  return 0;

}


3.3   pH værdier  

I denne opgave antages det, at du lige har løst self-check opgave 3 side 236 i lærebogen Problem Solving and Program Design in C, eighth edition.

Målet med opgaven er at træne din evne til at arbejde med nestede if-else konstrolstrukturer, herunder if-else kæder (multiple alternative if statements).

Sammenlign din løsning med følgende if-else kæde (som bogen kalder en multiple-alternative if):

  if (ph <= 2)
     printf("Very acidic");  
  else if (ph < 7) 
     printf("Acidic");       
  else if (ph == 7)
     printf("Neutral");      
  else if (ph < 12)
     printf("Alkaline");     
  else 
     printf("Very alkaline");

Er ovenstående if-else kæde ækvivalent med din løsning på bogens opgave? Som en hjælp til afgørelsen, skriv en kommentar efter hvert printf kald som viser præcist, for hvilket interval pH værdier udskriften er gældende. Du skal være meget omhyggelig og systematisk - ellers laver du let en fejl.

Løsning

If-else kæden, som blev vist i denne opgave, er ækvivalent med bogens flowchart.

Overbevis dig selv om dette ved at notere for hver af de grå kasser i bogens flowchart, hvilket pH interval der leder til denne 'udskrift'.

Tilsvarende, i den programstump som jeg viser i denne opgave, noter for hver printf hvilke pH værdier der leder til en bestemt udskrift. Husk i den forbindelse på, at hvis en bestemt printf udføres i en if-else kæde (altså i en multiple-alternative if) så er det logiske udtryk i den nærmeste if sand, og alle de logiske udtryk i de if'erne ovenover er falske.

Opgave 3 side 236 i bogen giver umiddelbart anledning til følgende if-statements:

  if (ph > 7){
    if (ph < 12)
      printf("Alkaline");
    else 
      printf("Very alkaline");
  }
  else { 
     if (ph == 7)
       printf("Neutral");
     else if (ph > 2)
       printf("Acidic");  
     else
       printf("Very acidic");  
  }


3.4   Timer, minutter og sekunder - igen  

Denne opgave er en fortsættelse af en tidligere opgave, hvor vi konverterede hele sekunder til uger, dage, timer, minutter og sekunder efter sædvanlige principper. I denne opgave begrænser vi os til timer, minutter og sekunder (vi dropper altså interessen for uger og dage).

Målet med opgaven er at træne dig i at bruge af if-else kæder, if'er i sekvens og betingede udtryk (med ?: operatoren). Målet er endvidere at opdele et lidt større program i mindre og markerede dele inden for main.

Det er sjusket og utilfredsstillende når det oprindelige program giver output som dette:

Vi ønsker at blive fri for '0 timer' og '0 minutter'. Endvidere ønsker vi korrekt angivelse af ental og flertal. Derfor foretrækker vi et program der giver følgende output:

Skriv en ny version af programmet, som opfylder disse krav.

Overvej ombyggelig brugen af if-else kæder kontra sekvenser af if kontra betingede udtryk med brug af den ternære operator ?:

Løsning

Kommer senere...


3.5   Ordningen af betingelser i en if-else kæde  

Vi har på en tidligere slide set på følgende program med en if-else kæde:

#include <stdio.h>

int main(void) {

  int percent, grade;

  printf("How many percent? ");
  scanf("%d",&percent);

  if (percent >= 90)
    grade = 11;
  else if (percent >= 82)
    grade = 10;
  else if (percent >= 74)
    grade = 9;
  else if (percent >= 66)
    grade = 8;
  else if (percent >= 58)
    grade = 7;
  else if (percent >= 50)
    grade = 6;
  else if (percent >= 40)
    grade = 5;
  else if (percent >= 10)
    grade = 3;
  else grade = 0; 

  printf("%d percent corresponds to the Danish grade %d\n\n", 
          percent, grade);
  
  return 0;
}

Nu bytter vi om på tilfældene i if-else kæden (dog bevarer vi else-delen):

#include <stdio.h>

int main(void) {

  int percent, grade;

  printf("How many percent? ");
  scanf("%d",&percent);

  if (percent >= 10)
    grade = 3;
  else if (percent >= 40)
    grade = 5;
  else if (percent >= 50)
    grade = 6;
  else if (percent >= 58)
    grade = 7;
  else if (percent >= 66)
    grade = 8;
  else if (percent >= 74)
    grade = 9;
  else if (percent >= 82)
    grade = 10;
  else if (percent >= 90)
    grade = 11;
  else grade = 0; 

  printf("%d percent corresponds to the Danish grade %d\n\n", 
          percent, grade);
  
  return 0;
}

Ændrer dette betydningen af programmet? Uddrag en generel tommelfingerregel for ordningen af de logiske udtryk i en if-else kæde.

Løsning

Det foreslåede program

#include <stdio.h>

int main(void) {

  int percent, grade;

  printf("How many percent? ");
  scanf("%d",&percent);

  if (percent >= 10)
    grade = 3;
  else if (percent >= 40)
    grade = 5;
  else if (percent >= 50)
    grade = 6;
  else if (percent >= 58)
    grade = 7;
  else if (percent >= 66)
    grade = 8;
  else if (percent >= 74)
    grade = 9;
  else if (percent >= 82)
    grade = 10;
  else if (percent >= 90)
    grade = 11;
  else grade = 0; 

  printf("%d percent corresponds to the Danish grade %d\n\n", 
          percent, grade);
  
  return 0;
}

er ikke korrekt. Det første tilfælde indfanger alle de andre tilfælde. Derfor vil vi aldrig komme ind i tilfælde 2 - 8. Vi kommer dog ind i den sidste else-del, hvis (percent < 10).

Moralen er at de logiske udtryk skal ordnes så de mest specielle tilfælde (snævre tilfælde) håndteres før de mere generelle tilfælde (de bredere tilfælde).

I dette eksempel er tilfældet (percent >= 90) mere snævert end tilfældet (percent >= 82).


Genereret: Fredag 17. september 2021, 14:24:45