例如,0,0.5,0.15625,1,2,3 ......是从IEEE 754转换而来的值。它们的硬编码版本是否精确?
例如:
是
float a=0;
if(a==0){
return true;
}
总是回归真实?其他例子:
float a=0.5;
float b=0.25;
float c=0.125;
是* b总是等于0.125而a * b == c总是如此?还有一个例子:
int a=123;
float b=0.5;
是* b总是61.5?或者一般来说,是整数乘以IEEE 754二进制浮点精确?
或者更一般的问题:如果值是硬编码,并且值和结果都可以用IEEE 754中的二进制格式表示(例如:0.5 - 0.125),那么值是否准确?
答案 0 :(得分:7)
浮点数没有固有的模糊性。只是有些(但不是全部)真实数字无法准确表示。
与固定宽度的十进制表示比较,让我们说三位数。可以使用1.00表示整数1,使用0.10可以表示1/10,但只能使用0.33来表示1/3。
如果我们改为使用二进制数字,整数1将表示为1.00(二进制数字),1/2表示为0.10,1 / 4表示为0.01,但1/3可以(再次)仅表示近似值。
但有些事情需要记住:
(我的意见是,它实际上是一个合理的第一近似值,是的,浮点数 本身就是模糊的,所以除非你确定你的特定应用程序可以处理它,远离他们。)
有关您可能需要或想要的更多详情,请阅读着名的What Every Computer Scientist Should Know About Floating-Point Arithmetic。此外,这个更容易访问的网站:The Floating-Point Guide。
答案 1 :(得分:2)
不,但正如托马斯·帕德龙 - 麦卡锡所说,有些数字可以使用二进制来精确表示,但不是所有数字都可以。
这是我向与我合作的非开发人员解释的方式(如Mahmut Ali,我也在一个非常古老的金融包上工作):想象一下,有一个非常大的蛋糕切成256片。现在你可以给1个人整个蛋糕,2个人一半的切片,但很快你决定将它分成3个你不能 - 它是85或86 - 你不能再分开蛋糕了。浮点数也一样。你只能在某些表示中得到确切的数字 - 有些数字只能近似接近。
答案 2 :(得分:1)
C ++不需要二进制浮点表示。内置整数需要具有二进制表示,通常是二进制补码,但也支持一个补码,符号和幅度。但是浮点可以是例如小数。
这就留下了一个问题:C ++浮点是否可以有一个不具有2作为素数的基数,如2和10.是否允许其他基数?我不知道,上次我试图检查,我失败了。
但是,假设基数必须为2或10,那么所有示例都涉及2的幂的值,因此可以准确表示。
这意味着对大多数问题的单一回答是“是”。唯一的例外是“整数乘以IEEE 754二进制浮点数[精确]”。如果结果超出了可用的精度,那么它就不是精确的,但是否则就是。
有关浮点表示的背景信息,请参阅经典“What Every Computer Scientist Should Know About Floating-Point Arithmetic”。属性一般。
如果某个值可以在32位或64位IEEE 754中精确表示,那么这并不意味着它可以用其他浮点表示精确表示。这是因为不同的32位表示和不同的64位表示使用不同的位数来保持尾数并具有不同的指数范围。因此,可以用一种方式精确表示的数字可能超出其他表示的精度或范围。
您可以使用std::numeric_limits<T>::is_iec559
(例如T
为double
)来检查您的实施是否声称与IEEE 754兼容。但是,当打开浮点优化时,至少g ++编译器(1)错误地声称是IEEE 754,而不是处理例如根据该标准,NaN值正确。实际上,is_iec559
仅告诉您数字表示是否为IEEE 754,而不是语义是否符合。
(1)本质上,gcc和g ++不是为不同的语义提供不同的类型,而是尝试通过编译器选项来适应不同的语义。并且对程序的各个部分进行单独编译,这些编译不符合C ++标准。 功能
答案 3 :(得分:0)
原则上,这应该是可能的。如果你将自己局限于具有有限2次幂表示的这类数字。
但这很危险:如果有人接受您的代码并将0:
1:
1
2:
1 0
0 1
3:
1 0 1
0 1 0
1 0 1
4:
1 0 1 0
0 1 0 1
1 0 1 0
0 1 0 1
5:
1 0 1 0 1
0 1 0 1 0
1 0 1 0 1
0 1 0 1 0
1 0 1 0 1
6:
1 0 1 0 1 0
0 1 0 1 0 1
1 0 1 0 1 0
0 1 0 1 0 1
1 0 1 0 1 0
0 1 0 1 0 1
7:
1 0 1 0 1 0 1
0 1 0 1 0 1 0
1 0 1 0 1 0 1
0 1 0 1 0 1 0
1 0 1 0 1 0 1
0 1 0 1 0 1 0
1 0 1 0 1 0 1
8:
1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1
1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1
1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1
1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1
更改为0.5
或将0.4
更改为.0625
,原因何在?那你的代码就坏了。不,即使是过多的评论也无济于事 - 有人总会忽视它们。