基于ARM伪代码,用有限精度浮点实现IEEE 754合规运算可行吗?
背景
通常浮点运算基于整数算术实现(如Berkeley SoftFloat),而ARM伪代码(来自Arm官方A64指令集架构文档)采用无限精度浮点类型real实现浮点运算。
我的实现
我用C语言编写了基于ARM伪代码的32位浮点运算模型,将real用有限精度浮点类型替代:64位double、x86_64平台的80位long double或AArch64平台的128位long double:
typedef double Real; //typedef long double Real;
测试问题
测试中发现部分失败案例:大多与缺失Inexact和/或Underflow异常有关,部分结果存在±1位偏差。
与基于整数算术的实现(通过检查特定位是否非零)不同,ARM伪代码的FPRoundBase函数会计算error:
// Get the unrounded mantissa as an integer, and the "units in last place" rounding error. int_mant = RoundDown(mantissa * 2.0^F); // < 2.0^F if biased_exp == 0, >= 2.0^F if not error = mantissa * 2.0^F - Real(int_mant);
Inexact和/或Underflow异常的触发依赖该error:
if !altfp && biased_exp == 0 && (error != 0.0 || trapped_UF) then if fpexc then FPProcessException(FPExc_Underflow, fpcr); ... if error != 0.0 then if fpexc then FPProcessException(FPExc_Inexact, fpcr);
部分场景下error本应非零却被计算为0,导致异常缺失,但数值结果正确。例如x + y运算:
x -4.96411207e-35 0x8683f7ff y -3.98828101 0xc07f3fff x after FPUnpack -4.9641120695506692e-35 0xb8d07effe0000000 y after FPUnpack -3.9882810115814209 0xc00fe7ffe0000000 x+y -3.9882810115814209 0xc00fe7ffe0000000 === FPRoundBase === op -3.9882810115814209 0xc00fe7ffe0000000 exponent 1 min_exp -126 biased_exp 128 int_mant 16728063 mantissa 1.9941405057907104 0x3fffe7ffe0000000 frac_size 23 error 0 0x0 ===
此处error为0,但实际将1.9941405057907104乘以2^23得到16728062.9999999995871232,舍入后为16728063,理论上error不应为0。
尝试的解决方法
我尝试局部提升计算error的精度,虽修复部分失败案例,但出现新的问题;其他调整手段也得到类似结果。所有Real(即double)运算均采用FE_TONEAREST模式。
核心疑问
基于ARM伪代码,采用有限精度浮点算术实现符合IEEE 754标准的32位浮点运算是否可行?
更新0:测试发现128位long double的失败案例比64位double少50%。
更新1:原文“error free”意为“IEEE 754 conforming”,已修正表述。
内容的提问来源于stack exchange,提问作者pmor

