Ada:浮点文字与浮点变量

问题描述

在我的 Ada 代码中舍入浮点数时,我看到了一些奇怪的行为。

我知道浮动是不可靠的,有时它们不能准确表示。

我的问题是,如果您先将值存储在变量中,为什么会很重要。

float'rounding(8.9 / 0.2)

上面的结果是45,这似乎是有道理的,8.9 / 0.2 = 44.5 那么从零舍入。 (我还尝试将每个数字转换为浮点数以确保没有类型差异)

然后

a : float : 8.9;
b : float : 0.2;
float'rounding(a / b)

这次是44。这意味着 a / b = 44.4999999 然后向下取整。

为什么在变量中保存值会改变所有相同类型的计算结果?!

任何见解都会很棒!

解决方法

Ada 实数是universal_real 类型,可用于涉及实数类型的计算,例如float 或long_float,只要文字值在该类型的有效值范围内即可。

Universal_real 被实现为计算机浮点硬件可表示的“最大”类型。这类似于 C 语言,其中真正的文字是双精度的。

看下面的例子:

with Ada.Text_IO; use Ada.Text_IO;

procedure Main is
   a_val : constant := 8.9;
   b_val : constant := 0.2;
   a     : float := a_val;
   b     : float := b_val;
   a_l   : long_float := a_val;
   b_l   : long_float := b_val;
begin
   Put_Line(Float'Image(Float'Rounding(a_val / b_val)));
   Put_Line(Float'Image(Float'Rounding(a / b)));
   Put_Line(Long_Float'Image(Long_Float'Rounding(a_l / b_l)));
end Main;

命名数字 a_val 和 b_val 的类型为universal_real。程序的输出为:

 4.50000E+01
 4.40000E+01
 4.50000000000000E+01

直接使用名称number的除法与使用long_float的除法相同,与使用float的除法不同。

,

我不了解 Ada,但大多数这些数字无法准确表示为(二进制)浮点数。 Jeffrey 指出不同之处在于您的计算完全在编译时执行,但他认为说明运行时版本给出“错误”答案的原因可能会有所启发。

使用binary32表示,即Ada中的float变量,我们得到:

input       nearest representable float
8.9       =  8.8999996185302734375
0.2       =  0.20000000298023223876953125
8.9 / 0.2 = 44.499996185302734375

对结果进行四舍五入在数学上按预期工作,但由于之前的精度损失,您最终得到 44。

相比之下,binary64 浮动,即 Ada 中的 long_float,恰好相反:

8.9       =  8.9000000000000003552713678800500929355621337890625
0.2       =  0.200000000000000011102230246251565404236316680908203125
8.9 / 0.2 = 44.5

在除法过程中错误发生取消,因此精确结果为 44.5,四舍五入符合预期。

我倾向于使用 Python REPL 以交互方式快速检查这些,decimal module 对于查看浮点数的扩展特别有用。 Python 本身只知道 binary64 浮点数,但 NumPy 库提供对其他 floating-point types 的访问。