Algorithm 有没有办法优化乘法循环?

Algorithm 有没有办法优化乘法循环?,algorithm,math,algebra,Algorithm,Math,Algebra,假设我必须重复将一个变量乘以一个常数并将结果乘以另一个常数的过程,n次才能得到我想要的结果 显而易见的解决方案是迭代n次,但是n越大,它就越耗时 代码示例: const N = 1000000; const A = 123; const B = 456; var c = 789; for (var i = 0; i < n; i++) { c = (c * a) % b; } log("Total: " + c); const N=1000000; 常数A=123; 常数

假设我必须重复将一个变量乘以一个常数并将结果乘以另一个常数的过程,n次才能得到我想要的结果

显而易见的解决方案是迭代n次,但是n越大,它就越耗时

代码示例:

const N = 1000000;

const A = 123;
const B = 456;

var c = 789;

for (var i = 0; i < n; i++)
{
    c = (c * a) % b;
}

log("Total: " + c);
const N=1000000;
常数A=123;
常数B=456;
var c=789;
对于(变量i=0;i

有没有代数方法来优化这个循环?

首先,请注意,
c*A^n
永远不是
B=456
的精确倍数,因为前者总是奇数,后者总是偶数。您可以通过考虑所涉及数字的素因子分解来概括这一点,并看到
c
A
的因子的重复不会给您提供包含
B
的所有因子的东西。这意味着,
c
将永远不会由于迭代乘法而变成
0

对于
c*a
mod
B=456
,只有456个可能的值;因此,如果您将循环迭代456次,您将看到至少重复了
c
的值。假设重复的
c
的第一个值是
c'
,当
i=i'
时。假设它第一次看到
c'
是在
i=i'
时。通过继续迭代乘法,我们希望再次看到
c'

  • 我们在
    i'
  • 我们在
    i'
  • 我们应该在
    i'+(i'-i'')看到它
  • 我们也应该在
    i'+k(i'-i'')看到它
一旦你检测到一个重复,你就知道这个模式将永远重复。因此,您可以计算需要多少个模式才能到达N,以及重复模式中对于
i=N-1
的偏移量,然后您就可以知道答案,而无需实际执行乘法

一个简单的例子:

A = 2
B = 3
C = 5

c[0] = 5
c[1] = 5 * 2 % 3 = 1
c[2] = 1 * 2 % 3 = 2
c[3] = 2 * 2 % 3 = 1 <= duplicate

i' = 3
i'' = 1
repeating pattern: 1, 2, 1

c[1+3k] = 1
c[2+3k] = 2
c[3+3k] = 1

10,000 = 1 + 3k for k = 3,333
c[10,000] = 1
c[10,001] = 2
c[10,002] = 1
A=2
B=3
C=5
c[0]=5
c[1]=5*2%3=1
c[2]=1*2%3=2

c[3]=2*2%3=1首先,请注意,
c*A^n
永远不是
B=456
的精确倍数,因为前者总是奇数,后者总是偶数。您可以通过考虑所涉及数字的素因子分解来概括这一点,并看到
c
A
的因子的重复不会给您提供包含
B
的所有因子的东西。这意味着,
c
将永远不会由于迭代乘法而变成
0

对于
c*a
mod
B=456
,只有456个可能的值;因此,如果您将循环迭代456次,您将看到至少重复了
c
的值。假设重复的
c
的第一个值是
c'
,当
i=i'
时。假设它第一次看到
c'
是在
i=i'
时。通过继续迭代乘法,我们希望再次看到
c'

  • 我们在
    i'
  • 我们在
    i'
  • 我们应该在
    i'+(i'-i'')看到它
  • 我们也应该在
    i'+k(i'-i'')看到它
一旦你检测到一个重复,你就知道这个模式将永远重复。因此,您可以计算需要多少个模式才能到达N,以及重复模式中对于
i=N-1
的偏移量,然后您就可以知道答案,而无需实际执行乘法

一个简单的例子:

A = 2
B = 3
C = 5

c[0] = 5
c[1] = 5 * 2 % 3 = 1
c[2] = 1 * 2 % 3 = 2
c[3] = 2 * 2 % 3 = 1 <= duplicate

i' = 3
i'' = 1
repeating pattern: 1, 2, 1

c[1+3k] = 1
c[2+3k] = 2
c[3+3k] = 1

10,000 = 1 + 3k for k = 3,333
c[10,000] = 1
c[10,001] = 2
c[10,002] = 1
A=2
B=3
C=5
c[0]=5
c[1]=5*2%3=1
c[2]=1*2%3=2

c[3]=2*2%3=1
%
有两个有用的属性:

1)
(x%b)%b=x%b

2)
(c*a)%b=((c%b)*(a%b))%b

这意味着,例如

(((c*a)%b)*a) % b = ((((c*a)%b)%b) * (a%b)) % b
                   = (((c*a) % b) * (a%b)) % b
                   = (c*a*a) % b
                   = (c*a^2) % b
因此,在您的情况下,您计算的最终
c
相当于

(c*a^n)%b
这可以使用以下方法有效地计算

为了说明这种等价性:

def f(a,b,c,n):
    for i in range(n):
        c  = (c*a)%b
    return c

def g(a,b,c,n):
    return (c*pow(a,n,b)) % b

a = 123
b = 456
c = 789
n = 10**6

print(f(a,b,c,n),g(a,b,c,n)) #prints 261, 261

%
有两个有用的属性:

1)
(x%b)%b=x%b

2)
(c*a)%b=((c%b)*(a%b))%b

这意味着,例如

(((c*a)%b)*a) % b = ((((c*a)%b)%b) * (a%b)) % b
                   = (((c*a) % b) * (a%b)) % b
                   = (c*a*a) % b
                   = (c*a^2) % b
因此,在您的情况下,您计算的最终
c
相当于

(c*a^n)%b
这可以使用以下方法有效地计算

为了说明这种等价性:

def f(a,b,c,n):
    for i in range(n):
        c  = (c*a)%b
    return c

def g(a,b,c,n):
    return (c*pow(a,n,b)) % b

a = 123
b = 456
c = 789
n = 10**6

print(f(a,b,c,n),g(a,b,c,n)) #prints 261, 261

有迭代乘法的数学抽象吗?然后,
A
B
之间存在特殊关系:如果
A%B==0
…您可以预先计算或缓存
c=0的值。。b-1
并将其存储在
查找表中
。在循环中,
c
总是被模运算截断到这个范围。是的,c是周期性的,最大周期长度是b。@PaulHankin的可能重复。我最初倾向于同意你的观点,这是重复的,但当我看到两个高代表性用户给出的答案似乎是基于这样的假设,即这不仅仅是简单的变相的模幂运算我认为等价性不是很明显。迭代乘法有数学抽象吗?然后,
A
B
之间存在特殊关系:如果
A%B==0
…您可以预先计算或缓存
c=0的值。。b-1
并将其存储在
查找表中
。在循环中,
c
总是被模运算截断到这个范围。是的,c是周期性的,最大周期长度是b。@PaulHankin的可能重复。我最初倾向于同意你的观点,这是重复的,但当我看到两个高代表性用户给出的答案似乎是基于这样的假设,即这不仅仅是简单的变相的模幂运算我认为等价性不是很明显。