简体   繁体   English

计算和存储超大功率

[英]Calculate and Store Power of very large Number

I am finding pow(2,i) where i can range: 0<=i<=100000. 我正在寻找pow(2,i)i可以在范围内: 0<=i<=100000. Apart i have MOD=1000000007 除了i有MOD = 1000000007

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

for i=100000 won't power value become greater than MOD ? 对于i=100000功率值不会大于MOD吗?

How do I store the power correctly? 如何正确储存电源?

The operation doesn't look feasible to me. 该操作对我来说似乎不可行。 I am getting correct value up to i=70 max I guess. 我猜到我得到的正确值最大为i=70

I have to find sum+= ar[i]*power(2,i) and finally print sum%1000000007 where ar[i] is an additional array with some big numbers up to 10^5 我必须找到sum + = ar [i] * power(2,i)并最终打印sum%1000000007,其中ar [i]是一个附加数组,具有一些大数,最大为10 ^ 5

As long as your modulus value is less than half the capacity of your data type, it will never be exceeded. 只要您的模数值小于数据类型容量的一半,就永远不会超过它。 That's because you take the previous value in the range 0..1000000006 , double it, then re-modulo it bringing it back to that same range. 这是因为您将先前的值取在0..1000000006范围内,将其加倍,然后重新对其进行模0..1000000006 ,使其回到相同的范围。

However, I can't guarantee that higher values won't cause you troubles, it's more mathematical analysis than I'm prepared to invest given the simple alternative. 但是,我不能保证更高的价值不会给您带来麻烦,它是一种数学分析方法,比我为简单选择而准备进行的投资要多。 You could spend a lot of time analysing, checking and debugging, but it's probably better just to not allow the problem to occur in the first place. 可能需要花费大量时间进行分析,检查和调试,但最好不要首先发生问题。

The alternative? 替代方案? I'd tend to use the pre-generation method (having a program do the gruntwork up front, inserting the pre-generated values into an array easily and speedily accessible from your real program). 我倾向于使用预生成方法(让程序预先做一些繁琐的工作,将预生成的值轻松方便地从实际程序中插入到数组中)。

With this method, you can use tools that are well tested and known to work with massive values. 通过这种方法,您可以使用经过充分测试并已知具有巨大价值的工具。 Since this data is not going to change, it's useless calculating it every time your program starts. 由于此数据不会更改,因此每次程序启动时都无法对其进行计算。

If you want an easy (and efficient) way to do this, the following bash script in conjunction with bc and awk can do this: 如果您想要一种简单(有效)的方法来执行此操作,则以下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

The bc part is the "meat" of the matter, it creates the large powers of two and outputs them modulo the number you provided. bc部分是问题的“肉”,它会产生2的大幂,并以您提供的数字为模输出它们。 The awk part is simply to format them in C-style array elements, five per line. awk部分只是将它们格式化为C样式的数组元素,每行五个。

Just take the output of that and put it into your code and, voila, there you have it, a compile-time-expensed array that you can use for fast lookup. 只需将其输出并将其放入代码中,瞧,那里就有一个可在编译时扩展的数组,可用于快速查找。

It takes only a second and a half on my box to generate the array and then you never need to do it again. 只需一秒钟,在我的箱子半来生成数组,然后你永远需要再次做到这一点。 You also won't have to concern yourself with the vagaries of modulo math :-) 您也不必担心模数学的多变:-)

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,
};

If you notice that your modulo can be stored in int. 如果您注意到模数可以存储在int中。 MOD=1000000007(decimal) is equivalent of 0b00111011100110101100101000000111 and can be stored in 32 bits. 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

Tricky part starts when pow(2,i) is grater than your MOD=1000000007, but if you know that current pow(2,i) will be greater than your MOD, you can actually see how bits look like after MOD 当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

So if you have pow(2,i-1)%MOD you can do *2 actually on pow(2,i-1)%MOD till you're next pow(2,i) will be greater than MOD. 因此,如果您具有pow(2,i-1)%MOD,则可以对pow(2,i-1)%MOD进行* 2,直到下一个pow(2,i)大于MOD。

In example for i=34 you will use (589934536*2) MOD 1000000007 instead of (8589934592*2) MOD 1000000007, because 8589934592 can't be stored in int. 在i = 34的示例中,您将使用(589934536 * 2)MOD 1000000007而不是(8589934592 * 2)MOD 1000000007,因为8589934592无法存储在int中。

Additional you can try bit operations instead of multiplication for pow(2,i). 另外,您可以尝试位操作而不是pow(2,i)的乘法。 Bit operation same as multiplication for 2 is bit shift left . 与2乘法相同的位运算是左移

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM