Unwanted rounding

M

Marco

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

Richard Heathfield

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

Duncan Muirhead

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
 
M

Marco

Richard said:
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...
 
R

Richard Heathfield

Marco said:
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.
 
M

Marco

Richard said:
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...
 
R

Richard Heathfield

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

Richard Heathfield

Marco said:
Richard said:
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?
 
M

Marco

Richard said:
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"
 
R

Richard Heathfield

Marco said:
Richard said:
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?
 
D

Duncan Muirhead

Duncan Muirhead said:


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
 
R

Richard Heathfield

Duncan Muirhead said:
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.
 
W

William Hughes

Marco said:
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
 
S

santosh

William said:
Marco said:
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
 
W

William Hughes

santosh said:
William said:
Marco said:
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
 
G

Gordon Burditt

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.09999999989999999727707802321674535050988197326660156250000000000000000000000000
Value: 36.09999999990000000074652497517035953933373093605041503906250000000000000000000000
After: 36.09999999990000000421597192712397372815757989883422851562500000000000000000000000

36.0999999999 as double:
Before: 36.099999999899992531027237419039011001586914062500000000000000
Value: 36.099999999899999636454595020040869712829589843750000000000000
After: 36.099999999900006741881952621042728424072265625000000000000000

36.0999999999 as float:
Before: 36.099994659423828125000000000000000000000000000000000000000000
Value: 36.099998474121093750000000000000000000000000000000000000000000
After: 36.100002288818359375000000000000000000000000000000000000000000
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.09999999999999999514277426726494013564661145210266113281250000000000000000000000
Value: 36.09999999999999999861222121921855432447046041488647460937500000000000000000000000
After: 36.10000000000000000208166817117216851329430937767028808593750000000000000000000000

36.100 as double:
Before: 36.099999999999994315658113919198513031005859375000000000000000
Value: 36.100000000000001421085471520200371742248535156250000000000000
After: 36.100000000000008526512829121202230453491210937500000000000000

36.100 as float:
Before: 36.099994659423828125000000000000000000000000000000000000000000
Value: 36.099998474121093750000000000000000000000000000000000000000000
After: 36.100002288818359375000000000000000000000000000000000000000000
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.09899999999999999772404279951842909213155508041381835937500000000000000000000000
Value: 36.09900000000000000119348975147204328095540404319763183593750000000000000000000000
After: 36.09900000000000000466293670342565746977925300598144531250000000000000000000000000

36.099 as double:
Before: 36.098999999999989540810929611325263977050781250000000000000000
Value: 36.098999999999996646238287212327122688293457031250000000000000
After: 36.099000000000003751665644813328981399536132812500000000000000

36.099 as float:
Before: 36.098995208740234375000000000000000000000000000000000000000000
Value: 36.098999023437500000000000000000000000000000000000000000000000
After: 36.099002838134765625000000000000000000000000000000000000000000
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,431
Messages
2,571,678
Members
48,796
Latest member
Greg L.

Latest Threads

Top