faster factor, (factor 1) = () (issue #751 cont.)

no need to go up to sqrt(n), Instead track i^2 and quit when that gets
larger than the (remaining) n (i.e., not the original n)
This commit is contained in:
Roger Crew 2021-06-27 03:58:58 -07:00
parent 41aa1a918e
commit b89bd9f889
2 changed files with 20 additions and 25 deletions

View file

@ -71,7 +71,7 @@
(test #t (perfect? 496))
(test #t (perfect? 8128))
(test '(1) (factor 1))
(test '() (factor 1))
(test '(2) (factor 2))
(test '(3) (factor 3))
(test '(2 2) (factor 4))
@ -86,6 +86,7 @@
(test '(2 3 3) (factor 18))
(test '(2 2 2 3 3) (factor 72))
(test '(3 3 3 5 7) (factor 945))
(test-error (factor 0))
(test 975 (aliquot 945))

View file

@ -192,30 +192,24 @@
;;> Returns the factorization of \var{n} as a monotonically
;;> increasing list of primes.
(define (factor n)
(when (zero? n)
(error "cannot factor 0"))
(factor-twos
n
(lambda (b n)
(let lp ((i 3) (ii 9) (n (abs n))
(res (append (make-list b 2)
(if (negative? n) (list -1) '()))))
(cond
((negative? n)
(cons -1 (factor (- n))))
((<= n 2)
(list n))
(else
(let lp ((n n)
(res (list)))
(cond
((even? n)
(lp (quotient n 2) (cons 2 res)))
((= n 1)
(reverse res))
(else
(let lp ((i 3) (n n) (limit (exact (ceiling (sqrt n)))) (res res))
(cond
((= n 1)
(reverse res))
((> i limit)
(reverse (cons n res)))
((> ii n)
(reverse (if (= n 1) res (cons n res))))
((zero? (remainder n i))
(lp i (quotient n i) limit (cons i res)))
(lp i ii (quotient n i) (cons i res)))
(else
(lp (+ i 2) n limit res))))))))))
(lp (+ i 2)
(+ ii (* (+ i 1) 4))
n
res)))))))
;;> Returns the Euler totient function, the number of positive
;;> integers less than \var{n} that are relatively prime to \var{n}.