C++ 什么是浮点/舍入误差的简单示例?

C++ 什么是浮点/舍入误差的简单示例?,c++,floating-accuracy,C++,Floating Accuracy,我听说过使用浮点变量时出现“错误”。现在我试图解决这个难题,我想我得到了一些舍入/浮点错误。所以我最终要找出浮点错误的基本原理 什么是浮点/舍入错误的简单示例(最好是C++) 编辑:例如,假设我有一个成功概率为p的事件。我做这件事10次(p没有变化,所有试验都是独立的)。两次试验成功的概率是多少?我将其编码为: double p_2x_success = pow(1-p, (double)8) * pow(p, (double)2) * (double)choose(8, 2); 这是浮点错误

我听说过使用浮点变量时出现“错误”。现在我试图解决这个难题,我想我得到了一些舍入/浮点错误。所以我最终要找出浮点错误的基本原理

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

编辑:例如,假设我有一个成功概率为p的事件。我做这件事10次(p没有变化,所有试验都是独立的)。两次试验成功的概率是多少?我将其编码为:

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

这是浮点错误的机会吗?

通常,浮点错误是指当一个数字不能存储在IEEE浮点表示中时

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

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


因此,像0.5(1/2)这样的数字很容易存储,但并非每个数字都是一个C语言的简单例子,在不久前吸引了我:

double d = 0;
sscanf("90.1000", "%lf", &d);
printf("%0.4f", d);
这将打印
90.0999

这是一个将角度(单位:DMS)转换为弧度的函数


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

这张图值千言万语-试着画出方程式
f(k)


你会得到这样的XY图(X和Y是对数比例)。
 for(double d = 0; d != 0.3; d += 0.1); // never terminates 

若计算机能够表示32位浮点而不存在舍入误差,那个么对于每个
k
,我们应该得到零。但是,由于浮点误差累积,误差随着k值的增大而增大


这里有一个吸引了我的注意:

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

双精度和浮点具有不同的精度,因此第一个将表示为
256.4999900000003
,第二个表示为
256.5
,因此将以不同的方式进行舍入

我喜欢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
>>>
超级简单:

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 

在我看来,这是最简单的一种,适用于多种语言的方法很简单:

0.2+0.1
下面是一些我想到的REPL示例,但在任何符合IEEE754的语言上都应该返回这个结果

蟒蛇

>0.2+0.1
0.30000000000000004
科特林

0.2+0.1
res0:kotlin.Double=0.300000000004
斯卡拉

爪哇

红宝石

irb(main):001:0>0.2+0.1
=> 0.30000000000000004

我认为Ruby在以下方面有一个很好的例子:

sum=0
一万倍
总和=总和+0.0001
结束
打印总和#=>0.999999062

正如一位匿名用户所指出的,使用
sscanf
时,“f”转换说明符需要一个
float
参数,而不是
double
(然而,“f”表示
double
printf
——是的,它令人困惑)。“lf”修改后的转换说明符应该用于使
sscanf
一起工作。我想你真正需要的是:。阅读这个:参见简单的Java示例,在C中应该是相同的:我可以在CC0许可证下将这个图像(重做,使它成为SVG)添加到Wikipedia Commons吗,Lua和PHP返回
0.3
。以及Perl:),但在Javascript中工作;)这是什么语言?问题是标记C++,在这里代码完全没有意义(<代码> 1/10代码/代码>在浮点中是完全可表示的,它是代码> 0 00000 )
False                                                                                                                                 
a:10000000.09999999962747097015                                                                                                       
b:0.10000000000000000555 
scala> 0.2 + 0.1
val res0: Double = 0.30000000000000004
jshell> 0.2 + 0.1
$1 ==> 0.30000000000000004