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



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

假设你的意思是否定十进制指数,即科学记数法中十指数的幂:

#include <math.h>
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)))value绝对值的10底对数,四舍五入。从本质上讲,它是使用科学记数法value十指数的幂。如果我们否定它,并将十的幂提高到那个幂,我们就有了那个十的幂的倒数。

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

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

下面是一个示例程序来演示:

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
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) = %.16gn", 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 的机器上输出相同的double秒):

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时,取而代十的十进制幂。需要两个因素,因为单个因素没有必要的范围和精度。(但是,这两个值相对于以十为底的对数是对称的。对于具有千个指数的查找表(涵盖 IEEE-754 双精度,但应在编译时检查它是否涵盖DBL_MAX),这将是十个比较和两个乘法(使用浮点值),所以它会非常快。

可移植程序也可以计算运行时所需的表。

相关内容

最新更新