2

我使用 c++ 来计算各种类型的特殊函数(例如 Lambert 函数、求值反转的迭代方法等)。在许多情况下,直接使用尾数和指数显然有更好的方法。

我找到了很多如何提取尾数和指数部分的答案,但是所有这些都只是“计算速度不是很有效的学术案例”,对我来说有点无用(我使用尾数和指数操作的动机是改进计算速度)。有时我需要调用一些特定的函数大约十亿次(非常昂贵的计算),所以每次保存的计算工作都很好。并且使用将尾数作为双精度返回的“freexp”不是很合适。

我的问题是(对于具有 IEEE 754 浮点的 c++ 编译器):

1)如何读取浮点/双精度尾数的特定位?

2)如何将整个尾数读入浮点/双精度的整数/字节?

3) 与 1)、2) 相同的问题。

4) 写作题与 1)、2)、3) 相同。

如果我直接使用尾数或指数,我的动机是更快的计算。我想必须有一个非常简单的解决方案。

4

3 回答 3

6

在许多情况下,直接使用尾数和指数显然有更好的方法。

我从我的信号处理工作中知道这种感觉非常好,但事实是指数和尾数不能简单地用作单独的数字。IEEE754 规定了一些特殊情况和偏移量等。

我想必须有一个非常简单的解决方案。

工程经验告诉我:以“一个简单的解决方案”结尾的句子通常不是真的。

“学术案例”

然而,这绝对不是真的(我会在最后提到一个例子)。

IEEE754 浮点数优化在现实世界中的使用非常可靠。但是,我发现随着后来的 x86 处理器能够执行 SIMD(单指令,多数据)以及浮点与大多数“位移”操作一样快的总体事实,我通常怀疑您不明智尝试自己在一点水平上做到这一点。

通常,由于 IEEE754 是一种标准,您会在任何地方找到有关它如何存储在您的特定架构中的文档。如果你看过,你至少应该找到解释如何做 1) 和 2) 的维基百科文章(它不像你想象的那样静态)。

更重要的是: 不要试图比你的编译器更聪明。你可能不会,除非你明确知道如何向量化多个相同的操作。

试验您的特定编译器的数学优化。如前所述,如今他们通常做的不多。CPU 在进行浮点计算时并不比在整数上慢,这是必然的。

我宁愿看看你的算法并在那里寻找优化的潜力。

另外,当我在做的时候,让我们介绍一下 VOLK(内核向量优化库),它主要是一个用于信号处理的数学库。http://libvolk.org有一个概述。查看以 32f 开头的内核,例如32f_expfast。您会注意到有不同的实现,通用的和 CPU 优化的,每个 SIMD 指令集都不同。

于 2016-01-09T19:48:13.420 回答
1

您可以将 fp 值的地址复制到 an 中unsigned char*,并将结果指针视为覆盖 fp 值的数组的地址。

于 2016-01-09T19:51:02.793 回答
-1

在 C 或 C++ 中,如果x是 IEEE 双精度,那么如果L是 64 位长整数,则表达式

L = *((long *) &x);

将允许直接访问这些位。Ifs是表示符号的字节 (0 = '+', 1 = '-'),e是表示无偏指数的整数,并且f是表示小数位的 long int,则

s = (byte)(L >> 63);

e = ((int)(L >> 52) & 0x7FF) - 0x3FF;

f = (L & 0x000FFFFFFFFFFFFF);

(如果 f 是一个规范化数字,即不是 0、非规范化、inf 或 NaN,那么最后一个表达式应该0x0010000000000000添加到它以允许 IEEE 双精度格式中的隐式高 1 位。)

将符号、指数和分数重新打包成双精度是类似的:

L = (s << 63) + ((e + 0x3FF) << 52) + (f & 0x000FFFFFFFFFFFFF);

x = *((双 *) &L);

上面的代码只生成少量机器指令,在用 64 位代码编译的 64 位机器上没有子程序调用。对于 32 位代码,有时会调用执行 64 位算术运算,但好的编译器通常会生成内联代码。在任何一种情况下,这种方法都非常快。

如果允许使用不安全的代码,类似的方法适用于 C#,使用L = bitConverter.DoubleToInt64Bits(x);x = BitConverter.Int64BitsToDouble(L);或完全如上。

于 2016-01-30T08:29:50.870 回答