Juniper浮点场景/错误中粘性位丢失的细节是什么



在一些Juniper MX路由器上,浮点处理不正确:如果在计算过程中向右移动超过8位(下溢),则粘性位将丢失。有解决办法吗?是否存在任何已知的影响?它修好了吗?这是IEEE可以接受的选项吗?其他系统中是否存在此问题?

数学细节示例(最好使用固定宽度字体和宽屏幕查看):

                                                                                                    1
shifts:                                                                                                                                                          12345678901
4095.05615204245304994401521980762481689453125000000000   = 0x1.ffe1cbff5e3e1p+11 = 0x40affe1cbff5e3e1 =  111111111111.00001110010111111111101011110001111100001
+   1.0000137123424794882708965815254487097263336181640625 = 0x1.0000e60e10001p+0  = 0x3ff0000170168000 =             1.0000000000000000111001100000111000010000000000000001
                                                                                                     ^
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
                                    1000000000000.000011100110000011100001000000000000000010s
                                                                                         LGRS
                                                                                         0101 
                                             1          2         3         4         5       
mantissa bit #:                                                                                           1234567890123 4567890123456789012345678901234567890123    
4096.0561657547959839575923979282379150390625             = 0x1.0000e60e10001p+12 = 0x40b0000e60e10001 = 1000000000000.0000111001100000111000010000000000000001               (on "all" systems/correct)
4096.056165754795074462890625                             = 0x1.0000e60e10000p+12 = 0x40b0000e60e10000 = 1000000000000.0000111001100000111000010000000000000000               (on Juniper router)
^                                                         ^                        ^                                                        ^

互联网消息来源告诉我,许多MX系列路由器使用Intel x86 CPU。当x87配置为在扩展精度模式下操作时,观察到的行为与使用x87 FPU进行浮点计算(与SSE或AVX相反)完全一致。

x87 FPU将所有操作数存储在80位寄存器中,其中每个寄存器使用64个有效位(尾数)保存一个浮点操作数,有效位的整数位是显式的。FPU控制字的位8和9表示精度控制字段,该字段指示FPU将在哪个位位置对结果进行舍入。设置为2相当于双倍精度,而设置为3表示舍入到扩展精度。

大多数类Unix的32位操作系统将x87舍入控制设置为3,而Windows将其设置为2。我不知道现代的Junos是32位操作系统还是64位操作系统。出于向后兼容性的原因,它可能会保留x87和FPU精度控制设置3的使用。

x87精度控制设置为3(扩展精度)时,双舍入存在问题。浮点运算的结果首先四舍五入到扩展精度,并存储在内部FPU寄存器中。稍后,当该结果存储到与double变量相对应的存储位置时,数据从寄存器中取出并再次四舍五入

我使用英特尔编译器在Windows64上对问题的具体场景进行了编程,以便轻松访问x87汇编语言指令。程序以三种不同的格式(十进制浮点、十六进制浮点和二进制)转储两个源操作数ab以及和r,还转储这些操作数的内部80位表示(带有t前缀)。

通过将USE_X87_EXTENDED_PRECISION定义为01,可以在计算之前将FPU的精度控制设置为双精度或扩展精度,并且相关FPU控制字的值显示为compute cw。当USE_X87_EXTENDED_PRECISION设置为0时,程序的输出为:

original cw=027f
compute  cw=027f
a=4.0950561520424530e+003  0x1.ffe1cbff5e3e1p+11 40affe1cbff5e3e1 ta=400afff0e5ffaf1f0800
b=1.0000137123424795e+000   0x1.0000e60e10001p+0 3ff0000e60e10001 tb=3fff8000730708000800
r=4.0960561657547960e+003  0x1.0000e60e10001p+12 40b0000e60e10001 tr=400b8000730708000800

然而,当USE_X87_EXTENDED_PRECISION1时,结果是:

original cw=027f
compute  cw=037f
a=4.0950561520424530e+003 0x1.ffe1cbff5e3e1p+11 40affe1cbff5e3e1 ta=400afff0e5ffaf1f0800
b=1.0000137123424795e+000  0x1.0000e60e10001p+0 3ff0000e60e10001 tb=3fff8000730708000800
r=4.0960561657547951e+003 0x1.0000e60e10000p+12 40b0000e60e10000 tr=400b8000730708000400

在第二次取整期间,从trr,取整位为1,但粘性位为0,因为经过取整位的所有尾随有效位都为零,所以"0";甚至";默认舍入模式的一部分";四舍五入到最接近或甚至"0";

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#define USE_X87_EXTENDED_PRECISION (1)
typedef struct tbyte {
uint64_t l;
uint16_t h;
} tbyte;
uint64_t double_as_uint64 (double a)
{
uint64_t r; memcpy (&r, &a, sizeof r); return r;
}
int main (void)
{
double a = 0x1.ffe1cbff5e3e1p+11;
double b = 0x1.0000e60e10001p+0;
double r;
uint16_t cw_orig, cw_comp, cw_temp;
tbyte ta, tb, tr;
__asm fstcw word ptr [cw_orig];
#if USE_X87_EXTENDED_PRECISION
cw_temp = cw_orig | (3 << 8);
__asm fldcw word ptr [cw_temp];
#endif // USE_X87_EXTENDED_PRECISION
__asm fstcw word ptr [cw_comp];
__asm fld qword ptr [a];
__asm fld qword ptr [b];
__asm fld st(1);
__asm fadd st, st(1);
__asm fst qword ptr [r];
__asm fstp tbyte ptr [tr];
__asm fstp tbyte ptr [tb];
__asm fstp tbyte ptr [ta];
__asm fldcw word ptr [cw_orig];
printf ("original cw=%04xn", cw_orig);
printf ("compute  cw=%04xn", cw_comp);
printf ("a=%23.16e %21.13a %016llx ta=%04x%016llxn", a, a, double_as_uint64 (a), ta.h, ta.l);
printf ("b=%23.16e %21.13a %016llx tb=%04x%016llxn", b, b, double_as_uint64 (b), tb.h, tb.l);
printf ("r=%23.16e %21.13a %016llx tr=%04x%016llxn", r, r, double_as_uint64 (r), tr.h, tr.l);
return EXIT_SUCCESS;
}

相关内容

  • 没有找到相关文章

最新更新