473,406 Members | 2,847 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,406 software developers and data experts.

Unwanted rounding

Hello,

I have :
float f = 36.09999999;

When I do :
char cf[25];
sprintf(cf,"%0.03lf", f);

I get : 36.100

How could I get 36.099 ?

Thanks in advance.
Dec 1 '06 #1
29 3139
Marco <.said:
Hello,

I have :
float f = 36.09999999;
I recommend double rather than float.
>
When I do :
char cf[25];
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

Marco wrote:
Hello,

I have :
float f = 36.09999999;

When I do :
char cf[25];
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
ma**********@pobox.com said:
>
Marco wrote:
>Hello,

I have :
float f = 36.09999999;

When I do :
char cf[25];
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.

--
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

Richard Heathfield wrote:
ma**********@pobox.com said:

Marco wrote:
Hello,

I have :
float f = 36.09999999;

When I do :
char cf[25];
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
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
Marco <.said:
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...
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 <stdio.h>
#include <string.h>
#include <ctype.h>

int main(void)
{
float f = 36.0999999;
char cf[25] = {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
On Fri, 01 Dec 2006 10:54:43 +0100, wrote:
Hello,

I have :
float f = 36.09999999;

When I do :
char cf[25];
sprintf(cf,"%0.03lf", f);

I get : 36.100

How could I get 36.099 ?

Thanks in advance.
#include <stdio.h>
#include <stdlib.h>
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
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
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
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
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
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
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 <stdio.h>
#include <stdlib.h>
#include <math.h>
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
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 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 <stdio.h>
#include <stdlib.h>
#include <math.h>
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

Marco wrote:
Hello,

I have :
float f = 36.09999999;

When I do :
char cf[25];
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
William Hughes wrote:
Marco wrote:
Hello,

I have :
float f = 36.09999999;

When I do :
char cf[25];
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

santosh wrote:
William Hughes wrote:
Marco wrote:
Hello,
>
I have :
float f = 36.09999999;
>
When I do :
char cf[25];
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
Marco wrote:
Hello,

I have :
float f = 36.09999999;

When I do :
char cf[25];
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
>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[25];
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
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[25];
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
>>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 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[25];
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 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.0989999999999999977240427995184290921315550804 1381835937500000000000000000000000
>Value:
36.0990000000000000011934897514720432809554040431 9763183593750000000000000000000000
>After:
36.0990000000000000046629367034256574697792530059 8144531250000000000000000000000000
>>
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.0989999999999966462382872123271226882930000000 00000000000000
might 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
Gordon Burditt wrote:
[ snip ]
>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.0989999999999966462382872123271226882930000000 00000000000000
might 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
>>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.098999999999996646238287212327122688293000000 000000000000000
might 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?

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 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.
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 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.
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 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.
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
In article <5P******************************@comcast.comJoe Wright <jo********@comcast.netwrites:
Gordon Burditt wrote:
[ snip ]
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.
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?
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.
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.
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.
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.
Each floating point number is exactly representable in decimal notation.
Again, nothing infinite in 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.
That may be quite something else. But showing exact representations
to show that 36.099 is not representable as a floating point number is
not misleading at all.
--
dik t. winter, cwi, kruislaan 413, 1098 sj amsterdam, nederland, +31205924131
home: bovenover 215, 1025 jn amsterdam, nederland; http://www.cwi.nl/~dik/
Dec 4 '06 #25
"Dik T. Winter" wrote:
Joe Wright <jo********@comcast.netwrites:
>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 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.

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.
<http://cbfalconer.home.att.net>
Dec 4 '06 #26
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
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

Richard Heathfield skrev:
Marco <.said:
Hello,

I have :
float f = 36.09999999;

I recommend double rather than float.

When I do :
char cf[25];
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
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 thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: Norvin Laudon | last post by:
Hi, Can somebody explain the following, from the MSDN documentation for the "System.Convert.ToInt32(double)" function <quote> Return Value value rounded to the nearest 32-bit signed...
4
by: spebola | last post by:
I am using vb.net 2003 professional and I get the following results when using the round method: dim Amount as decimal = 180.255 Amount = Amount.Round(Amount, 2) Amount now contains 180.25. ...
8
by: Zorpiedoman | last post by:
Howcome: Dim D as decimal = .5D msgbox d.Round(D, 0) this returns "0" Now when I went to school .5 rounds UP to 1 not DOWN to zero?????!!! Documentation says this, but what the heck are...
2
by: Jiri Nemec | last post by:
Hello all, I have got one table with rounding values, table contains prices and round types. id price_from price_to rounding 1 0 1500 0.1 2 1500 ...
11
by: cj | last post by:
Lets assume all calculations are done with decimal data types so things are as precise as possible. When it comes to the final rounding to cut a check to pay dividends for example in VB rounding...
18
by: jdrott1 | last post by:
i'm trying to round my currency string to end in 9. it's for a pricing application. this is the function i'm using to get the item in currency: FormatCurrency(BoxCost, , , , TriState.True) if...
206
by: md | last post by:
Hi Does any body know, how to round a double value with a specific number of digits after the decimal points? A function like this: RoundMyDouble (double &value, short numberOfPrecisions) ...
20
by: jacob navia | last post by:
Hi "How can I round a number to x decimal places" ? This question keeps appearing. I would propose the following solution #include <float.h> #include <math.h>
30
by: bdsatish | last post by:
The built-in function round( ) will always "round up", that is 1.5 is rounded to 2.0 and 2.5 is rounded to 3.0. If I want to round to the nearest even, that is my_round(1.5) = 2 # As...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.