8

可能重复:
处理浮点数的准确性问题

我很惊讶为什么我试图在 C 中乘以一个浮点数(使用 GCC 3.2)并且它没有按我预期的那样做。作为示例:

int main() {
  float nb = 3.11f;
  nb *= 10;
  printf("%f\n", nb);
}

显示:31.099998

我很好奇浮动的实现方式以及为什么会产生这种意外行为?

4

6 回答 6

14

首先,您可以乘以浮点数。您遇到的问题不是乘法本身,而是您使用的原始数字。乘法可能会丢失一些精度,但在这里,您相乘的原始数字会丢失精度。

这实际上是一种预期的行为。floats 是使用二进制表示来实现的,这意味着它们不能准确地表示十进制值。

有关详细信息,请参阅MSDN

您还可以在float 的描述中看到它具有 6-7 位有效数字精度。在您的示例中,如果您四舍五入31.099998到 7 个有效数字,您将得到31.1,所以它仍然可以按预期工作。

doubletype 当然会更准确,但由于它是二进制表示,而你写的数字是十进制,仍然存在舍入误差。

如果您想要十进制数的完全准确性,您应该使用十进制类型。这种类型存在于 C# 等语言中。http://msdn.microsoft.com/en-us/library/system.decimal.aspx

您还可以使用有理数表示。只要您可以将数字表示为两个整数的除法,使用两个整数即可获得完全的准确性。

于 2010-06-13T05:02:56.970 回答
5

这按预期工作。计算机具有有限的精度,因为它们试图从整数计算浮点值。这会导致浮点不准确。

浮点维基百科页面比我在这里更详细地介绍了表示和由此产生的准确性问题:)

有趣的现实世界旁注:就是为什么大量金钱计算是使用整数(美分)完成的部分原因——不要让计算机因缺乏精度而赔钱!我想要我的 0.00001 美元!

于 2010-06-13T05:03:20.850 回答
4

数字 3.11 不能用二进制表示。最接近 24 位有效位的是 11.0001110000101000111101,即十进制的 3.1099998950958251953125。

如果您的数字 3.11 应该代表货币金额,那么您需要使用十进制表示。

于 2010-06-13T05:08:36.843 回答
2

在 Python 社区中,我们经常看到人们对此感到惊讶,因此有经过充分测试和调试的常见问题解答和关于该问题的教程部分(当然,它们是用 Python 而非 C 来表达的,但由于 Python 委托浮点算术无论如何,对于底层的 C 和硬件,浮点机制的所有描述仍然适用)。

当然,这不是乘法的错——删除你乘法的语句,nb无论如何你都会看到类似的问题。

于 2010-06-13T05:04:38.603 回答
1

来自维基百科文章

浮点数不能精确地表示所有实数,浮点运算也不能精确地表示真正的算术运算,这一事实导致了许多令人惊讶的情况。这与计算机通常表示数字的有限精度有关。

于 2010-06-13T05:04:36.733 回答
0

浮点数不精确,因为它们使用基数 2(因为它是二进制:0 或 1)而不是基数 10。正如许多人之前所说,将基数 ​​2 转换为基数 10 会导致舍入精度问题。

于 2010-06-13T05:06:52.373 回答