Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scheme 从数学上讲,为什么一个数的指数乘以另一个数的SICP算法有效?_Scheme_Sicp_Exponentiation_Modular Arithmetic - Fatal编程技术网

Scheme 从数学上讲,为什么一个数的指数乘以另一个数的SICP算法有效?

Scheme 从数学上讲,为什么一个数的指数乘以另一个数的SICP算法有效?,scheme,sicp,exponentiation,modular-arithmetic,Scheme,Sicp,Exponentiation,Modular Arithmetic,给出了以下步骤: (define (expmod base exp m) (cond ((= exp 0) 1) ((even? exp) (remainder (square (expmod base (/ exp 2) m)) m)) (else (remainder (* base (expmod base (- exp 1) m))

给出了以下步骤:

    (define (expmod base exp m)
  (cond ((= exp 0) 1)
        ((even? exp)
         (remainder (square (expmod base (/ exp 2) m))
                    m))
        (else
         (remainder (* base (expmod base (- exp 1) m))
                    m))))
作者声称,它“计算一个数乘以另一个数的指数”。例如
(expmod 5 3 n)
应该返回(5^3)mod n

然而,从数学的角度来看,我就是看不出它是如何工作的。正如所强调的,它打算使用一个属性,即对于任何正整数a、b和n,(ab)mod n=[(a mod n)(b mod n)]mod n,但我看不出它实际上是如何使用它的。考虑<代码>(ExpMod 5 3 3)< /> >:

  • 首先,我们称之为
    (expmod 5 3)
    。从数学上来说,这意味着我们要求的是(5^3)mod 3
  • 由于第二个参数是奇数,我们计算
    (余数(*5(expmod 5(-3 1)3))3
    ,即
    (余数(*5(expmod 5 2 3))3
    。从数学上讲,这是[5*[(5^2)mod 3]]mod 3。由于此表达式中的首字母5没有附加mod 3,因此此表达式在(ab)mod n=[(a mod n)(b mod n)]mod n形式中是而不是,因此无法使用预期属性
  • 那么,既然它似乎没有使用预期的属性,为什么这个算法会工作呢?我忽略了模运算的什么性质

    (ab) mod n = [a (b mod n)] mod n
    
    这也是事实

    这里有一个关于
    a
    的归纳证明

    基本情况:当
    a=0
    (0b)mod n=0 mod n=[0(b mod n)]mod n

    ((a+1) b) mod n
    = (ab + b) mod n
    = (ab mod n) + (b mod n)
    = [a (b mod n)] mod n + (b mod n)             by induction hypothesis
    = [a (b mod n)] mod n + (b mod n) mod n
    = [a (b mod n) + (b mod n)] mod n
    = [(a + 1) (b mod n)] mod n
    
    感应情况:

    通过归纳假设,假设
    (ab)mod n=[a(b mod n)]mod n
    为真。我们需要证明,
    ((a+1)b)mod n=[(a+1)(b mod n)]mod n

    ((a+1) b) mod n
    = (ab + b) mod n
    = (ab mod n) + (b mod n)
    = [a (b mod n)] mod n + (b mod n)             by induction hypothesis
    = [a (b mod n)] mod n + (b mod n) mod n
    = [a (b mod n) + (b mod n)] mod n
    = [(a + 1) (b mod n)] mod n
    
    如所愿

    这就证明了

    (ab) mod n = [a (b mod n)] mod n
    

    事实上,你可以看到

    (ab) mod n = [(a mod n) (b mod n)] mod n
    
    是由此产生的结果。这里有一个证据:

    (ab) mod n 
    = [a (b mod n)] mod n            by what we just proved
    = [(b mod n) a] mod n
    = [(b mod n) (a mod n)] mod n    by what we just proved
    = [(a mod n) (b mod n)] mod n
    

    这是1.2.4中fast exp的定义,参考:

    (define (fast-expt b n)
      (cond ((= n 0) 1)
            ((even? n) (square (fast-expt b (/ n 2))))
            (else (* b (fast-expt b (- n 1))))))
    
    如果我们将其重命名为closer match expmod,它看起来如下所示:

    (define (expt base exp)
      (cond ((= exp 0) 1)
            ((even? exp)
             (square (expt base (/ exp 2))))
            (else
             (* base (expt base (- exp 1))))))
    
    要获得一个简单的
    expmod
    ,我们现在只需计算每个子句的剩余部分:

    (define (expmod base exp m)
      (cond ((= exp 0) 1)
            ((even? exp)
             (remainder (square (expt base (/ exp 2))) m))
            (else
             (remainder (* base (expt base (- exp 1))) m))
    
    到目前为止,我们还没有使用脚注
    (ab)mod m=((a mod m)(b mod m)mod m)
    。当然,这种情况的一个特例是
    (aa)mod m=((a mod m)(a mod m)mod m)
    ,它给出
    (余数(平方a)m)=(余数(平方m))m
    。我们可以将它与
    偶数
    子句一起使用,以便

             (remainder (square (expt base (/ exp 2))) m)
    
    变成:

             (remainder (square (remainder (expt base (/ exp 2)) m))
                        m)
    
    在这中间我们有一个指数的余数,所以这相当于:

             (remainder (square (expmod base (/ exp 2) m)) m)
    
             (remainder (* base (remainder E m)) m)
    
    使用新的
    偶数
    子句

    (define (expmod base exp m)
      (cond ((= exp 0) 1)
            ((even? exp)
             (remainder (square (expmod base (/ exp 2) m)) 
                        m))
            (else
             (remainder (* base (expt base (- exp 1))) m))
    
    为了简化odd子句,现在让我们使用
    E
    代替
    (expt base(-exp 1))

    通过使用
    mod
    的定义属性,我们可以说任何数字
    a

             a = (+ (* (quotient a m) m) (remainder a m))
    
    所以这也是事实:

             E = (+ (* (quotient E m) m) (remainder E m))
    
    将此替换为我们的
    odd
    条款:

             (remainder (* base E) m)
    
    给出:

             (remainder (* base (+ (* (quotient E m) m) (remainder E m))) m)
    
    我们可以忽略
    (*(商em)m)
    ,因为包含此项的任何项都可以被
    m
    整除,因此在执行外部
    余数时,计算结果将为
    0
    ,因此这相当于:

             (remainder (square (expmod base (/ exp 2) m)) m)
    
             (remainder (* base (remainder E m)) m)
    
    将E扩展到其原始值:

             (remainder (* base (remainder (expt base (- exp 1)) m)) m)
    

    再一次,在中间,我们有一个指数的剩余部分,这样就变成:

             (remainder (* base (expmod base (- exp 1) m)) m)
    
    我们的
    expmod
    现在是:

    (define (expmod base exp m)
      (cond ((= exp 0) 1)
            ((even? exp)
             (remainder (square (expmod base (/ exp 2) m)) 
                        m))
            (else
             (remainder (* base (expmod base (- exp 1) m))
                        m))))
    

    关于第2点,请注意,(a*(b mod n))mod n也等于(a*b)mod n.@molbdnilo奇怪,如果这样美好的事情是真的,我会期望它在前面和中间。我错过了吗?它是根据加法规则得出的。(大多数值得知道的事情在维基百科中根本没有提到。)@molbdnilo来自加法规则?如果它是琐碎的,我就不能这么容易地看到它。因此,最终,奇数分支不使用所讨论的属性?
    (余数(*base(余数em))m)
    的形式似乎是[a*(b mod m)]mod m。由于这是从
    (余数(*base E)m)
    中推导出来的,因此我得出的结论是否正确,即您提供了与Sorawe Porncharoenwase具有相同属性的证据?i、 e.(ab)mod n=[a(b mod n)]mod n?@J.Mini是的,我没有在奇数子句中使用它。当消除
    (*(商em)m)
    时,可能有一种方法可以使用它,但我不够聪明,看不到它,而且在任何情况下,它似乎有点做作。我没有仔细看索拉维的答案,正忙着写我自己的:-),也许我会说这个答案是建立在他的基础上的?我很惊讶这不是。你已经证明的版本比他们提供的版本更强大。当有一个更强大的版本不需要额外的概念时,他们为什么要给出一个具体的例子?此外,我很惊讶SICP的脚注中没有这一点。这让我怀疑我是否误读了它。是吗?嗯,维基百科并不包含所有内容,而且,
    [(a mod n)(b mod n)]mod n
    也没有什么问题。有人可能会说,SICP的错误在于他们没有准确地遵循方程式,而解决办法是使用
    (*(余数基数m)…)
    而不是
    (*基数…)
    。事实上,从性能的角度来看,最好使用
    (*(余数基数m)…)
    。例如,请参阅以提高球拍中的
    模块化expt
    的性能。