分解浮点数

本文关键字:浮点数 分解 | 更新日期: 2023-09-27 18:29:11

给定一个浮点数,我想把它分成几个部分的总和,每个部分都有给定的位数。例如,给定3.1415926535,并被告知将其分为10个基数的部分,每个部分4位,它将返回3.141+5.926E-4+5.350E-8。事实上,我想把一个double(精度为52位)分成三部分,每个部分的精度为18位,但用一个以10为基数的例子来解释更容易。我并不一定反对使用标准双精度IEEE浮点的内部表示的技巧,但我确实更喜欢一种纯粹停留在浮点领域的解决方案,以避免任何与endian依赖或非标准浮点表示有关的问题。

不,这不是家庭作业问题,是的,这有实际用途。如果你想确保浮点乘法是精确的,你需要确保你相乘的任何两个数字的位数永远不会超过你在浮点类型中有空间的一半。从这种分解开始,然后乘以所有部分并进行卷积,是实现这一点的一种方法。是的,我也可以使用任意精度的浮点库,但当只涉及几个部分时,这种方法可能会更快,而且重量肯定会更轻。

分解浮点数

如果你想确保浮点乘法是精确的,你需要确保你相乘的任何两个数字的位数永远不会超过你在浮点类型中有空间的一半。

没错。这种技术可以在Veltkamp/Dekker乘法中找到。虽然可以像其他答案中那样访问表示的位,但也可以只进行浮点运算。这篇博客文章中有一个例子。您感兴趣的部分是:

Input: f; coef is 1 + 2^N
 p = f * coef;
 q = f - p;
 h = p + q;  // h contains the 53-N highest bits of f
 l = f - h;  // l contains the N lowest bits of f

*-+必须完全是精度为f的IEEE 754运算才能工作。在英特尔体系结构上,这些操作由SSE2指令集提供。Visual C在其编译的C程序的前奏中将历史FPU的精度设置为53位,这也有帮助。

分解数字的c方法是absfrexp,它们去掉了符号和指数。结果必然在[0.5,1.0)中。乘以1<<N表示整数部分(由modf获得)包含前N位。

您可以使用BitConverter.DoubleToInt64BitsC#的逐位运算符。您似乎熟悉IEEE浮点格式,所以我不添加更多细节。

我刚刚注意到标签C。在这种情况下,您可以使用union并执行大致相同的操作。

你遇到的真正问题是:

  1. 处理隐式前导"1"。在边界情况下,这将导致+0/-0的情况。由于这个原因,我可以预测你的代码将充满特殊情况
  2. 在指数非常低的情况下,甚至在考虑"领先1"问题之前,您就会将指数超出范围。即使在范围内,你也需要求助于亚常态。考虑到正规数和次正规数之间的巨大差距,我也敢于预测,在这个方案中,会有几个有效的浮点数范围没有可能的表示

除了上面提到的,指数的处理应该是琐碎的:减去第二个和第三个18位部分的18和36(然后找到前导1,当然会进一步递减)。

丑陋的解决方案?IEEE 754在边界情况下本身就很丑陋。大端序/小端序是您遇到的最小问题。

就我个人而言,我认为这对你最初的目标来说太复杂了。只需坚持一个简单的问题解决方案:找到一个计算尾随零的函数(标准本身定义了一个吗?我可能会把它与libtrary混淆),并确保总和>52。是的,你对"半位数(?)"的要求(你的意思是26位,对吧?)比必要的更严格。同样也是错误的,因为它没有考虑到隐含的1。这也是为什么上面我没有说>=52,而是说>52。

希望这能有所帮助。

在数字上,通常可以向左移动n位数字,转换为整数并进行减法。

  a = (3.1415926535)*1000 = 3141.5926535
  b = (int) a             = 3141
  c = a - (double) b      = 0.5926535   << can convert this to 0.5926, etc.
  d = (double) b / 1000   = 3.141 << except this MIGHT NOT be exact in base 2!!

但是,如果你用2的幂做所有的乘法/除法,则原理是一样的。