11

I have problem on UNIX based systems sprintf does not round up properly value.

For example

double tmp = 88888888888885.875
char out[512];

Thats 88,888,888,888,885.875 just to be easier on eyes. I am giving such specific and big example because it seems it works fine on smaller numbers.

I am trying to use it in following way

sprintf(out, "%021.2f", tmp);
printf("out = %s\n", tmp);

On windows this results in:

out = 000088888888888885.88

On for example AIX, but shows in Linux as well:

out = 000088888888888885.87

Why is this happening? Any ideas and how to make it behave same way on Win/Unix

Thanks

grobartn
  • 3,510
  • 11
  • 40
  • 52
  • 2
    erm, http://www.ideone.com/UVtft reports `.88`, my local SuseLinux reports the same... – Nim Jan 10 '11 at 17:29
  • 3
    What CPUs are you using for each OS? – chrisaycock Jan 10 '11 at 17:33
  • On Linux (Debian 5) AMD64 I get `000088888888888885.88` – Charles Salvia Jan 10 '11 at 17:41
  • Please take a look at http://stackoverflow.com/questions/994764/rounding-doubles-5-sprintf. A difference between your fraction (.875) and his fraction (.555) is that yours can be expressed exactly in binary; it is 7/8. – rajah9 Jan 10 '11 at 17:42
  • 1
    On most computers using 64-bit IEEE `double` s, your two `out` strings are both equal to the original (exact) value of `tmp`. – aschepler Jan 10 '11 at 17:49
  • this is 32 bit box.. CPU on win box is Intel Xeon(R) x5550 2.6GHz running windows vista and VS2010... on Aix its XLC compiler – grobartn Jan 10 '11 at 18:11

4 Answers4

1

What floating point representations are used by your processor and your compiler?

Not all processors use the same way to represent floating-point values and even compilers may choose different floating-point representation methods (I think the Microsoft C++ compiler even has options to choose the representation).

The page http://www.quadibloc.com/comp/cp0201.htm gives an overview of some of the floating-point representations (although they seem to be rather old architectures shown there).

http://msdn.microsoft.com/en-us/library/0b34tf65.aspx describes how Microsoft Visual C++ stores floating-point values. I couldn't find immediately what representation is used by AIX or Linux.

Additinally, every compiler has options that let you indicate how you want to work with floating-point operations. Do you want them to be correct as possible (but possibly somewhat slower)? Or do you want floating-point operations to be fast as possible (but possibly less correct)?

Patrick
  • 23,217
  • 12
  • 67
  • 130
  • MSVC can't choose the representation, it's options are about the optimizations it performs on floating-point arithmetic and methods. – Puppy Jan 10 '11 at 17:53
  • Here's an interesting related question: http://stackoverflow.com/questions/1961442/different-math-rounding-behaviour-between-linux-mac-os-x-and-windows – makes Jan 10 '11 at 17:53
1

There is a bug report for glibc with a problem very similar to yours. The main conclusion (in comment 46) here is that double is not a 15-decimal-digit number and you should not expect it to work like that.

As a workaround you can add something small to your numbers to make them round better. But this solution is not general because it depends on number ranges you deal with.

Another workaround can be multiplying to prepare them for rounding, then rounding (e.g. 2597.625*100 = 259762.5 -> 259763 = 2597.63*100)

However I think there must be smarter workarounds.

ssmir
  • 1,522
  • 8
  • 10
0

That's because you're using double which has accuracy limitations, meaning, your 88888888888885.875 is probably being rounded to something else internally.

See more info in a similar question, in blogs or in wikipedia.

Community
  • 1
  • 1
Miguel Ventura
  • 10,344
  • 2
  • 31
  • 41
  • 3
    Yes by why is the double being rounded differently on the different OS's? Of course it has accuracy limitations, that's why he is getting different answers. – Grammin Jan 10 '11 at 17:37
  • 2
    It can vary from the box's architecture to some polishing being done by libc's printf. As you can see from comments to question, even within the same OS (Linux) it behaves differently, because essentially there's no warranty that it should behave the same. – Miguel Ventura Jan 10 '11 at 17:40
0

On an IEEE 754 conformant implementation, it should print 88888888888885.88 in the default rounding mode. This has nothing to do with floating point precision since the value is exactly representable; it's simply a matter of printf's rounding to 2 places after the decimal point. No idea why you're seeing 88888888888885.87 on some systems.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • 1
    The OP might like to try omitting the `sprintf` (and just assigning directly to a double) to verify that this is happening in `printf`. – Cascabel Jan 10 '11 at 18:36