37

我在使用浮点变量时听说过“错误”。现在我正在尝试解决这个难题,我想我遇到了一些舍入/浮点错误。所以我终于要弄清楚浮点错误的基础知识了。

什么是浮点/舍入错误的简单示例(最好在 C++ 中)?

编辑:例如说我有一个成功概率为 p 的事件。我做了 10 次这个事件(p 不变,所有试验都是独立的)。恰好 2 次成功试验的概率是多少?我将此编码为:

double p_2x_success = pow(1-p, (double)8) * pow(p, (double)2) * (double)choose(8, 2);

这是浮点错误的机会吗?

4

9 回答 9

44

图片值一千字 - 尝试绘制方程f(k)
在此处输入图像描述
你会得到这样的 XY 图(X 和 Y 是对数刻度)。
在此处输入图像描述
如果计算机可以表示 32 位浮点数而没有舍入误差,那么对于每个k我们应该得到零。但是由于浮点误差累积,误差随着 k 值的增大而增加。

嗯!

于 2011-04-17T15:49:25.687 回答
31
 for(double d = 0; d != 0.3; d += 0.1); // never terminates 
于 2008-10-30T10:46:24.137 回答
13

通常,浮点错误是指无法以 IEEE 浮点表示形式存储的数字。

整数存储时最右边的位为 1,左边的每一位都是 (2,4,8,...) 的两倍。很容易看出,它可以存储最多 2^n 的任何整数,其中 n 是位数。

浮点数的尾数(小数部分)以类似的方式存储,但从左到右移动,每个连续的位是前一个值的一半。(实际上比这要复杂一点,但现在可以了)。

因此,像 0.5 (1/2) 这样的数字很容易存储,但并非每个 <1 的数字都可以通过添加固定数量的 1/2、1/4、1/8、...

一个非常简单的例子是 0.1 或 1/10。这可以通过无限系列来完成(我真的不介意计算),但是每当计算机存储 0.1 时,存储的并不完全是这个数字。

如果您可以访问 Unix 机器,很容易看到这一点:

Python 2.5.1 (r251:54863, Apr 15 2008, 22:57:26) 
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 0.1
0.10000000000000001
>>> 

无论您使用哪种语言,您都需要非常小心地使用浮点数和双精度数进行相等测试。

(对于您的示例,0.2 是另一个无法存储在 IEEE 二进制文件中的讨厌数字,但只要您正在测试不等式,而不是等式,例如 p <= 0.2,那么您就可以了。)

于 2008-10-30T07:33:33.123 回答
9

这是一个吸引我的:

 round(256.49999) == 256
roundf(256.49999) == 257

doubles 和 floats 具有不同的精度,因此第一个将表示为256.49999000000003,第二个表示为 ,256.5因此会以不同的方式舍入

于 2014-12-17T15:37:32.583 回答
7

C 中的一个简单示例,不久前就引起了我的注意:

double d = 0;
sscanf("90.1000", "%lf", &d);
printf("%0.4f", d);

这打印90.0999

这是一个将 DMS 中的角度转换为弧度的函数。

为什么它在上述情况下不起作用?

于 2008-10-30T07:52:46.127 回答
6

这是我想到的最简单的,应该适用于多种语言的简单方法是:

0.2 + 0.1

以下是一些我想到的 REPL 示例,但应该在任何符合 IEEE754 的语言上返回此结果。

Python

>>> 0.2 + 0.1
0.30000000000000004

科特林

0.2 + 0.1
res0: kotlin.Double = 0.30000000000000004

斯卡拉

scala> 0.2 + 0.1
val res0: Double = 0.30000000000000004

爪哇

jshell> 0.2 + 0.1
$1 ==> 0.30000000000000004

红宝石

irb(main):001:0> 0.2 + 0.1
=> 0.30000000000000004
于 2020-05-20T15:47:02.050 回答
6

我喜欢 Python 解释器中的这个:

Python 2.7.10 (default, Oct  6 2017, 22:29:07) 
[GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.31)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 0.1+0.2
0.30000000000000004
>>>
于 2018-11-06T18:16:02.300 回答
2

超级简单:

a = 10000000.1
b = 1/10
print(a - b == 10000000)
print ('a:{0:.20f}\nb:{1:.20f}'.format(a, b))

打印(取决于平台)类似:

False                                                                                                                                 
a:10000000.09999999962747097015                                                                                                       
b:0.10000000000000000555 
于 2019-08-14T12:58:21.167 回答
0

我认为 Ruby 在其文档中有一个很好的例子:

sum = 0
10_000.times do
  sum = sum + 0.0001
end
print sum #=> 0.9999999999999062
于 2021-05-10T20:41:45.890 回答