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

Is hardcode float precise if it can be represented by binary format in IEEE 754?

例如,0、0.5、0.15625、1、2、3... 是从 IEEE 754 转换而来的值。它们的硬编码版本是否精确?

例如:

float a=0;
if(a==0){
    return true;
}

总是return是吗?其他示例:

float a=0.5;
float b=0.25;
float c=0.125;

a * b 是否始终等于 0.125 且 a * b==c 始终为真?还有一个例子:

int a=123;
float b=0.5;

a * b 总是 61.5 吗?或者一般来说,整数乘以 IEEE 754 二进制浮点数是否精确?

或者更一般的问题:如果值是硬编码的,并且值和结果都可以用 IEEE 754 中的二进制格式表示(例如:0.5 - 0.125),那么该值是否精确?

原则上应该是可以的。如果您将自己限制在这个 class 具有有限 2 次方表示的数字。

但这很危险:如果有人拿走您的代码并将您的 0.5 更改为 0.4 或您的 .0625 更改为 .065 怎么办?那么你的代码就坏了。不,即使过多的评论也无济于事 - 总会有人忽略它们。

浮点数没有固有的模糊性。只是有些,但不是全部,实数不能准确表示。

与固定宽度的十进制表示法比较,假设是三位数。整数1可以表示,用1.00,1/10可以表示,用0.10,但1/3只能近似,用0.33.

如果我们改用二进制数字,整数 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. Also, this somewhat more accessible website: The Floating-Point Guide

不,但正如 Thomas Padron-McCarthy 所说,一些数字可以使用二进制精确表示,但并非所有数字都可以。

这是我向与我一起工作的非开发人员解释的方式(比如 Mahmut Ali,我也在研究一个非常古老的财务包):想象一下有一个非常大的蛋糕被切成 256 片。现在,您可以将整个蛋糕分给 1 个人,将一半的蛋糕分给 2 个人,但是一旦您决定将其分成 3 份,您就不能再分了——要么是 85 分,要么是 86 分——你不能再分蛋糕了。浮点数也是如此。您只能在某些表示上获得精确数字 - 有些数字只能近似计算。

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++ 标准。