4

我一直在玩浮点数,根据我过去对它们的了解,0.1 + 0.2最终会变成这样的事实0.30000000000000004并不让我感到惊讶。

然而,令我惊讶的是,整数运算似乎总是工作很好,并且没有任何这些伪像。

我首先在 JavaScript(node.js 中的 Chrome V8)中注意到了这一点:

0.1 + 0.2 == 0.3 // false, NOT surprising
123456789012 + 18 == 123456789030  // true
22334455667788 + 998877665544 == 23333333333332 // true
1048576 / 1024 == 1024  // true

C++(Mac OS X 上的 gcc)似乎具有相同的属性。

最终结果似乎是整数——因为没有更好的词——工作。只有当我开始使用十进制数字时,事情才会变得不稳定。

这是设计的一个特征,一个数学工件,还是编译器和运行时环境完成的一些优化?

4

8 回答 8

4

这是设计的一个特征,一个数学工件,还是编译器和运行时环境完成的一些优化?

这是实数的一个特征。现代代数的一个定理(现代代数,不是高中代数;数学专业的学生在基础微积分和线性代数课后上现代代数课)说,对于某个正整数b,任何正实数r都可以表示为r = a * b p,其中a在 [1, b ) 中,p是某个整数。例如,1024 10 = 1.024 10 *10 3。正是这个定理证明了我们使用科学记数法的合理性。

该数字a可以分为终端(例如 1.0)、重复(1/3=0.333...)或非重复(pi 的表示)。这里有一个终端号码的小问题。任何终端编号也可以表示为重复编号。例如,0.999... 和 1 是同一个数字。这种表示中的歧义可以通过指定可以表示为终端号的数字来解决。

您发现的是所有整数在任何基数中都有终端表示这一事实的结果。

这里有一个关于实数如何在计算机中表示的问题。就像intandlong long int不代表所有的整数一样,floatdouble不代表所有的实数。大多数计算机上用于表示实数r的方案是以r = a *2 p的形式表示,但尾数(或有效数)a被截断为一定数量的位,指数p限制为某个有限数. 这意味着某些整数无法精确表示。例如,即使一个 googol (10 100) 是一个整数,它的浮点表示不准确。googol 的 base 2 表示是一个 333 位的数字。这个 333 位尾数被截断为 52+1 位。

这样做的结果是双精度算术不再精确,即使对于整数来说,如果所讨论的整数大于 2 53。尝试使用unsigned long long int介于 2 53和 2 64之间的值的类型进行实验。您会发现对于这些大整数,双精度算术不再精确。

于 2012-10-25T10:16:38.770 回答
3

我是在假设 Javascript 对所有数字使用双精度浮点表示的情况下写的。

某些数字具有浮点格式的精确表示,特别是所有整数,例如|x| < 2^53. 一些数字不会,特别是像 0.1 或 0.2 这样的小数,它们在二进制表示中变成无限小数。

如果所有操作数和运算结果都有精确的表示,那么使用 . 比较结果是安全的==

相关问题:

什么二进制数只能表示为近似值?

为什么十进制数不能用二进制精确表示?

于 2012-10-25T09:13:38.030 回答
2

具有可表示范围的整数完全可以由机器表示,浮点数不是(嗯,大多数)。

如果通过“基本整数数学”您了解“特征”,那么是的,您可以假设正确实现算术是一个特征。

于 2012-10-25T08:40:38.140 回答
2

原因是,您可以精确地以二进制格式(0001、0010、0011、...)表示每个整数(1、2、3、...)

这就是为什么整数总是正确的,因为 0011 - 0001 总是 0010。浮点数的问题是,点之后的部分不能精确地转换为二进制。

于 2012-10-25T08:41:33.680 回答
1

您所说的“工作”的所有情况都是您给出的数字可以精确地以浮点格式表示的情况。您会发现添加 0.25 和 0.5 和 0.125 也完全可以,因为它们也可以用二进制浮点数精确表示。

只有值不能像 0.1 这样你才会得到看起来不准确的结果。

于 2012-10-25T08:40:29.840 回答
1

整数是精确的,因为不精确主要来自我们编写小数的方式,其次是因为许多有理数在任何给定的基数中根本没有不重复的表示。

有关完整说明,请参阅:https ://stackoverflow.com/a/9650037/140740。

于 2012-11-16T01:37:02.310 回答
0

只有当您将足够小的整数添加到非常大的整数时,该方法才有效——即使在这种情况下,您也没有以“浮点”格式表示两个整数。

于 2012-10-25T08:44:35.157 回答
-1

不能表示所有浮点数。这是由于它们的编码方式。维基页面比我解释得更好:http ://en.wikipedia.org/wiki/IEEE_754-1985 。因此,当您尝试比较浮点数时,您应该使用增量:

myFloat - expectedFloat < delta

您可以使用最小的可表示浮点数作为增量。

于 2012-10-25T08:44:06.687 回答