我在基于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上的行为方式相同
由于
答案 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 question或blogs中查看更多信息wikipedia。
答案 3 :(得分:0)
在符合IEEE 754标准的实现中,它应该以默认的舍入模式打印88888888888885.88
。这与浮点精度无关,因为该值可以准确表示;这只是printf
四舍五入到小数点后2位的问题。不知道你为什么在某些系统上看到88888888888885.87
。