我正在尝试将浮点双精度值x
转换为带有12(正确舍入)有效数字的十进制数。我假设x
介于10 ^ 110和10 ^ 111之间,因此其十进制表示形式为x.xxxxxxxxxxxE110
。而且,为了好玩,我只想使用浮点运算。
我到达下面的伪代码,其中所有操作都是双精度操作,符号1e98
是最接近数学10 ^ 98的双精度,而1e98_2
是最接近的双精度到数学减法的结果10 ^ 98 - 1e98
。符号fmadd(X * Y + Z)
用于与操作数X
,Y
,Z
进行融合的乘法 - 加法运算。
y = x * 2^-1074; // exact
q = y / 1e98; // q is denormal and the significand of q interpreted
// as an integer is our candidate for the 12 decimal
// digits of x
r = fmadd(q * 1e98 - y); // close to 1e98 * (error made during the division)
// If 1e98_2 >= 0, we divided by a number that was smaller than we wished
// The correct answer may be q or q+1.
if (r and 1e98_2 have opposite signs)
{
return the significand of q;
}
s = copysign(2^-1074, r);
r1 = abs(r);
r2 = abs(1e98_2);
h = 1e98 * 0.5 * 2^-1074;
Set rounding mode to downwards
r3 = fmadd(r2 * q + r1);
if (r3 < h)
{
return the significand of q;
}
else
{
return significand of (q + s)
}
我为弥漫上述伪代码的困惑道歉,但对我来说还不是很清楚,因此有以下问题:
第一个fmadd是否按预期工作(计算1e98 *(分割期间出错)?
迹象。我不能说服自己他们是对的。但我无法说服自己也错了。
关于此算法可能产生错误结果的频率的任何想法,或许是争论?
如果它完全有效,如果“q = y / 1e98”变为“q = y * 1e-98”,则算法将继续有效(所有其他指令保持不变) )?
我还没有测试过这个算法。我没有任何带有fmadd指令的计算机,虽然我希望找到一个能够执行上述指令的计算机。
答案 0 :(得分:2)
让y/d
成为确切的操作,q=rnd(y/d)
是舍入到最近浮点数的结果
然后真实误差乘以d为rt=(rnd(y/d)-y/d)*d=q*d-y
,我们用fmadd执行的操作为r=rnd(q*d-y)
为什么q*d-y
是准确的(fmadd没有最终舍入)不太清楚,但要说q*d
的位数有限(<nbits(q)+nbits(d)
),y
的指数}是q*d
(+/- 1),因为错误是|rt|<0.5*ulp(q)*d
,这意味着第一个nbits(q)
正在消失......这回答了问题1。
所以q*1e98 - y = r
,其中|r|*2^1074 <= 0.5e98 < 5*10^98
(第二个不平等是幸运的)
q*(10^98) - y = r + (10^98-1e98)*q
其中|10^98-1e98|*q*2^1074 <= 0.5e95
(假设至少15位精度,log(2^53)/log(10) > 15
)
所以你问|q*(10^98)-y|*2^1074>5*10^97
您的|q*(10^98)-y|
近似为r+1e98_2*q
由于|r| < 5*10^98
和|r+(10^98-1e98)*q|<|r|
如果标志相反,我认为这对问题2有积极的回答。但我不确定1e98_2是否&lt; 0
如果r
和1e98_2
具有相同的符号,则可能超过5*10^97
,因此您需要进一步处理r3 = 1e98_2*q + r
与h=0.5e98*2^-1074
对于问题3,乍一看,我会说两件事可能会导致算法失败:
1e98_2
不准确(10^98-1e98-1e98_2 = -3.6e63
约。)
且h
不是ht=0.5*10^98*2^-1074
,但我们上面看到的要小一些。
真正的错误r3t
约为(1e98_2-3e63)*q + r < r3
(仅当&gt; 0时我们感兴趣,因为1e98_2&gt; 0)。
因此,当真实误差r3t低于真正的平均值ht时,误差r3的近似值高于近似平均值h可能导致不正确的舍入。是否可能,如果是,你的问题3有多频繁?
为了减轻上述不平等风险,您试图截断r3的大小,因此r3 <= 1e98_2*q + r
。对错误界限进行真正的分析我觉得有点累......
所以我扫描了一个错误,我发现的第一个失败的例子是1.0000000001835e110(我假设正确舍入到最接近的双倍,但它实际上是1000000000183.49999984153799821120915424942630528225695526491963291846957919215885146546696544423465444842668032e98)。
在这种情况下,r
和1e98_2
具有相同的符号,
(x/1e98) > 1000000000183.50000215
q
有效数字因此四舍五入为1000000000184
r3>h
(r3*2^1074
约为5.000001584620017e97)我们错误地增加了q+s
,当它应该是q-s
时,绝对是一个错误强>
我的回答是:
是的,r=fmadd(q * 1e98 - y)
正好是1e98 *(分割时出错),但我们不关心除法,它只是提供一个猜测,重要的是减法是准确的。 / p>
是的,标志是正确的,因为|r| < 5*10^98
和|r+(10^98-1e98)*q|<|r|
,如果标志相反。但我不确定1e98_2是否&lt; 0
第一个失败的例子(1.0000000001835e110 - 1.0e110)/1.0e110 ulp -> 1.099632e6
,一个非常天真的猜想就是说,百万分之一的情况,r3正在下降......所以一旦q + s校正为qs, r3>h
的出现r3t<ht
在任何情况下远小于1 / 1,000,000 ......在感兴趣的范围内有超过10 ^ 15的双打,所以请考虑这不是一个严肃的答案...
是的,上面的讨论完全是关于猜测q,与它的生成方式无关,而且1中的减法仍然是准确的......