【问题标题】:Calculate and Store Power of very large Number计算和存储非常大数的幂
【发布时间】:2015-05-18 06:46:41
【问题描述】:

我发现pow(2,i) 其中i 的范围是:0<=i<=100000. 除了i 有 MOD=1000000007

powers[100000];
powers[0]=1;
for (i = 1; i <=100000; ++i)
{
  powers[i]=(powers[i-1]*2)%MOD;
}

对于i=100000,功率值不会大于MOD吗?

如何正确储存电源?

我觉得这个手术不可行。 我猜我得到的正确值高达i=70 max。

我必须找到 sum+= ar[i]*power(2,i) 并最后打印 sum%1000000007 其中 ar[i] 是一个附加数组,其中包含一些高达 10^5 的大数字

【问题讨论】:

  • 显示的代码有一个明显的问题,那就是您忘记了大小为 X 的数组的索引从零 t0 X 减一开始,所以powers 数组的最高索引是 99999
  • 你可能想要一个bignum 库,比如GMPlib
  • Calculating pow(a,b) mod n 的可能副本
  • 确定什么正确意味着我们需要更多上下文。铁。如果唯一的任务是存储数字,你甚至不需要数组。
  • 我只是做了一些测试;即使对于i=99999,这段代码对我来说似乎也能很好地工作。每次迭代中的模运算确保您不会得到任何溢出。您所说的“得到正确的值直到i=70”是什么意思?

标签: c++ algorithm modular-arithmetic


【解决方案1】:

只要您的模值小于数据类型容量的一半,就永远不会超过。那是因为您将 0..1000000006 范围内的前一个值加倍,然后重新取模,使其回到同一范围。

但是,我不能保证更高的值不会给您带来麻烦,考虑到简单的替代方案,它比我准备投资的更多的数学分析。您可以花费大量时间分析、检查和调试,但最好一开始就不要让问题发生。

替代方案?我倾向于使用预生成方法(让程序预先完成繁琐的工作,将预生成的值插入到数组中,轻松快速地从您的 real 程序访问)。

通过这种方法,您可以使用经过充分测试且已知可处理大量价值的工具。由于这些数据不会改变,所以每次程序启动时计算它是没有用的。

如果您想要一种简单(且高效)的方式来做到这一点,下面的 bash 脚本与 bcawk 可以做到这一点:

#!/usr/bin/bash

bc >nums.txt <<EOF
    i = 1;
    for (x = 0;x <= 10000; x++) {
        i % 1000000007;
        i = i * 2;
    }
EOF

awk 'BEGIN { printf "static int array[] = {" }
           { if (NR % 5 == 1) printf "\n    ";
             printf "%s, ",$0;
             next
           }
     END   { print "\n};" }' nums.txt

bc 部分是问题的“肉”,它创建了 2 的大幂,并以您提供的数字为模输出它们。 awk 部分只是将它们格式化为 C 样式的数组元素,每行五个。

只需将其输出并将其放入您的代码中,瞧,您就拥有了一个可用于快速查找的编译时间消耗数组。

在我的盒子上只需要一秒钟半的时间来生成数组,然后你永远需要再做一次。您也不必担心模数的变幻莫测:-)

static int array[] = {
    1,2,4,8,16,
    32,64,128,256,512,
    1024,2048,4096,8192,16384,
    32768,65536,131072,262144,524288,
    1048576,2097152,4194304,8388608,16777216,
    33554432,67108864,134217728,268435456,536870912,
    73741817,147483634,294967268,589934536,179869065,
    359738130,719476260,438952513,877905026,755810045,
    511620083,23240159,46480318,92960636,185921272,
    371842544,743685088,487370169,974740338,949480669,
    898961331,797922655,595845303,191690599,383381198,
    766762396,533524785,67049563,134099126,268198252,
    536396504,72793001,145586002,291172004,582344008,
    164688009,329376018,658752036,317504065,635008130,
    270016253,540032506,80065005,160130010,320260020,
    640520040,281040073,562080146,124160285,248320570,
    :
    861508356,723016705,446033403,892066806,784133605,
    568267203,136534399,273068798,546137596,92275185,
    184550370,369100740,738201480,476402953,952805906,
    905611805,
};

【讨论】:

  • 但不是(a*b)%m == ((a%m) * (b%m)) % m吗?我从全模计算以及 bignum 和模块(也使用 bc 完成)中得到相同的结果。
  • @MOehm,您的问题是中间值在字长处自动换行(以 2 的幂为模)。假设您的int 范围是0..255,并且您想要取模107。最多 64,值 mod 107 是值:1,2,4,8,16,32,64。之后,模开始但具有正确的值:128%107 = 21。但是下一个 2 的幂是 256。因为你有一个 8 位的 int,所以当你将 1280 % 107 = 0 加倍时,它会归零,而你 想要 是 @987654339 @。也许我的第一段没有明确我想要表达的意思,所以我修复了它。
  • @paxdiablo 是的,但如果您使用的是mod 后的值21,那么将其加倍将为您提供21 * 2 mod 107 = 42,这正是您想要的值并避免任何溢出.
  • 我不相信。当用模运算计算 2^8 时,我必须从 (2^7) mod 107 开始工作,当然,不是从 128 开始。所以我得到 2*21,即 42,即 (2^8) mod 107 的值. 在整个过程中使用具有相同模值的模运算的想法 id。
  • 其实,这似乎是对的。可能需要更新答案:-)
【解决方案2】:

如果您注意到您的模数可以存储在 int 中。 MOD=1000000007(十进制)相当于0b00111011100110101100101000000111,可以32位存储。

 - i      pow(2,i)        bit representation 
 - 0            1         0b00000000000000000000000000000001
 - 1            2         0b00000000000000000000000000000010 
 - 2            4         0b00000000000000000000000000000100 
 - 3            8         0b00000000000000000000000000001000
 - ...
 - 29   536870912         0b00100000000000000000000000000000

当 pow(2,i) 大于您的 MOD=1000000007 时,棘手的部分开始了,但如果您知道当前 pow(2,i) 将大于您的 MOD,您实际上可以看到 MOD 之后位的样子

 - i      pow(2,i)  pow(2,i)%MOD      bit representation
 - 30   1073741824  73741817    0b000100011001010011000000000000
 - 31   2147483648  147483634   0b001000110010100110000000000000
 - 32   4294967296  294967268   0b010001100101001100000000000000
 - 33   8589934592  589934536   0b100011001010011000000000000000

所以如果你有 pow(2,i-1)%MOD 你可以在 pow(2,i-1)%MOD 上做 *2 直到你下一个 pow(2,i) 将大于 MOD .

在 i=34 的示例中,您将使用 (589934536*2) MOD 1000000007 而不是 (8589934592*2) MOD 1000000007,因为 8589934592 不能存储在 int 中。

另外,您可以尝试位运算而不是 pow(2,i) 的乘法。 与2乘法相同的位运算是位shift left

【讨论】:

  • 我有两个 find sum+= ar[i]*power(2,i) 最后打印 sum%1000000007 其中 ar[i] 是一个附加数组,其中包含一些高达 10^5 的大数字。如果我从你告诉的方法返回 pow%MOD,我的总和不会不正确吗?
  • 编辑您的问题,以便每个人都可以回答。明确你想要完成的任务。
猜你喜欢
  • 2020-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-11
  • 2011-10-08
  • 1970-01-01
  • 2011-05-05
相关资源
最近更新 更多