使用浮点计算从浮点转换为十进制

时间:2013-07-17 21:08:13

标签: floating-point ieee-754 fma

我正在尝试将浮点双精度值x转换为带有12(正确舍入)有效数字的十进制数。我假设x介于10 ^ 110和10 ^ 111之间,因此其十进制表示形式为x.xxxxxxxxxxxE110。而且,为了好玩,我只想使用浮点运算。

我到达下面的伪代码,其中所有操作都是双精度操作,符号1e98是最接近数学10 ^ 98的双精度,而1e98_2是最接近的双精度到数学减法的结果10 ^ 98 - 1e98。符号fmadd(X * Y + Z)用于与操作数XYZ进行融合的乘法 - 加法运算。

  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)
  }

我为弥漫上述伪代码的困惑道歉,但对我来说还不是很清楚,因此有以下问题:

  1. 第一个fmadd是否按预期工作(计算1e98 *(分割期间出错)?

  2. 迹象。我不能说服自己他们是对的。但我无法说服自己也错了。

  3. 关于此算法可能产生错误结果的频率的任何想法,或许是争论?

  4. 如果它完全有效,如果“q = y / 1e98”变为“q = y * 1e-98”,则算法将继续有效(所有其他指令保持不变) )?

  5. 我还没有测试过这个算法。我没有任何带有fmadd指令的计算机,虽然我希望找到一个能够执行上述指令的计算机。

1 个答案:

答案 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

如果r1e98_2具有相同的符号,则可能超过5*10^97,因此您需要进一步处理r3 = 1e98_2*q + rh=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)。

在这种情况下,r1e98_2具有相同的符号,

  • (x/1e98) > 1000000000183.50000215

  • q有效数字因此四舍五入为1000000000184

  • r3>hr3*2^1074约为5.000001584620017e97)我们错误地增加了q+s,当它应该是q-s时,绝对是一个错误

我的回答是:

  1. 是的,r=fmadd(q * 1e98 - y)正好是1e98 *(分割时出错),但我们不关心除法,它只是提供一个猜测,重要的是减法是准确的。 / p>

  2. 是的,标志是正确的,因为|r| < 5*10^98|r+(10^98-1e98)*q|<|r|,如果标志相反。但我不确定1e98_2是否&lt; 0

  3. 第一个失败的例子(1.0000000001835e110 - 1.0e110)/1.0e110 ulp -> 1.099632e6,一个非常天真的猜想就是说,百万分之一的情况,r3正在下降......所以一旦q + s校正为qs, r3>h的出现r3t<ht在任何情况下远小于1 / 1,000,000 ......在感兴趣的范围内有超过10 ^ 15的双打,所以请考虑这不是一个严肃的答案...

  4. 是的,上面的讨论完全是关于猜测q,与它的生成方式无关,而且1中的减法仍然是准确的......