3
#include <stdio.h>

int main(void) {
    float score1;
    float score2;
    float score3;
    float value;

    printf("Please enter three exam score: ");
    scanf("%f", &score1);
    scanf("%f", &score2);
    scanf("%f", &score3);
    printf("First exam:    %.1f", score1);
    printf("%%\\n");
    printf("Second exam:   %.0f", score2);
    printf("%%\\n");
    printf("Third exam:    %.0f", score3);
    printf("%%\\n");
    printf("-----------------------------------");

    value = (score1 + score2 + score3) / 3.0;

    printf("\\n");
    printf("Average:       %.14f",value);
    printf("%%.\\n");

    return 0;
}

-here is my code. the three scores are 75.5 92 100 and the average of these is 89.16666666666667%. but I am getting 89.16666412353516%. as the average when I run the program. any help is appreciated!

Thank you -Slurpski

Chris
  • 26,361
  • 5
  • 21
  • 42
Slurpski
  • 25
  • 1
  • Your value looks fine because you are using `float`. Try entering `89.16666666666667` to the "You entered" field of [IEEE-754 Floating Point Converter](https://www.h-schmidt.net/FloatConverter/IEEE754.html). – MikeCAT Mar 29 '22 at 20:04
  • 1
    @pmg, On a x86/x86-64, we're probably talking about IEEE single-precision for `float`, IEEE double precision for `double`, and [this](https://en.wikipedia.org/wiki/Extended_precision#x86_extended_precision_format) for `long double`. That has log10(2^64) digits of precision, or just over 19. Not 34. – ikegami Mar 29 '22 at 20:15
  • 1
    `float` has like 6 or 7 digits of precision: **89.1666**6412353516; `double` has about 15 or 16 digits; and `long double` has maybe 19 or 20 digits (thank you @ikegami) --- see https://ideone.com/DtcfN1 – pmg Mar 29 '22 at 20:15
  • 3
    I was taught not to express values to have more significance than the original data, which here has 1 decimal place. [xkcd](https://xkcd.com/2170/). – Weather Vane Mar 29 '22 at 20:29

2 Answers2

2

Change float value; to double value; then you will get the value you want, which was 89.16666666666667.

Float is most likely a 32-bit IEEE 754 single precision Floating Point number (1 bit for the sign, 8 bits for the exponent, and 23 bits for the value). float has 7 decimal digits of precision.

  • 13
    No, you will just get closer to the correct value. – ikegami Mar 29 '22 at 20:10
  • IEEE-754 single-precision binary floating-point has 24-bit significands, not 23. 23 are encoded in the significand field and one is encoded via the exponent field. [And it has no decimal digits of precision; it uses base two.](https://stackoverflow.com/questions/61609276/how-to-calculate-float-type-precision-and-does-it-make-sense/61614323#61614323) – Eric Postpischil Mar 29 '22 at 20:27
  • 2
    @Eric Postpischil Re "*And it has no decimal digits of precision*", Sure it does. 24 bits of precision means log10( 2^24 ) =7.(...) digits of precision. – ikegami Mar 29 '22 at 20:29
  • @ikegami: Read the answer I linked to. There are **no** decimal digits in a binary numeral. That answer also discusses using a number of decimal digits as an approximation. – Eric Postpischil Mar 29 '22 at 20:32
  • @Eric Postpischil It really doesn't matter how many words you use, one can convert between binary and decimal just as easily as between litres and gallons – ikegami Mar 29 '22 at 20:34
  • @ikegami: Not with a fixed number of digits in the destination base, you cannot, in general. – Eric Postpischil Mar 29 '22 at 20:34
  • 1
    @Eric Postpischil, No idea what you mean in general, but you definitely can here. – ikegami Mar 29 '22 at 20:35
  • @ikegami: Really no idea? Show us the number represented by the decimal numeral 0.2 in binary with a finite number of binary digits. – Eric Postpischil Mar 29 '22 at 20:36
  • 1
    @Eric Postpischil, You can't. 2/10 is a periodic number in binary. – ikegami Mar 29 '22 at 20:39
  • @ikegami: That’s right. There are no decimal digits in the binary numeral, and you cannot represent all decimal numerals with it. – Eric Postpischil Mar 29 '22 at 20:40
  • 1
    @Eric Postpischil And I never said otherwise. I said it would have 7 digits of precision. And you do. You get 0.2000000[0298023223876953125] – ikegami Mar 29 '22 at 20:52
  • 1
    @ikegami: Telling people `float` or `double` have decimal digits of precision is what leads to Stack Overflow getting questions over and over and over and over again about why calculations with some purportedly decimal numbers go wrong. No, binary floating-point numbers do not have decimal digits of precision. You do arithmetic with them, and sooner or later the differences creep in, and you get results that differ from what you would get if the numbers **actually** had decimal digits of precision. With one decimal digit of precision, we can calculate 1/5 exactly. With binary, we cannot. – Eric Postpischil Mar 29 '22 at 20:55
  • 1
    @Eric Postpischil, Re "*why calculations with some purportedly decimal numbers go wrong.*", Hell no that's not the reason. They have no concept that it might be wrong after 7 or 15/16 digits. If they did, they wouldn't be asking the question. They don't know about the limited precision, and they have no concept that most decimal numbers are periodic in binary. That's the problem, and that's what the answer is always "X/10 is periodic in binary just like 1/3 is periodic in decimal, so X/10 can't accurately be represented by a floating point number without infinite storage." Every. Single. Time. – ikegami Mar 29 '22 at 22:10
  • @ikegami: Here is a seven-decimal-digit number: 8.589973e9. If you attempt to store it in a `float` and print it, it will not print that number. Give it a try, `printf("%.7g\n", 8.589973e9f);`. `float` does not have seven decimal digits of precision. – Eric Postpischil Mar 29 '22 at 23:29
  • @ikegami: Here is a seven-decimal-digit number: 8.589973e9. If you attempt to store it in a `float` (IEEE-754 binary32) and print it, the program will not print that number. Give it a try, `printf("%.7g\n", 8.589973e9f);`. The reason `float` cannot even record and reproduce a seven-decimal-digit number, let alone maintain seven digits when calculating with them, is that `float` does not have seven decimal digits of precision. – Eric Postpischil Mar 29 '22 at 23:36
  • @Eric Postpischil, That produces the number 8589973504. The first 7 digits are correct, but the 8th digit is wrong enough to affect the 7th when you round. Well, that's why I always say "23 bits (~7 digits)" in my answers – ikegami Mar 30 '22 at 01:14
  • @Nagmat, As mentioned earlier and corrected earlier, the mantissa (what you call "value") is 24 bits in size, not 23. [Ref](https://en.wikipedia.org/wiki/Single-precision_floating-point_format) It's encoded as part of the exponent ( e == 127 ? 0 : 1 ) – ikegami Mar 30 '22 at 01:16
  • @ikegami: First bit of the mantissa is `1` for finite numbers except for denormals where it is zero. It makes no sense to talk about mantissa bits for non-numbers (NaN has multiple distinguishable representations, but that is not a representation of a "mantissa") or infinities. Yes, denormals are indicated in the exponent, but that `e == 127` doesn't look at all like the right test, denormals have a very low exponent. Are you using `e` to mean stored representation or unbiased exponent? (Some of the representation bit patterns aren't an exponent at all, even considering bias) – Ben Voigt Mar 30 '22 at 19:28
2

1/6 is periodic in decimal, so it can't be represented exactly as a decimal floating point number. It would require infinite storage to do so. You claim 89.16666666666667 is correct, but it's not. You applied some rounding to obtain that.

1/6 is periodic in binary, so it can't be represented exactly by a floating point number. It would require infinite storage to do so. So some rounding must be applied. 89.16666412353515625 looks weird in decimal, but it's simply the correct number with some rounding applied in binary. Just like 89.16666666666667 is the closest number to the correct number after rounding in decimal, 89.16666412353515625 is the closest number to the correct number after rounding in binary. (This assumes the use of IEEE single-precision floating point number, which has 24 bits (~7 digits) of precision.)

Do you really need that many decimal places? I imagine it would be satisfactory to round the result to a decimal place or two.

ikegami
  • 367,544
  • 15
  • 269
  • 518
  • 3
    I was taught not to express values to have more significance than the original data, which here has 1 decimal place. [xkcd](https://xkcd.com/2170/). – Weather Vane Mar 29 '22 at 20:31
  • @WeatherVane: Why should we care if you were taught something? Lots of teachers all over the world teach incorrect concepts. Evaluation of a concept should depend on merit of the concept itself, not whether anybody was taught it. Rounding numbers loses information. – Eric Postpischil Mar 29 '22 at 20:34
  • @EricPostpischil well, the concept here, is to have a proportionate result. Exactly what relevant information was lost? – Weather Vane Mar 29 '22 at 20:36
  • @Eric Postpischil, It's a rule of thumb, and it works out great here. For a percentile test score, 2 decimal places is more than enough. (If anything, I'd argue that fewer would be better.) – ikegami Mar 29 '22 at 20:37
  • @WeatherVane: We do not know what relevant information was lost; the question does not state the purpose of this calculation. But 89⅙ could be a cut-off point between gradations of an exam score, so rounding it up to 89.16666666666667 could give a test taker an unearned reward. Or it could contribute to later scores falling above some threshold they should not. – Eric Postpischil Mar 29 '22 at 20:39
  • @EricPostpischil and how could rounding have been avoided without using a fraction? – Weather Vane Mar 29 '22 at 20:40
  • @WeatherVane: Who says you cannot use a fraction? Or, if you cannot use fractions, it is possible to perform the calculation so that the calculated results never cross a threshold they should not. E.g., one could check whether the result of the calculated division crosses a threshold that the original numerator and denominator did not and substitute a value on the desired side of the threshold. – Eric Postpischil Mar 29 '22 at 20:41
  • Anyway, that's why the answer asks if they could round, rather than tell them they should. The answer is almost definitely yes, but there are situations where that might be the case as @Eric Postpischil points out. I'll improve the wording a bit. – ikegami Mar 29 '22 at 20:44
  • @EricPostpischil you can, but OP is using a decimal. You wrote "Rounding numbers loses information" but without changing the question, we are stuck with a decimal, and round ing, be it 6 decimals or 20. – Weather Vane Mar 29 '22 at 20:44
  • @WeatherVane: OP is using binary (in `float`) and decimal (in `%.14f`) but has not stated what the program requirements are. Just because somebody shows you some code does not mean what the code does is the specification of what the program is desired to do. – Eric Postpischil Mar 29 '22 at 20:51
  • "closest decimal number to the correct number after rounding in binary" is convoluted and misleading. It is the exact decimal expression of the correct binary number (round to nearest). – Ben Voigt Mar 30 '22 at 19:32
  • @Ben Voight, Ambiguity removed. – ikegami Mar 30 '22 at 20:31