我正在尝试实现费马的分解(算法C 计算机编程艺术,第2卷)。不幸的是,在我的版本(ISBN 81-7758-335-2)中,此算法打印不正确。下面因子内循环应该是什么条件?我正在运行循环,直到y< = n [作为限制传递]。
(if (< limit y) 0 (factor-inner x (+ y 2) (- r y) limit))
无论如何都要完全避免这种情况,因为它会使循环的速度加倍?
(define (factor n)
(let ((square-root (inexact->exact (floor (sqrt n)))))
(factor-inner (+ (* 2 square-root) 1)
1
(- (* square-root square-root) n)
n)))
(define (factor-inner x y r limit)
(if (= r 0)
(/ (- x y) 2)
(begin
(display x) (display " ") (display y) (display " ") (display r) (newline)
;;(sleep-current-thread 1)
(if (< r 0)
(factor-inner (+ x 2) y (+ r x) limit)
(if (< limit y)
0
(factor-inner x (+ y 2) (- r y) limit))))))
答案 0 :(得分:1)
通过算法C 查看,看起来问题在于递归步骤,它会在r < 0
时有效地跳过步骤C4,因为x
没有递增而r
1}}仅递减y
。
使用1998年版Vol。中的a
,b
和r
的符号。 2(ISBN 0-201-89684-2),Scheme版本如下:
(define (factor n)
(let ((x (inexact->exact (floor (sqrt n)))))
(factor-inner (+ (* x 2) 1)
1
(- (* x x) n))))
(define (factor-inner a b r)
(cond ((= r 0) (/ (- a b) 2))
((< 0 r) (factor-inner a (+ b 2) (- r b)))
(else (factor-inner (+ a 2) (+ b 2) (- r (- a b))))))
编辑添加:基本上,我们正在做一个反复检查是否
的技巧r <- ((a - b) / 2)*((a + b - 2)/2) - N
为0,我们只是通过跟踪r
或a
增加时b
的变化情况来实现。如果我们要在上面b
的表达式中将b+2
设置为r
,则相当于将r
的旧值减少b
,这就是为什么两者都在算法的步骤C4中并行完成。我鼓励你扩展上面的代数表达式并说服自己这是真的。
只要r > 0
,您希望继续减少它以找到b
的正确值,因此您不断重复步骤C4。但是,如果您超调,r < 0
,则需要增加它。您可以通过增加a
来实现此目的,因为将a
增加2相当于将r
的旧值减少a
,如步骤C3所示。您将始终拥有a > b
,因此在步骤C3中r
增加a
会自动使r
再次为正,因此您只需直接进入步骤C4。
证明a > b
也很容易。我们从明显大于a
的{{1}}开始,如果我们将b
增加到b
,我们就会
b = a - 2
这意味着N = (a - (a - 2))/2 * ((a + (a - 2) - 2)/2 = 1 * (a - 2)
是素数,因为它具有的最小因子小于N
是1,并且算法已经终止。
答案 1 :(得分:1)
(< limit y)
检查不是必需的,因为在最坏的情况下,算法最终会找到这个解决方案:
x = N + 2
y = N
然后返回1.