Alternativ 2:z = x + y / sqrt(x*x + y*y);
z = x + y / sqrt(pow(x, 2) + pow(y, 2));
struct spelare s = { "Kalle", 95.0, 18 };
Alternativ 2:talstrangen[0] = '0' + (int)talet; talstrangen[1] = '.'; talstrangen[2] = '0' + (int)(10 * talet) % 10; talstrangen[3] = '\0';
talstrangen[0] = '0' + (int)talet; talstrangen[1] = '.'; talstrangen[2] = '0' + (int)((talet - (int)talet ) * 10); talstrangen[3] = '\0';
Överkurs:
I själva verket kommer båda dessa algoritmer på de flesta datorer att ge fel svar just för värdet 5.1! (Provkör själv och se!)
Det beror på att reella tal inte (brukar) representeras exakt i en dator, utan med datatypen float, som lagras som ett binärt tal. En tiondel (0.1) går inte att representera exakt med binära flyttal, på samma sätt som en tredjedel inte går att representera exakt med vanliga decimala tal.
Om man tänker sig att en del flyttalsberäkningar ibland ger ett litet, slumpmässigt fel, och försöker skriva sina program så att de fungerar i alla fall, så brukar det bli rätt. I det här fallet kan man göra en avrundning, kanske så här:
talstrangen[0] = '0' + (int)talet; talstrangen[1] = '.'; talstrangen[2] = '0' + (int)(10 * (talet + 0.05)) % 10; talstrangen[3] = '\0';
int dagnummer(int datum) { return datum % 100; }
void visa_spelare(struct spelare b) { printf("Namn: %s\n", b.namn); printf("Vikt: %f\n", b.vikt); printf("Styrka: %d\n", b.styrka); }
Om man inkluderar header-filen ctype.h, får man tillgång till makrot isdigit:int is_ok_pnr_siffror(char *pnr) { for (int i = 0; i < 11; ++i) if (i != 6 && (pnr[i] < '0' || pnr[i] > '9')) return 0; return 1; }
Ytterligare ett alternativ, som jag själv kanske skulle välja i verkligheten:int is_ok_pnr_siffror(char *pnr) { for (int i = 0; i < 11; ++i) if (i != 6 && !isdigit(pnr[i])) return 0; return 1; }
Kommentar: Samtliga dessa lösningsförslag förutsätter att strängen är minst lika lång som ett riktigt personnummer. Strängar som är kortare kan orsaka felaktiga resultat eller programkrascher.int is_ok_pnr_siffror(char *pnr) { return isdigit(pnr[0]) && isdigit(pnr[1]) && isdigit(pnr[2]) && isdigit(pnr[3]) && isdigit(pnr[4]) && isdigit(pnr[5]) && isdigit(pnr[7]) && isdigit(pnr[8]) && isdigit(pnr[9]) && isdigit(pnr[10]); }
int is_ok_pnr_tecken(char *pnr) { return is_ok_pnr_siffror(pnr) && (pnr[6] == '-' || pnr[7] == '-'); }
Alternativ 2:struct spelare las_spelare() { struct spelare s; printf("Ange spelarens namn: "); scanf("%s", s.namn); printf("Ange spelarens vikt: "); scanf("%f", &s.vikt); printf("Ange spelarens styrka: "); scanf("%d", &s.styrka); return s; }
void las_spelare(struct spelare* p) { printf("Ange spelarens namn: "); scanf("%s", p->namn); printf("Ange spelarens vikt: "); scanf("%f", &p->vikt); printf("Ange spelarens styrka: "); scanf("%d", &p->styrka); }
Kommentarer:#include <stdio.h> int main() { char startbokstav; printf("Ge en stor bokstav: "); scanf("%c", &startbokstav); for (char bokstav = startbokstav; bokstav <= 'Z'; ++bokstav) printf("%c", bokstav); printf("\n"); return 0; }
#include <stdio.h> #include <math.h> int main() { float min, max, tal; printf("Ange minsta värdet: "); scanf("%f", &min); while (min >= 0) { printf("Ange största värdet: "); scanf("%f", &max); printf("Tal Rot\n"); printf("\n"); tal = min; while (tal <= max) { printf("%-6.2f %-6.2f\n", tal, sqrt(tal)); tal += 0.1; } printf("Ange minsta värdet: "); scanf("%f", &min); } return 0; }
Överkurs:
I själva verket kommer programmet ovan ibland att missa att skriva ut det sista värdet. (Provkör själv och se!)
Precis som problemen i uppgift 5 ovan, beror det på att reella tal inte (brukar) representeras exakt i en dator, utan med datatypen float, som lagras som ett binärt tal. En tiondel (0.1) går inte att representera exakt med binära flyttal, på samma sätt som en tredjedel inte går att representera exakt med vanliga decimala tal.
En regel är att man ska undvika likhetsjämförelser med flyttal. I programmet ovan ingår det en likhetsjämförelse i villkoret tal <= max, och den ger ibland ett oväntat resultat, just eftersom flyttal inte är en exakt korrekt representation av reella tal.
Hur ska man göra i stället? Jo, eftersom man ska undvika likhetsjämförelser med flyttal, bör vi använda ett heltal som styrvariabel i loopen. Heltal representeras alltid exakt, så där kan det aldrig bli några avrundningsfel.
#include <stdio.h> #include <math.h> int main() { float min, max, tal; int antal_steg; printf("Ange minsta värdet: "); scanf("%f", &min); while (min >= 0) { printf("Ange största värdet: "); scanf("%f", &max); printf("Tal Rot\n"); printf("\n"); antal_steg = 10 * (max - min) + 1; // Varför "+ 1"? Jo: // Mellan 1 och 2 finns 10 intervall, men 11 utskrifter! tal = min; for (int i = 0; i < antal_steg; ++i) { printf("%-6.2f %-6.2f\n", tal, sqrt(tal)); tal += 0.1; } printf("Ange minsta värdet: "); scanf("%f", &min); } return 0; }
Om man gjort den andra varianten av las_spelare i uppgift 10, den som tar en pekare som argument, ska de två anropen till las_spelare i stället se ut så här:#include <stdio.h> struct spelare { char namn[10]; // Spelarens namn float vikt; // Spelarens vikt int styrka; // Spelarens styrka }; // Stoppa in "las_spelare" och "visa_spelare" här int main() { struct spelare s1, s2; s1 = las_spelare(); s2 = las_spelare(); if (s1.vikt < s2.vikt || (s1.vikt == s2.vikt && s1.styrka <= s2.styrka)) { visa_spelare(s1); visa_spelare(s2); } else { visa_spelare(s2); visa_spelare(s1); } return 0; }
las_spelare(&s1); las_spelare(&s2);
#include <stdlib.h> #include <stdio.h> struct spelare { char namn[10]; // Spelarens namn float vikt; // Spelarens vikt int styrka; // Spelarens styrka }; int main() { int antal1 = 0, antal2 = 0, antal3 = 0, antal4 = 0; struct spelare s; FILE* tsin; tsin = fopen("spelare.txt", "r"); while (fscanf(tsin, "%s %f %d", s.namn, &s.vikt, &s.styrka) == 3) { if (s.vikt < 0) { printf("Otillåten vikt.\n"); exit(EXIT_FAILURE); } else if (s.vikt < 40) ++antal1; else if (s.vikt < 80) ++antal2; else if (s.vikt < 120) ++antal3; else ++antal4; } fclose(tsin); printf("0.0 - 39.9: %d\n", antal1); printf("40.0 - 79.9: %d\n", antal2); printf("80.0 - 119.9: %d\n", antal3); printf("120.0 - : %d\n", antal4); return 0; }
#include <stdio.h> int main(void) { int x, y, z, max; printf("Skriv tre heltal: "); scanf("%d", &x); scanf("%d", &y); scanf("%d", &z); if (x >= y && x > z) /* Här räknar vi ut */ max = x; /* vilket av de tre */ else if (y > x && y > z) /* talen x, y och z */ max = y; /* som är störst, */ else /* och lägger det i max. */ max = z; printf("Största talet: %d\n", max); return 0; }