分解浮点数

时间:2013-08-27 06:28:28

标签: c# c floating-point

给定一个浮点数,我想将它分成一个部分之和,每个部分都有一个给定的位数。例如,给定3.1415926535并告诉它将其分成10个基本的10个部分,每个4位数,它将返回3.141 + 5.926E-4 + 5.350E-8。实际上,我想将一个double(具有52位精度)分成三个部分,每个部分具有18位精度,但是使用base-10示例更容易解释。我不一定反对使用标准双精度IEEE浮点数的内部表示的技巧,但我真的更喜欢一种纯粹保留在浮点范围内的解决方案,以避免任何与字节序相关或非标准的问题浮点表示。

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

4 个答案:

答案 0 :(得分:7)

  

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

完全。这种技术可以在Veltkamp / Dekker乘法中找到。虽然可以像在其他答案中一样访问表示的位,但您也可以仅使用浮点运算。 this blog post中有一个实例。您感兴趣的部分是:

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

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

答案 1 :(得分:1)

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

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

你遇到的真正问题是:

  1. 处理隐式前导“1”。在边界情况下,这会导致你+0 / -0的情况。由于这个原因,我可以预测你的代码将充满特殊情况。
  2. 指数非常低,即使在考虑“前导1”问题之前,您的意愿也会超出范围。即使在范围内,您也需要求助于低于正常范围。鉴于正常数字和次正规数之间的差距很大,我也敢于预测会有多个有效浮点数范围在这个方案中没有可能的表示。
  3. 除非如上所述,指数的处理应该是微不足道的:对第二个和第三个18位部分减去18和36(然后找到前导1,当然进一步减少它。)

    丑陋的解决方案?在边界情况下,IEEE 754 本身是丑陋的。 Big-endian / little-endian是你问题最少的。

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

    希望这有帮助。

答案 2 :(得分:1)

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

答案 3 :(得分:0)

通常,在数字上,您可以向左移位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的幂来做所有的暗示/除法,那么校长就是一样的。