435,009 Members | 2,866 Online + Ask a Question
Need help? Post your question and get tips & solutions from a community of 435,009 IT Pros & Developers. It's quick & easy.

Unwanted rounding

 P: n/a Hello, I have : float f = 36.09999999; When I do : char cf; sprintf(cf,"%0.03lf", f); I get : 36.100 How could I get 36.099 ? Thanks in advance. Dec 1 '06 #1
29 Replies

 P: n/a Marco <.said: Hello, I have : float f = 36.09999999; I recommend double rather than float. > When I do : char cf; sprintf(cf,"%0.03lf", f); Not lf - just f. > I get : 36.100 How could I get 36.099 ? Remove the precision specification (03), and then search the string for the decimal point, using strchr. Check that you have at least three valid characters (non-'\0') after the decimal point, and make the fourth one '\0' to truncate the string at the point you want. -- Richard Heathfield "Usenet is a strange place" - dmr 29/7/1999 http://www.cpax.org.uk email: rjh at the above domain, - www. Dec 1 '06 #2

 P: n/a Marco wrote: Hello, I have : float f = 36.09999999; When I do : char cf; sprintf(cf,"%0.03lf", f); I get : 36.100 How could I get 36.099 ? You can't. See http://c-faq.com/fp/printfprec.html Dec 1 '06 #3

 P: n/a ma**********@pobox.com said: > Marco wrote: >Hello,I have :float f = 36.09999999;When I do :char cf;sprintf(cf,"%0.03lf", f);I get : 36.100How could I get 36.099 ? You can't. See http://c-faq.com/fp/printfprec.html He can. See my parallel reply. -- Richard Heathfield "Usenet is a strange place" - dmr 29/7/1999 http://www.cpax.org.uk email: rjh at the above domain, - www. Dec 1 '06 #4

 P: n/a Richard Heathfield wrote: ma**********@pobox.com said: Marco wrote: Hello, I have : float f = 36.09999999; When I do : char cf; sprintf(cf,"%0.03lf", f); I get : 36.100 How could I get 36.099 ? You can't. See http://c-faq.com/fp/printfprec.html He can. See my parallel reply. OOPS! Mea Culpa. Thanks Dec 1 '06 #5

 P: n/a Richard Heathfield wrote: Remove the precision specification (03), and then search the string for the decimal point, using strchr. Check that you have at least three valid characters (non-'\0') after the decimal point, and make the fourth one '\0' to truncate the string at the point you want. It doesn't work (double, "%f") I read floating representation and I understood it can't work... Dec 1 '06 #6

 P: n/a Marco <.said: Richard Heathfield wrote: >Remove the precision specification (03), and then search the string forthe decimal point, using strchr. Check that you have at least three validcharacters (non-'\0') after the decimal point, and make the fourth one'\0' to truncate the string at the point you want. It doesn't work (double, "%f") I read floating representation and I understood it can't work... I think I understand what may be happening. When I first implemented a solution for you, I took your existing code, which used float, and did this: #include #include #include int main(void) { float f = 36.0999999; char cf = {0}; int i = 0; char *p = NULL; sprintf(cf, "%f", f); printf("[%s]\n", cf); p = strchr(cf, '.'); if(p != NULL) { ++p; while(i < 3 && isdigit(*p)) { ++i; ++p; } *p = '\0'; } printf("[%s]\n", cf); return 0; } This is what I got as output: [36.099998] [36.099] which is obviously correct. But if I follow my own suggestion and substitute float with double, I get this output: [36.100000] [36.100] Obviously not what you want! So I modified this line: sprintf(cf, "%f", f); to this: sprintf(cf, "%.16f", f); with this result: [36.0999999000000003] [36.099] which *is* what you want. -- Richard Heathfield "Usenet is a strange place" - dmr 29/7/1999 http://www.cpax.org.uk email: rjh at the above domain, - www. Dec 1 '06 #7

 P: n/a On Fri, 01 Dec 2006 10:54:43 +0100, wrote: Hello, I have : float f = 36.09999999; When I do : char cf; sprintf(cf,"%0.03lf", f); I get : 36.100 How could I get 36.099 ? Thanks in advance. #include #include int main( int argc, char** argv) { float f = 36.09999; printf( "%.3f\n", ((int)(f*1e3))*1e-3); return EXIT_SUCCESS; } Converting floats to integers doesn't cause rounding. Duncan Dec 1 '06 #8

 P: n/a Duncan Muirhead said: float f = 36.09999; printf( "%.3f\n", ((int)(f*1e3))*1e-3); That's much simpler than mine, which is good - but alas I do have a nit to pick with it: if f exceeds INT_MAX / 1000, which might be as low as 32, you have an obvious problem. -- Richard Heathfield "Usenet is a strange place" - dmr 29/7/1999 http://www.cpax.org.uk email: rjh at the above domain, - www. Dec 1 '06 #9

 P: n/a Richard Heathfield wrote: with this result: [36.0999999000000003] [36.099] which *is* what you want. But it works just by chance :-) If I set 10.0899999, it doesn't work... Dec 1 '06 #10

 P: n/a Marco <.said: Richard Heathfield wrote: >with this result:[36.0999999000000003][36.099]which *is* what you want. But it works just by chance :-) If I set 10.0899999, it doesn't work... But if you follow my suggestion of using double (and sprintf(cf, "%.16f", f)), it works fine: [10.0899999000000005] [10.089] Is that not the result you expected? -- Richard Heathfield "Usenet is a strange place" - dmr 29/7/1999 http://www.cpax.org.uk email: rjh at the above domain, - www. Dec 1 '06 #11

 P: n/a Richard Heathfield wrote: But if you follow my suggestion of using double (and sprintf(cf, "%.16f", f)), it works fine: [10.0899999000000005] [10.089] Is that not the result you expected? For this case, yes. But if I have : 13.99999999999999999999999999, I get 14.000000.......... even with "%.40f" Dec 1 '06 #12

 P: n/a Marco <.said: Richard Heathfield wrote: >But if you follow my suggestion of using double (and sprintf(cf, "%.16f",f)), it works fine:[10.0899999000000005][10.089]Is that not the result you expected? For this case, yes. But if I have : 13.99999999999999999999999999, I get 14.000000.......... even with "%.40f" Good. Now we're getting somewhere. And at *this* point, we have to ask how much precision you are expecting from your floating-point values. Let's look at a pure binary representation of 13.99999999999999999999999999. We start off with 13, which is easy: 1101. Four bits so far. Then comes the binary point. We'll give you that for free. :-) Now all we have to do is represent 0.99999999999999999999999999 in binary. Since the number is so close to 1, we can approximate rapidly via (n-1)/n where n is a power of 2. 1/2 is too low. 3/4 is too low. 7/8 is too low. 15/16 is too low. 31/32 is too low. ....cutting to the chase... 1023/1024 is too low... 65535/65536 is too low - so 16 bits isn't enough... ....and we eventually discover that we need to go as high as 154742504910672534362390527 / 154742504910672534362390528 That's 87 bits of precision. Plus those four for your 13, making 91 bits of precision altogether. Do you have a double that big? -- Richard Heathfield "Usenet is a strange place" - dmr 29/7/1999 http://www.cpax.org.uk email: rjh at the above domain, - www. Dec 1 '06 #13

 P: n/a On Fri, 01 Dec 2006 11:25:07 +0000, Richard Heathfield wrote: Duncan Muirhead said: >float f = 36.09999;printf( "%.3f\n", ((int)(f*1e3))*1e-3); That's much simpler than mine, which is good - but alas I do have a nit to pick with it: if f exceeds INT_MAX / 1000, which might be as low as 32, you have an obvious problem. Fair point. How about #include #include #include int main( int argc, char** argv) { float f = 36.09999; printf( "%.3f\n", f - fmod(f, 1e-3)); return EXIT_SUCCESS; } Duncan Dec 1 '06 #14

 P: n/a Duncan Muirhead said: On Fri, 01 Dec 2006 11:25:07 +0000, Richard Heathfield wrote: >Duncan Muirhead said: >>float f = 36.09999;printf( "%.3f\n", ((int)(f*1e3))*1e-3); That's much simpler than mine, which is good - but alas I do have a nitto pick with it: if f exceeds INT_MAX / 1000, which might be as low as32, you have an obvious problem. Fair point. How about #include #include #include int main( int argc, char** argv) { float f = 36.09999; printf( "%.3f\n", f - fmod(f, 1e-3)); return EXIT_SUCCESS; } Again, far simpler than mine, and I can't think of any nits. -- Richard Heathfield "Usenet is a strange place" - dmr 29/7/1999 http://www.cpax.org.uk email: rjh at the above domain, - www. Dec 1 '06 #15

 P: n/a Marco wrote: Hello, I have : float f = 36.09999999; When I do : char cf; sprintf(cf,"%0.03lf", f); I get : 36.100 How could I get 36.099 ? Thanks in advance. This falls squarely into the catagory of "if you have to ask, you shouldn't be doing this". Why would you prefer 36.099 rather than 36.100 as a three decimal place representation of 36.09999999? - William Hughes Dec 1 '06 #16

 P: n/a William Hughes wrote: Marco wrote: Hello, I have : float f = 36.09999999; When I do : char cf; sprintf(cf,"%0.03lf", f); I get : 36.100 How could I get 36.099 ? Thanks in advance. This falls squarely into the catagory of "if you have to ask, you shouldn't be doing this". What a silly rule. So, no one should ever learn anything by asking about something they don't know about? Why would you prefer 36.099 rather than 36.100 as a three decimal place representation of 36.09999999? It's probable that the OP's simply curious as to this behaviour. Once he learns the underlying reason he may very well go on to simply use 36.100 Dec 1 '06 #17

 P: n/a santosh wrote: William Hughes wrote: Marco wrote: Hello, > I have : float f = 36.09999999; > When I do : char cf; sprintf(cf,"%0.03lf", f); > I get : 36.100 > How could I get 36.099 ? > Thanks in advance. This falls squarely into the catagory of "if you have to ask, you shouldn't be doing this". What a silly rule. So, no one should ever learn anything by asking about something they don't know about? No. But there is a big difference between "Why do I see this behaviour?" and "How can I change this behaviour?". It is the second question to which "if you have to ask, you shouldn't be doing this" applies. - William Hughes Dec 1 '06 #18

 P: n/a Marco wrote: Hello, I have : float f = 36.09999999; When I do : char cf; sprintf(cf,"%0.03lf", f); I get : 36.100 How could I get 36.099 ? Thanks in advance. You are aware that 0.9... = 1 aren't you? Just wanted to make sure... /Mattan Ref: http://www.faqs.org/faqs/sci-math-fa...bers/0.999eq1/ Dec 1 '06 #19

 P: n/a >I have : >float f = 36.09999999; There is no exact representation of 36.09999999 in binary floating point. 36.0999999999 as long double: Before: 36.09999999989999999727707802321674535050988197326 660156250000000000000000000000000 Value: 36.09999999990000000074652497517035953933373093605 041503906250000000000000000000000 After: 36.09999999990000000421597192712397372815757989883 422851562500000000000000000000000 36.0999999999 as double: Before: 36.09999999989999253102723741903901100158691406250 0000000000000 Value: 36.09999999989999963645459502004086971282958984375 0000000000000 After: 36.09999999990000674188195262104272842407226562500 0000000000000 36.0999999999 as float: Before: 36.09999465942382812500000000000000000000000000000 0000000000000 Value: 36.09999847412109375000000000000000000000000000000 0000000000000 After: 36.10000228881835937500000000000000000000000000000 0000000000000 >When I do :char cf;sprintf(cf,"%0.03lf", f);I get : 36.100 There is no exact representation of 36.100 in binary floating point. 36.100 as long double: Before: 36.09999999999999999514277426726494013564661145210 266113281250000000000000000000000 Value: 36.09999999999999999861222121921855432447046041488 647460937500000000000000000000000 After: 36.10000000000000000208166817117216851329430937767 028808593750000000000000000000000 36.100 as double: Before: 36.09999999999999431565811391919851303100585937500 0000000000000 Value: 36.10000000000000142108547152020037174224853515625 0000000000000 After: 36.10000000000000852651282912120223045349121093750 0000000000000 36.100 as float: Before: 36.09999465942382812500000000000000000000000000000 0000000000000 Value: 36.09999847412109375000000000000000000000000000000 0000000000000 After: 36.10000228881835937500000000000000000000000000000 0000000000000 >How could I get 36.099 ? There is no exact representation of 36.099 in binary floating point. 36.099 as long double: Before: 36.09899999999999999772404279951842909213155508041 381835937500000000000000000000000 Value: 36.09900000000000000119348975147204328095540404319 763183593750000000000000000000000 After: 36.09900000000000000466293670342565746977925300598 144531250000000000000000000000000 36.099 as double: Before: 36.09899999999998954081092961132526397705078125000 0000000000000 Value: 36.09899999999999664623828721232712268829345703125 0000000000000 After: 36.09900000000000375166564481332898139953613281250 0000000000000 36.099 as float: Before: 36.09899520874023437500000000000000000000000000000 0000000000000 Value: 36.09899902343750000000000000000000000000000000000 0000000000000 After: 36.09900283813476562500000000000000000000000000000 0000000000000 >Thanks in advance. Dec 2 '06 #20

 P: n/a Gordon Burditt wrote: >I have :float f = 36.09999999; There is no exact representation of 36.09999999 in binary floating point. 36.0999999999 as long double: Before: 36.09999999989999999727707802321674535050988197326 660156250000000000000000000000000 Value: 36.09999999990000000074652497517035953933373093605 041503906250000000000000000000000 After: 36.09999999990000000421597192712397372815757989883 422851562500000000000000000000000 36.0999999999 as double: Before: 36.09999999989999253102723741903901100158691406250 0000000000000 Value: 36.09999999989999963645459502004086971282958984375 0000000000000 After: 36.09999999990000674188195262104272842407226562500 0000000000000 36.0999999999 as float: Before: 36.09999465942382812500000000000000000000000000000 0000000000000 Value: 36.09999847412109375000000000000000000000000000000 0000000000000 After: 36.10000228881835937500000000000000000000000000000 0000000000000 >When I do :char cf;sprintf(cf,"%0.03lf", f);I get : 36.100 There is no exact representation of 36.100 in binary floating point. 36.100 as long double: Before: 36.09999999999999999514277426726494013564661145210 266113281250000000000000000000000 Value: 36.09999999999999999861222121921855432447046041488 647460937500000000000000000000000 After: 36.10000000000000000208166817117216851329430937767 028808593750000000000000000000000 36.100 as double: Before: 36.09999999999999431565811391919851303100585937500 0000000000000 Value: 36.10000000000000142108547152020037174224853515625 0000000000000 After: 36.10000000000000852651282912120223045349121093750 0000000000000 36.100 as float: Before: 36.09999465942382812500000000000000000000000000000 0000000000000 Value: 36.09999847412109375000000000000000000000000000000 0000000000000 After: 36.10000228881835937500000000000000000000000000000 0000000000000 >How could I get 36.099 ? There is no exact representation of 36.099 in binary floating point. 36.099 as long double: Before: 36.09899999999999999772404279951842909213155508041 381835937500000000000000000000000 Value: 36.09900000000000000119348975147204328095540404319 763183593750000000000000000000000 After: 36.09900000000000000466293670342565746977925300598 144531250000000000000000000000000 36.099 as double: Before: 36.09899999999998954081092961132526397705078125000 0000000000000 Value: 36.09899999999999664623828721232712268829345703125 0000000000000 After: 36.09900000000000375166564481332898139953613281250 0000000000000 36.099 as float: Before: 36.09899520874023437500000000000000000000000000000 0000000000000 Value: 36.09899902343750000000000000000000000000000000000 0000000000000 After: 36.09900283813476562500000000000000000000000000000 0000000000000 >Thanks in advance. Given our ubiquitous 64-bit IEEE double (53 mantissa bits) 36.099 as double has no precision beyond 3.6098999999999997e+01 That printf("%.60f", 36.099) can give you something like 36.09899999999999664623828721232712268829300000000 0000000000000 might tease you to believe you have precision to 40+ digits. You don't. -- Joe Wright "Everything should be made as simple as possible, but not simpler." --- Albert Einstein --- Dec 2 '06 #21

 P: n/a >>I have : >>float f = 36.09999999; There is no exact representation of 36.09999999 in binary floating point.36.0999999999 as long double:Before: 36.0999999998999999972770780232167453505098819732 6660156250000000000000000000000000 >Value: 36.0999999999000000007465249751703595393337309360 5041503906250000000000000000000000 >After: 36.0999999999000000042159719271239737281575798988 3422851562500000000000000000000000 >>36.0999999999 as double:Before: 36.09999999989999253102723741903901100158691406250 0000000000000Value: 36.09999999989999963645459502004086971282958984375 0000000000000After: 36.09999999990000674188195262104272842407226562500 000000000000036.0999999999 as float:Before: 36.09999465942382812500000000000000000000000000000 0000000000000Value: 36.09999847412109375000000000000000000000000000000 0000000000000After: 36.10000228881835937500000000000000000000000000000 0000000000000 >>When I do :char cf;sprintf(cf,"%0.03lf", f);I get : 36.100 There is no exact representation of 36.100 in binary floating point.36.100 as long double:Before: 36.0999999999999999951427742672649401356466114521 0266113281250000000000000000000000 >Value: 36.0999999999999999986122212192185543244704604148 8647460937500000000000000000000000 >After: 36.1000000000000000020816681711721685132943093776 7028808593750000000000000000000000 >>36.100 as double:Before: 36.09999999999999431565811391919851303100585937500 0000000000000Value: 36.10000000000000142108547152020037174224853515625 0000000000000After: 36.10000000000000852651282912120223045349121093750 000000000000036.100 as float:Before: 36.09999465942382812500000000000000000000000000000 0000000000000Value: 36.09999847412109375000000000000000000000000000000 0000000000000After: 36.10000228881835937500000000000000000000000000000 0000000000000 >>How could I get 36.099 ? There is no exact representation of 36.099 in binary floating point.36.099 as long double:Before: 36.0989999999999999977240427995184290921315550804 1381835937500000000000000000000000 >Value: 36.0990000000000000011934897514720432809554040431 9763183593750000000000000000000000 >After: 36.0990000000000000046629367034256574697792530059 8144531250000000000000000000000000 >>36.099 as double:Before: 36.09899999999998954081092961132526397705078125000 0000000000000Value: 36.09899999999999664623828721232712268829345703125 0000000000000After: 36.09900000000000375166564481332898139953613281250 000000000000036.099 as float:Before: 36.09899520874023437500000000000000000000000000000 0000000000000Value: 36.09899902343750000000000000000000000000000000000 0000000000000After: 36.09900283813476562500000000000000000000000000000 0000000000000 >>Thanks in advance. Given our ubiquitous 64-bit IEEE double (53 mantissa bits)36.099 as double has no precision beyond3.6098999999999997e+01That printf("%.60f", 36.099) can give you something like36.0989999999999966462382872123271226882930000000 00000000000000might tease you to believe you have precision to 40+ digits. You don't. Since the value given above doesn't end in 5 followed by trailing zeroes, and it's not an exact integer, your example won't happen unless printf() is introducing unwanted rounding. The point of the output is that you have three consecutive floating point numbers (with no intermediate values in between) so rounding decimal numbers to put them in floating-point variables is inevitable and will result in errors. A floating-point variable contains a number (except when it's NaN or Inf or some such thing) and it is perfectly possible and reasonable to print out *EXACTLY* what that value is, to infinite precision, particularly when investigating problems of unwanted precision loss or comparing what you got with what you should have gotten if everything was done in infinite-precision math. Now, if that number 36.099 represents the weight in kilograms of something, you are correct that it is highly unlikely to have anywhere near 17 digits of precision in the result. Dec 2 '06 #22

 P: n/a Gordon Burditt wrote: [ snip ] >Given our ubiquitous 64-bit IEEE double (53 mantissa bits)36.099 as double has no precision beyond3.6098999999999997e+01That printf("%.60f", 36.099) can give you something like36.0989999999999966462382872123271226882930000000 00000000000000might tease you to believe you have precision to 40+ digits. You don't. Since the value given above doesn't end in 5 followed by trailing zeroes, and it's not an exact integer, your example won't happen unless printf() is introducing unwanted rounding. Where is (at what position) printf introducing this rounding? The point of the output is that you have three consecutive floating point numbers (with no intermediate values in between) so rounding decimal numbers to put them in floating-point variables is inevitable and will result in errors. I'm at a loss here. I have no idea what you mean. A floating-point variable contains a number (except when it's NaN or Inf or some such thing) and it is perfectly possible and reasonable to print out *EXACTLY* what that value is, to infinite precision, particularly when investigating problems of unwanted precision loss or comparing what you got with what you should have gotten if everything was done in infinite-precision math. A floating point variable (double, let's say) can hold a value precise to approximately 17 decimal digits. Nothing infinite about it. Now, if that number 36.099 represents the weight in kilograms of something, you are correct that it is highly unlikely to have anywhere near 17 digits of precision in the result. Why kilograms? The double has 53 bits and about 17 digits of precision no matter whether its value is kilos, nanos or light years. Using printf and friends to show decimal digits beyond 17 or so is misleading. -- Joe Wright "Everything should be made as simple as possible, but not simpler." --- Albert Einstein --- Dec 3 '06 #23

 P: n/a >>Given our ubiquitous 64-bit IEEE double (53 mantissa bits) >>36.099 as double has no precision beyond3.6098999999999997e+01That printf("%.60f", 36.099) can give you something like36.098999999999996646238287212327122688293000000 000000000000000might tease you to believe you have precision to 40+ digits. You don't. Since the value given above doesn't end in 5 followed by trailingzeroes, and it's not an exact integer, your example won't happenunless printf() is introducing unwanted rounding. Where is (at what position) printf introducing this rounding? 36.098999999999997 as double: Before: 36.09899999999998954081092961132526397705078125000 0000000000000 Value: 36.09899999999999664623828721232712268829345703125 0000000000000 After: 36.09900000000000375166564481332898139953613281250 0000000000000 Assuming that this is stored in a IEEE 64-bit floating point number, the rounding is 4 places in the 16th digit to the left of the decimal point. The actual number needs to be one of the three listed above, or something even farther away, since there aren't any numbers between the Before: and Value: numbers or between the Value: and After: numbers. Value: 36.09899999999999664623828721232712268829345703125 0000000000000 Input: 36.09899999999999700000000000000000000000000000000 0000000000000 ^^ >The point of the output is that you have three consecutive floatingpoint numbers (with no intermediate values in between) so roundingdecimal numbers to put them in floating-point variables is inevitableand will result in errors. I'm at a loss here. I have no idea what you mean. The program prints three consecutive floating point numbers. There's no numbers in between them at the specified precision. If you want to represent something close to the one in the middle, you've got these three choices. Anything else is further away. >A floating-point variable contains a number (except when it's NaNor Inf or some such thing) and it is perfectly possible and reasonableto print out *EXACTLY* what that value is, to infinite precision,particularly when investigating problems of unwanted precision lossor comparing what you got with what you should have gotten ifeverything was done in infinite-precision math. A floating point variable (double, let's say) can hold a value preciseto approximately 17 decimal digits. Nothing infinite about it. When you convert a floating point number (say, double) to decimal, it may take many more digits than 17 to represent EXACTLY the value it represents. >Now, if that number 36.099 represents the weight in kilograms ofsomething, you are correct that it is highly unlikely to haveanywhere near 17 digits of precision in the result. Why kilograms? The double has 53 bits and about 17 digits of precisionno matter whether its value is kilos, nanos or light years. Using printfand friends to show decimal digits beyond 17 or so is misleading. It's not misleading to represent the exact value of a floating-point number in decimal when discussing rounding error and the limits of precision of various types. Dec 4 '06 #24

 P: n/a In article <5P******************************@comcast.comJoe Wright

 P: n/a "Dik T. Winter" wrote: Joe Wright Gordon Burditt wrote: .... snip ... >>Where is (at what position) printf introducing this rounding? A floating point number is (by definition) a number of the form m * base^exp where m and exp are integer (the possibility that m is a fraction can be ignored because it can be made integer by suitable change of the exponent) and base is the base of the representation, which is 2 in IEEE. So a floating point number is in essence a rational number. If the base contains only prime factors 2 and/or 5, the denumerator of that number is a divisor of a power of 10, and so the number has an exact representation in finite decimal notation. So if printf is giving the above representation it is doing some rounding, because that is not the exact representation of an IEEE floating point number. You neglect that the usual base is 2, and that 10 is only used for input/output translation to/from text format. >>The point of the output is that you have three consecutivefloating point numbers (with no intermediate values in between)so rounding decimal numbers to put them in floating-pointvariables is inevitable and will result in errors. I'm at a loss here. I have no idea what you mean. Given some number in decimal notation there is either a single floating point number that it matches, or there are two floating point numbers, one of them larger and one of them smaller than the number given. 36.099 does not have an exact representation, so there are two numbers, one larger and one smaller. Since in general we cannot make an exact equivalent between representation as (2 ** binexp) and (10 ** decexp) the two representations cannot be exact equivalents (outside of a few specific values). -- Chuck F (cbfalconer at maineline dot net) Available for consulting/temporary embedded and systems. Dec 4 '06 #26

 P: n/a Duncan Muirhead wrote: [suggesting a way to print 36.09999999 as "36.099" instead of "36.100"] float f = 36.09999; printf( "%.3f\n", f - fmod(f, 1e-3)); Try this with 31.0999999. Or 0.9. See my longer post downthread for more details. - Ernie http://home.comcast.net/~erniew Dec 4 '06 #27

 P: n/a CBFalconer wrote: Since in general we cannot make an exact equivalent between representation as (2 ** binexp) and (10 ** decexp) the two representations cannot be exact equivalents (outside of a few specific values). You might want to give the phrasing of this some more thought. We aren't comparing logarithms, which is what binexp and decexp are. The question would be whether a number represented as (1 + m / 2^b) * 2^e with e, m, b integers, can be written exactly (with a finite number of digits) as a number in base 10, and as it happens, *all* of them can. Every one of the numbers that can be represented in IEEE 754, by far the most common floating-point encoding, can also be represented exactly in base 10, because 10 contains 2 as a factor. It's only in the other direction that we have an issue. You can convince yourself of this by looking at the decimal expansion for various values of binexp. -1 0.5 -2 0.25 -3 0.125 -4 0.0625 -5 0.03125 ... -23 0.00000011920928955078125 To create the decimal expansion of a binary fraction with b binary digits, you just need to add up the numbers on the right for each corresponding 1 bit in the binary fraction. This'll produce a decimal expansion with at most b decimal digits. For floats, b = 23, and for doubles, b = 53. The problems arise in the other direction. The OP had asked how to use printf() to display float f = 36.09999999; as "36.099" rather than "36.100". More generally, he wants rounding toward zero, rather than rounding to nearest. Someone suggested using printf( "%.3f\n", f - fmod( f, 1e-3 )); This looks like a good approach, but it can only touch the rounding done in printf(). The compiler must still round the decimal value of f in order to binary-encode it as a float, and it'll always do this using nearest-value rounding, so there are some values that will be rounded up rather than down. An example is 31.0999999f. This actually has one fewer 9 than the OP's example value, but the compiler will round it up to 31.1 before it ever reaches printf(). 31.0999999f can't be represented exactly, so the compiler has to choose between the two nearest values that it *can* represent exactly, (1 + 7916748 / 8388608) * 16 = 31.09999847412109375 (1 + 7916749 / 8388608) * 16 = 31.1000003814697265625 and it turns out the second one is closer. If you think this is just a problem of having too many digits, consider what happens to 0.9. It can't be represented exactly either, and float f = 0.9f; printf( "%.3f\n", f - fmod( f, 1e-3 )); prints "0.899", probably not what the OP wanted. The only surefire way to handle this is not to allow any rounding that you don't control. In particular, you can't store numbers in base 2. You have to maintain them as a string of decimal digits, and you have to perform all of the arithmetic in decimal. - Ernie http://home.comcast.net/~erniew Dec 4 '06 #28

 P: n/a Richard Heathfield skrev: Marco <.said: Hello, I have : float f = 36.09999999; I recommend double rather than float. When I do : char cf; sprintf(cf,"%0.03lf", f); Not lf - just f. I get : 36.100 How could I get 36.099 ? Remove the precision specification (03), and then search the string for the decimal point, using strchr. Check that you have at least three valid characters (non-'\0') after the decimal point, and make the fourth one '\0' to truncate the string at the point you want. how about.. sprintf(cf,"%0.03lf", floor(f*1000)/1000); -Lasse Dec 4 '06 #29

 P: n/a la******@ieee.org wrote: how about.. sprintf(cf,"%0.03lf", floor(f*1000)/1000); Try it with 31.0999999f or 0.9f. - Ernie http://home.comcast.net/~erniew Dec 4 '06 #30

This discussion thread is closed

Replies have been disabled for this discussion. 