如何翻转双精度的指数(例如1e300-> 1e-300)?

我有兴趣编写一个快速的C程序来翻转double的指数。 例如,该程序应将1e300转换为1e-300。 我想最好的方法是一些操作,但我缺乏足够的知识来实现​​这一点。 有什么好主意吗?

假设你的意思是否定小数指数,用科学记数法表示十指数的幂:

 #include  double negate_decimal_exponent(const double value) { if (value != 0.0) { const double p = pow(10.0, -floor(log10(fabs(value)))); return (value * p) * p; } else return value; } 

在上面, floor(log10(fabs(value)))是值的绝对值的基数10对数,向下舍入。 从本质上讲,它是使用科学记数法的十个指数value幂。 如果我们否定它,并将十倍的力量提升到那个力量,我们就会得到十倍的力量。

我们无法计算p的平方,因为它可能在幅度上非常大的值值下溢,或者在幅度上非常小的值值上溢。 相反,我们将value乘以p ,以使乘积的幅度接近一致(即十进制指数为零); 然后将其乘以p ,基本上否定十进制指数。

因为零的十进制对数是未定义的,所以我们需要单独处理它。 (我最初错过了这个角落的情况;感谢chux指出它。)

这是一个示例程序来演示:

 #include  #include  #include  double negate_decimal_exponent(const double value) { if (value != 0.0) { const double p = pow(10.0, -floor(log10(fabs(value)))); return (value * p) * p; } else return value; } #define TEST(val) printf("negate_decimal_exponent(%.16g) = %.16g\n", val, negate_decimal_exponent(val)) int main(void) { TEST(1.0e300); TEST(1.1e300); TEST(-1.0e300); TEST(-0.8e150); TEST(0.35e-25); TEST(9.83e-200); TEST(23.4728395e-220); TEST(0.0); TEST(-0.0); return EXIT_SUCCESS; } 

当编译时(记得与数学库链接, -lm )并运行,输出(在我的机器上;应该在使用IEEE-754 Binary64 for double s的所有机器上输出相同的内容):

 negate_decimal_exponent(1e+300) = 1e-300 negate_decimal_exponent(1.1e+300) = 1.1e-300 negate_decimal_exponent(-1e+300) = -1e-300 negate_decimal_exponent(-8e+149) = -8e-149 negate_decimal_exponent(3.5e-26) = 3.5e+26 negate_decimal_exponent(9.83e-200) = 9.83e+200 negate_decimal_exponent(2.34728395e-219) = 2.34728395e+219 negate_decimal_exponent(0) = 0 negate_decimal_exponent(-0) = -0 

有没有更快的方法来做到这一点?

当然。 构造一个10的幂的查找表,并使用二进制搜索来找到小于value 。 有一个第二个查找表有两个乘数,当乘以value ,否定10的十进制幂。 需要两个因素,因为单个因素没有必要的范围和精度。 (但是,这两个值相对于十对数是对称的。)对于具有千指数的查找表(涵盖IEEE-754双精度数,但是应该在编译时检查它是否覆盖DBL_MAX ),那就是进行十次比较和两次乘法(使用浮点值),因此速度非常快。

便携式程序也可以在运行时计算必要的表。