在sprintf中舍入Windows与基于Unix的系统的差异

时间:2011-01-10 17:26:29

标签: c++ c windows unix rounding-error

我在基于UNIX的系统上遇到问题sprintf没有正确地舍入值。

例如

double tmp = 88888888888885.875
char out[512];

这是88,888,888,888,885.875只是为了让眼睛更容易。 我给出了这样一个特别而又大的例子,因为它似乎在较小的数字上工作正常。

我试图以下列方式使用它

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

在Windows上,这会导致:

out = 000088888888888885.88

例如AIX,但也在Linux中显示:

out = 000088888888888885.87

为什么会这样? 任何想法以及如何使它在Win / Unix上的行为方式相同

由于

4 个答案:

答案 0 :(得分:1)

您的处理器和编译器使用了哪些浮点表示?

并非所有处理器都使用相同的方式来表示浮点值,甚至编译器也可以选择不同的浮点表示方法(我认为Microsoft C ++编译器甚至可以选择表示)。

页面http://www.quadibloc.com/comp/cp0201.htm概述了一些浮点表示(尽管它们似乎是相当旧的架构)。

http://msdn.microsoft.com/en-us/library/0b34tf65.aspx描述了Microsoft Visual C ++如何存储浮点值。我无法立即找到AIX或Linux使用的表示形式。

另外,每个编译器都有一些选项,可以指示您希望如何使用浮点运算。你想让它们尽可能正确(但可能有点慢)?或者您希望浮点运算尽可能快(但可能不太正确)?

答案 1 :(得分:1)

glibc有bug report,问题与你的问题非常相似。这里的主要结论(在评论46中)是double不是15位小数位数,你不应该期望它能像那样工作。

作为一种解决方法,您可以在数字中添加一些小的内容,以使它们更好。但这种解决方案并不通用,因为它取决于您处理的数字范围。

另一种解决方法可以是相乘以准备舍入,然后舍入(例如2597.625*100 = 259762.5 -> 259763 = 2597.63*100

但我认为必须有更聪明的解决方法。

答案 2 :(得分:0)

那是因为您使用的double具有准确性限制,这意味着您的88888888888885.875可能会在内部进行其他操作。

in a similar questionblogs中查看更多信息wikipedia

答案 3 :(得分:0)

在符合IEEE 754标准的实现中,它应该以默认的舍入模式打印88888888888885.88。这与浮点精度无关,因为该值可以准确表示;这只是printf四舍五入到小数点后2位的问题。不知道你为什么在某些系统上看到88888888888885.87