Math 如何在不进行大整数乘法的情况下获得5**x的前x个前导二进制数字

Math 如何在不进行大整数乘法的情况下获得5**x的前x个前导二进制数字,math,floating-point,Math,Floating Point,我想以完美的精度高效、优雅地计算5**x的前x个前导二进制数字 例如,5**20是101011011111000110101111000101011011010110001。前8个前导二进制数字是10101101 在我的用例中,x最多只有1-60。我不想创建一个表。使用64位整数的解决方案就可以了。我只是不想使用大整数。5n=2(-n)•10n 利用这个恒等式,我们可以很容易地计算出任意给定的5次方的前导N个2位数(最接近的整数) 这个代码示例是用C编写的,但在任何其他语言中都是一样的 示例输出

我想以完美的精度高效、优雅地计算5**x的前x个前导二进制数字

例如,5**20是101011011111000110101111000101011011010110001。前8个前导二进制数字是10101101

在我的用例中,x最多只有1-60。我不想创建一个表。使用64位整数的解决方案就可以了。我只是不想使用大整数。

5n=2(-n)•10n

利用这个恒等式,我们可以很容易地计算出任意给定的5次方的前导N个2位数(最接近的整数)

这个代码示例是用C编写的,但在任何其他语言中都是一样的

示例输出:

#包括
#包括
#包括
#包括
#定义静态断言(条件)((无效)sizeof(int[(条件)?1:-1]))
uint64功率5前导数字(双功率,uint8字节)
{
静态断言(DBL_MANT_DIG(DBL_MANT_DIG-ndigits);
}
编辑:现在将返回值限制为那些可以用
double
精确表示的值

无大整数乘法的5**x的前x位二进制数

高效优雅地以完美的精度计算5x?的前x位二进制数字

“以完美精度计算”省略了
pow()
。太多的实现将返回不完美的结果,FP math可能不会使用64位精度,即使使用
长双精度


形成一个包含64位整数部分
.ms
和64位小数部分
.ls
的整数。然后循环60次,乘以5,根据需要跳转2,以防止前导位变大

注:分数中有一些精度损失,
N>42
,但这不足以影响OP正在寻找的整数部分

#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>

typedef struct {
  uint64_t ms, ls;
} uint128;

// Simplifications possible here, leave for OP
uint128 times5(uint128 x) {
  uint128 y = x;
  for (int i=1; i<5; i++) {
    // y += x
    y.ms += x.ms;  
    y.ls += x.ls;
    if (y.ls < x.ls) y.ms++;
  }
  return y;
}

uint128 div2(uint128 x) { 
  x.ls = (x.ls >> 1) | (x.ms << 63);
  x.ms >>= 1;
  return x;
}

int main(void) {
  uint128 y = {.ms = 1};
  uint64_t pow2 = 2;
  for (unsigned x = 1; x <= 60; x++) {
    y = times5(y);
    while (y.ms >= pow2) {
      y = div2(y);
    }
    printf("%2u %16" PRIX64 ".%016" PRIX64 "\n", x, y.ms, y.ls);
    pow2 <<= 1;
  }
}
解决此任务的关键是:。形成一个算法(根据需要简单地是*5和/2),并编写一个类型和函数来完成每一小步



60的循环有效吗?也许没有。另一种方法会使用。对于大的
N
,当然是值得的,但是对于
N==60
,循环足够简单,可以快速旋转。

它是60个字节。一个表就是一种方法。如果你尝试使用一个太大而不能放入一个双精度或长精度的数字,这种方法会失败吗给人的印象是,问题是如何在不使用高精度整数的情况下,对任意大幂次的任意数字执行此操作。@templatetypedef如果需要超过64个二进制数字/位,则会失败,但它确实处理过大的数字,无法放入无符号的长整数中(请参见注释部分)“如果POW5太大,不能返回,则除以2直到它适合”。我可以用C++模板函数来扩展我的答案,它返回任意长度的<代码> STD::ButStuts。至于数字太大,不能适应双,我现在注意到我错了,所以我应该将结果限制在53位。(这也意味着比特集的概念比我想象的要复杂得多,尽管我相信我可以用一个双倍数组而不是一个。使用
exp2(-power)*pow(10,power)
而不是
pow(5,power)有什么意义
?注意:上面的代码开始生成N>42的近似分数结果。恰好这些近似分数结果没有生成整数结果。“完美”计算至少需要140位数学运算。
         whole part.fraction
 1                1.4000000000000000
 2                3.2000000000000000
 3                7.D000000000000000
 4                9.C400000000000000
...
57  14643E5AE44D12B.8F5FEE5AA432560D
58  32FA9BE33AC0AEC.E66FD3E29A7DD720
59  7F7285B812E1B50.401791B6823A99D0
60  9F4F2726179A224.501D762422C94044
    ^-------------^ This is the part OP is seeking.