How to find amicable pairs in scheme? -
i new in scheme. how find "amicable pais"?
(define (sumcd n) (define s 1 ) (set! m (quotient n 2)) (while (<= m) (if (=(modulo n i) 0) (set! s (+ s i))) (set! (+ 1)) ) )
and in main program want check (if (m=sumcd n) , (n=sumcd m)) m , n amicable pair. how can this?
excessive use of set!
indicates imperative style of programming, discouraged in scheme. here's racket-specific implementation of sum-of-divisors
not use set!
@ all.
(define (sum-of-divisors n) (define-values (q r) (integer-sqrt/remainder n)) (for/fold ((sum (if (and (zero? r) (> q 1)) (add1 q) 1))) ((i (in-range 2 q)) #:when (zero? (modulo n i))) (+ sum (quotient n i))))
equivalent version in standard r6rs/r7rs scheme, if you're not using racket:
(define (sum-of-divisors n) (define-values (q r) (exact-integer-sqrt n)) (let loop ((sum (if (and (zero? r) (> q 1)) (+ q 1) 1)) (i 2)) (cond ((>= q) sum) ((zero? (modulo n i)) (loop (+ sum (quotient n i)) (+ 1))) (else (loop sum (+ 1))))))
note not equivalent set!
-based version have. code create inner function, loop
, gets tail-called new arguments each time.
now, can define amicable?
, perfect?
accordingly:
(define (amicable? n) (define sum (sum-of-divisors n)) (and (not (= n sum)) (= n (sum-of-divisors sum)))) (define (perfect? n) (= n (sum-of-divisors n)))
if want test 2 numbers see if amicable pair, can this:
(define (amicable-pair? b) (and (not (= b)) (= (sum-of-divisors b)) (= b (sum-of-divisors a))))
update op's new question how use find amicable pairs between m
, n
. first, let's define variant of amicable?
returns number's amicable "peer":
(define (amicable-peer n) (define sum (sum-of-divisors n)) (and (not (= n sum)) (= n (sum-of-divisors sum)) sum))
if you're using racket, use this:
(define (amicable-pairs-between m n) (for*/list ((i (in-range m (add1 n))) (peer (in-value (amicable-peer i))) #:when (and peer (<= m peer n) (< peer))) (cons peer)))
if you're not using racket, use this:
(define (amicable-pairs-between m n) (let loop ((result '()) (i n)) (if (< m) result (let ((peer (amicable-peer i))) (if (and peer (<= m peer n) (< peer)) (loop (cons (cons peer) result) (- 1)) (loop result (- 1)))))))
the way works, because lists built right-to-left, i've decided count downward n
through m
, keeping numbers have amicable peer, , peer within range. (< peer)
check ensure amicable pair appears once in results.
example:
> (amicable-pairs-between 0 10000) ((220 . 284) (1184 . 1210) (2620 . 2924) (5020 . 5564) (6232 . 6368))
more op updates (wherein asked difference between recursive version , accumulative version is). version of amicable-pairs-between
wrote above accumulative. recursive version this:
(define (amicable-pairs-between m n) (let recur ((i m)) (if (> n) '() (let ((peer (amicable-peer i))) (if (and peer (<= m peer n) (< peer)) (cons (cons peer) (recur (+ 1))) (recur (+ 1)))))))
note there no result
accumulator time. however, it's not tail-recursive more.
Comments
Post a Comment