Language agnostic 典型浮点中没有倒数的最小正整数是什么?

Language agnostic 典型浮点中没有倒数的最小正整数是什么?,language-agnostic,floating-point,floating-accuracy,ieee-754,Language Agnostic,Floating Point,Floating Accuracy,Ieee 754,一个常见的假设是1/x*x==1。在符合IEEE 754标准的普通硬件上,打破这一点的最小正整数是什么 当乘法逆的假设失败时,写得不好的有理算术就停止工作。由于许多语言,包括C和C++默认使用浮点数转换成整数,使用圆到零,即使是小的误差也会导致积分结果一个一个地偏离。 快速测试程序产生各种结果 #包括 int main(){ { 双n; 对于(n=2;1/n*n==1;++n); 标准::cout双精度: 1/41=0x1.8f9c18f9c18fap-6,41*0x1.8f9c18f9c18f

一个常见的假设是
1/x*x==1
。在符合IEEE 754标准的普通硬件上,打破这一点的最小正整数是什么

当乘法逆的假设失败时,写得不好的有理算术就停止工作。由于许多语言,包括C和C++默认使用浮点数转换成整数,使用圆到零,即使是小的误差也会导致积分结果一个一个地偏离。 快速测试程序产生各种结果

#包括
int main(){
{
双n;
对于(n=2;1/n*n==1;++n);
标准::cout双精度:

1/41=0x1.8f9c18f9c18fap-6,41*0x1.8f9c18f9c18fap-6=0x1.000000000000028,四舍五入为1。 1/45=0x1.6c16c16c16c17p-6,45*0x1.6c16c16c16c17p-6=0x1.00000000000002c,四舍五入为1

但是,

1/49=0x1.4e5e0a72f0539p-6,49*0x1.4e5e0a72f0539p-6=0x0.FFFFFFFFFFFA4,四舍五入为0x0.fffffffffffff8=0x1.FFFFFFFFF0P-1

但49有一个倒数!它是0x1.4e5e0a72f053ap-6

更一般地说,如果f是[1,2]中的浮点数,则f具有倒数。在通常的四舍五入到偶数运算中,如果一个数位于[1-2-54,1+2-53]中,则它将四舍五入为1。 请注意,距离1/f最近的双精度,比如说d,距离1/f的距离小于2-54。如果d>1/f,那么我们是金色的;1
编辑:上面的推理是错误的,因为两个连续双精度之间的跨距是两倍。没有倒数的双精度示例是0x1.ffffffbfffffe。0x1.000000200001P-1太小,但0x1.0000002000002p-1太大。没有倒数的整数的最小示例l是237。1/237大约是0x1.1485f0e0acd3B68c6Bp-8,四舍五入为0x1.1485f0e0acd58p-8。这个数字太小,而后面的一个双精度数字太大。

这个问题似乎与C++选择的转换为整数的方法有关

这里有一个用于比较、测试32位、64位和80位浮点的Ada版本(只需要求7位、15位和18位,或者前两位使用内置类型)

首先是结果和注释,代码如下

$ gnatmake fp_torture.adb
gcc -c fp_torture.adb
gnatbind -x fp_torture.ali
gnatlink fp_torture.ali
$ ./fp_torture
 41 ( 5.96046E-08)
Error representing float  2.14748E+09 as integer
 49 ( 1.11022302462516E-16)
 2147483647 ( 0.00000000000000E+00)
 41 ( 5.42101086242752217E-20)
 2147483647 ( 0.00000000000000000E+00)
$

我们可以看到,浮点计算复制了C++的故障点,并确认了387个80位浮点的使用,但是将(非常接近于1的数)转换成整数,比较工作。

看到这个,在C++示例中添加适当的舍入可以允许比较工作。在Max It中添加终止条件,“双N”则起作用。

++n
无法增加n时,“float n”中出现一个点,因此迭代器停止迭代,但那是另一回事

下面的Ada版本创建了一个泛型,因此我可以用任何浮点类型实例化它。 (异常处理程序是必需的,因为2^31-1已转换为32位浮点和反向溢出…)

带有Ada.Text\u IO;
使用Ada.Text\u IO;
酷刑的程序是
通用的
类型浮点数\类型为数字;
程序测试;
程序测试
F:浮球型;
开始
--对于(n=2;1/n*n==1;++n);
对于2.自然“最后一个循环中的i
F:=浮点数型(i);
当1.0/F*F/=1.0时退出;
端环;
放线(自然的)图像(自然的(F))和“(”
&浮点型“图像(1.0-(1.0/F*F))&”);
--对于(;(int)(1/n*n)==1;++n);
对于1.自然“最后一个循环中的i
F:=浮点数型(i);
自然(1.0/F*F)/=1时退出;
端环;
放线(自然的)图像(自然的(F))和“(”
&浮点型“图像(1.0-(1.0/F*F))&”);
例外
当约束_错误=>
放置线(“表示浮点的错误”和浮点类型”图像(F)
&“作为整数”);
结束;
大浮点数类型为数字18;
程序Test7是新的测试FP(浮动);
程序Test15是新的测试FP(长浮点数);
程序Test18是新的测试FP(大浮点数);
开始
测试7;
试验15;
测试18;
结束酷刑;

它可能早在
1/3*3
时就失败了,因为
1/3
不能用二进制浮点值精确表示。唯一精确的方法是
1/3*3
恰好朝
1
而不是
0.99999…
1.00000001
或其他什么方向旋转。@Mystical可以,但通常不会。@Seems表示FPU的设计不是这样的。我想知道可靠地失败的最低值是什么。或者,FPU采用了什么二进制技巧能够将数字正确地四舍五入到40,但仍然在该范围内的不同点失败。我很想投票结束这个问题,因为它没有说明浮点错误或错误对浮点运算进行推理的好方法。特别询问
1/x*x==1
失败的条件,或者x存在一个r,使得
x*r==1
的计算结果为真,这对浮点运算的工作原理没有什么帮助,也不能为预测或控制任何其他情况下的错误提供什么依据此外,这个问题否定了语言标准或编译器,但试图用语言和编译器来实验性地研究这个问题。对浮点属性的认识非常低;这样的问题可能会帮助程序员更加注意真正的陷阱,这就是为什么我投了更高的票。@BrianDrummond:如果你学会了回答这个问题,这对其他浮点问题有什么帮助?我们得到的答案不是解释除法和后续乘法中的四舍五入如何组合生成1或不是1。他们没有详细说明浮点格式或如何计算e的边界
49 (1.11022e-16)
49 (1.11022e-16)
41 (5.96046e-08)
41 (5.96046e-08)
41 (5.42101e-20)
41 (5.42101e-20)
41 (5.42101e-20)
41 (5.42101e-20)
$ gnatmake fp_torture.adb
gcc -c fp_torture.adb
gnatbind -x fp_torture.ali
gnatlink fp_torture.ali
$ ./fp_torture
 41 ( 5.96046E-08)
Error representing float  2.14748E+09 as integer
 49 ( 1.11022302462516E-16)
 2147483647 ( 0.00000000000000E+00)
 41 ( 5.42101086242752217E-20)
 2147483647 ( 0.00000000000000000E+00)
$
with Ada.Text_IO;   
use Ada.Text_IO;

procedure FP_Torture is

    generic
       type Float_Type is digits <>;
    procedure Test_FP;

    procedure Test_FP is
       F : Float_Type;
    begin
       -- for ( n = 2; 1 / n * n == 1; ++ n ) ;
       for i in 2 .. Natural'Last loop
          F := Float_Type(i);
          exit when 1.0 / F * F /= 1.0;
       end loop;
       Put_Line(natural'image(natural(F)) & " (" 
               & Float_Type'image(1.0 - (1.0 / F * F)) & ")");

       -- for ( ; (int) ( 1 / n * n ) == 1; ++ n ) ;
       for i in 1 .. Natural'Last  loop
          F := Float_Type(i);
          exit when natural(1.0 / F * F) /= 1;
       end loop;
       Put_Line(Natural'image(Natural(F)) & " (" 
               & Float_Type'image(1.0 - (1.0 / F * F)) & ")");
    exception
       when Constraint_Error => 
           Put_Line("Error representing float " & Float_Type'image(F) 
                    & " as integer");
    end;

    type Big_Float is digits 18;

    procedure Test7 is new Test_FP(Float);
    procedure Test15 is new Test_FP(Long_Float);
    procedure Test18 is new Test_FP(Big_Float);

begin
    Test7;
    Test15;
    Test18;
end FP_Torture;