如果可以用IEEE 754中的二进制格式表示硬编码是否精确浮动?

时间:2015-11-11 07:44:52

标签: c++ c floating-point precision floating-accuracy

例如,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),那么值是否准确?

4 个答案:

答案 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可以(再次)仅表示近似值。

但有些事情需要记住:

  • 相同的数字不是十进制数字。 1/10可以 用十进制数字写成0.1,但不使用二进制数字 数字,无论你使用了多少(无限远)。
  • 在实践中,很难跟踪哪些数字可以是 代表什么,不能代表什么。 0.5可以,但0.4不能。所以当你需要的时候 确切的数字,例如(通常)在与钱合作时,你不应该这样做 使用浮点数。
  • 根据一些消息来源,一些处理器做了一些奇怪的事情 内部对数字执行浮点计算 无法准确表示,导致结果在某种程度上有所不同 也就是说,在实践中,这是不可预测的。

(我的意见是,它实际上是一个合理的第一近似值,是的,浮点数 本身就是模糊的,所以除非你确定你的特定应用程序可以处理它,远离他们。)

有关您可能需要或想要的更多详情,请阅读着名的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(例如Tdouble)来检查您的实施是否声称与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,原因何在?那你的代码就坏了。不,即使是过多的评论也无济于事 - 有人总会忽视它们。