c 改变双精度数的指数

Posted

技术标签:

【中文标题】c 改变双精度数的指数【英文标题】:c change the exponent of a double 【发布时间】:2014-09-07 15:17:07 【问题描述】:

假设我有一个double a = 0.3;。在不使用 pow() 等数学函数或手动相乘的情况下,我如何能够更改变量的指数。

我猜我必须使用指针访问变量的内存地址,找到指数并手动更改它。但是我该如何做到这一点呢?

请注意,这是在 8 位系统上,我正在尝试找到一种更快的方法将数字乘以 10^1210^9 , 10^610^3

最好的问候!

【问题讨论】:

我认为你不会有太大的成功。典型浮点的指数部分是 二进制 指数,而不是以 10 为底的指数。 看到 double 是一个 二进制 浮点数,调整指数位将无助于乘以 10 的幂,只能乘以 2 的幂。跨度> 您需要一个准确的结果,还是一个近似值对您来说足够好? 正如其他人所说,在这里摆弄比特对您没有帮助。但是如果你不使用pow 函数来计算你的因子10^x,你可能会加快你的计算速度。 (如果你现在正在这样做,那就是。) @user1806687:您可以使用查找表,例如:double decpow[] = 1, 10, 100, 1000, ... 并使用decpow[x] 而不是pow(10, x)。 (当然,这需要x 的非负整数值。但也有类似的解决方案取决于您的需要。似乎您只使用与单位前缀相关的十次方,如千-、兆-等) 【参考方案1】:

注意a*10^3 = a*1000 = a*1024 - a*16 - a*8 = a*2^10 - a*2^4 - a*2^3

所以你可以计算a*10^3如下:

将11个指数位读入int exp

将 52 个小数位读入double frac

计算double x,以exp+10为指数,frac为分数

计算double y,以exp+4为指数,frac为分数

计算double z,以exp+3为指数,frac为分数

计算输出为x-y-z,如果a < 0,别忘了加上符号位

您可以对其他选项(a*10^6a*10^9a*10^12)使用类似的方法...


您可以通过以下方式以“干净”的方式完成所有工作:

double MulBy1000(double a)

    double x = a;
    double y = a;
    double z = a;

    unsigned long long* px = (unsigned long long*)&x;
    unsigned long long* py = (unsigned long long*)&y;
    unsigned long long* pz = (unsigned long long*)&z;

    *px += 10ULL << 52;
    *py +=  4ULL << 52;
    *pz +=  3ULL << 52;

    return x - y - z;

请注意,我不确定这段代码是否违反了严格的别名规则。

【讨论】:

当指数 > minimum_exponent 时,frac 需要更多的工作来解释隐含的1 位。 @chux:我同意。这只是一个大概的思路,具体的实现细节留给OP去处理……谢谢。 a 永远不会小于 0。那么,如何读取指数位和分数位? @user1806687:请注意第二次更新(给出乘以 10^3 的完整实现)。 @user1806687:不客气,这对我来说也是一个好习惯 :)【参考方案2】:

一个数乘以 10 相当于

a) 将原始数字乘以 2 b) 将原始数字乘以 8 c) 将 (a) 和 (b) 的结果相加。

这是可行的,因为 to 是二进制的 1010

因此,一种方法是增加指数(对于 (a)),将 3 添加到指数(对于 (b)),然后添加结果。

要乘以 10^n,重复上述 n 次。或者计算出 1,000、1,000,000 等的二进制表示,并添加相关的 1。您可以通过注意 1000 例如 1024(例如)是 1024 - 16 - 8 来让事情变得更容易,即

a) 将原始的指数加 10 以乘以 1024 b) 将原始的指数加 4 以乘以 16 c) 将原始的指数加 3 以乘以 8 d) 从 (a) 减去 (b) 和 (c) 得到答案。

同样,您可以多次执行 10^6、10^9 等。

对于 n 的快速近似值和 3 的倍数的幂,只需将 10n/3 添加到指数(如 1024 ~= 1000)

【讨论】:

【参考方案3】:

为了好玩,一个简单的递归解决方案。

double ScalePower10(double x, unsigned power) 
    if (power <= 1) 
      if (power == 0) return x;
      return x * 10.0;
    
    double y = ScalePower10(x, power/2);
    y = y*y;
    if (power%2) y *= 10.0;
    return y;
  

【讨论】:

嗨 Chux。我认为 OP 是(隐含地)试图避免浮点运算。除此之外,尽管您的解决方案对于所有可能的指数都是通用的,但我认为 OP 要求的是一个非常具体的解决方案(对于 a*10^3a*10^6a*10^9a*10^12)。鉴于这一事实,OP 正在寻求一种优化的解决方案,即以非通用解决方案的价格获得最佳性能。

以上是关于c 改变双精度数的指数的主要内容,如果未能解决你的问题,请参考以下文章

C语言中单双精度数表示啥意思?

我在哪里可以找到 AVX 指数双精度函数?

用指数舍入一个双精度值

将双精度打印到字符串流时如何避免“指数”格式

如何在android中添加两个没有指数的双精度值

来自用户输入的双指数