5

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

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

4

4 回答 4

8

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

确切地。这种技术可以在 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

*, -, 并且+必须完全是 IEEE 754 操作,精度为f,才能正常工作。在 Intel 架构上,这些操作由 SSE2 指令集提供。Visual C 在它编译的 C 程序的前奏中将历史 FPU 的精度设置为 53 位,这也有帮助。

于 2013-08-27T09:46:17.633 回答
1

分解数字的 c 方法是absand frexp,它删除符号和指数。结果必然存在于 [ 0.5 , 1.0 ) 中。乘以1<<N整数部分(由 获得modf)包含前 N 位。

于 2013-08-27T07:01:05.930 回答
1

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

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

您遇到的真正问题是:

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

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

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

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

希望这可以帮助。

于 2013-08-27T06:38:24.623 回答
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 的幂来做所有的乘法/除法,那么本金是一样的。

于 2013-08-27T07:02:01.547 回答