可能重复:
Dealing with accuracy problems in floating-point numbers
我很惊讶为什么我试图在C中加倍浮点数(使用GCC 3.2)并且它没有像我预期的那样做。作为样本:
int main() {
float nb = 3.11f;
nb *= 10;
printf("%f\n", nb);
}
显示:31.099998
我对浮动的实现方式及其产生这种意外行为的原因感到好奇吗?
答案 0 :(得分:14)
首先,你可以乘以花车。你遇到的问题不是乘法本身,而是你使用的原始数字。乘法可能会失去一些精确度,但是这里您乘以的原始数字始于精度损失。
这实际上是预期的行为。 float
是使用二进制表示实现的,这意味着它们无法准确表示十进制值。
有关详细信息,请参阅MSDN。
您还可以在the description of float中看到它有6到7位有效数字。在您的示例中,如果您将31.099998
舍入为7位有效数字,则会得到31.1
,因此它仍然可以按预期运行。
double
类型当然会更准确,但由于它的二进制表示仍然有舍入误差,而你写的数字是十进制的。
如果想要十进制数的完全准确性,则应使用十进制类型。此类型存在于C#等语言中。 http://msdn.microsoft.com/en-us/library/system.decimal.aspx
您还可以使用有理数表示。只要你可以将数字表示为两个整数的除法,就可以使用两个整数来提供完全的准确性。
答案 1 :(得分:5)
这是按预期工作的。计算机具有有限的精度,因为它们试图从整数计算浮点值。这会导致浮点不准确。
Floating point wikipedia页面详细介绍了代表性和由此导致的准确性问题:)
有趣的现实世界的注释:this部分原因是使用整数(美分)进行大量金钱计算 - 不要让计算机因精度不足而亏钱!我想要我的$ 0.00001!
答案 2 :(得分:4)
数字3.11不能用二进制表示。 24位有效位最接近的是11.0001110000101000111101,小数点为3.1099998950958251953125。
如果您的号码3.11应该代表货币金额,那么您需要使用小数表示。
答案 3 :(得分:2)
在Python社区中,我们经常看到有人对此感到惊讶,因此在这个问题上有经过充分测试和调试的FAQs和tutorial sections(当然,它们是用Python语言表达的) ,而不是C,但由于Python委托浮动算术到底层的C和硬件,所以浮点机制的所有描述仍然适用。)
当然,这不是乘法的错误 - 删除乘以nb
的语句,无论如何你都会看到类似的问题。
答案 4 :(得分:1)
浮点数的事实 不能准确地代表所有真实的 数字和那个浮点数 操作无法准确表示 真正的算术运算,导致 许多令人惊讶的情况。这是 与有限精度有关 哪些计算机通常代表 号。
答案 5 :(得分:0)
浮点不精确,因为它们使用基数2(因为它是二进制:0或1)而不是基数10.而基数2转换为基数10,正如之前所说的那样,将导致舍入精度问题。