How to resolve the algorithm Iterated digits squaring step by step in the Racket programming language
Published on 12 May 2024 09:40 PM
How to resolve the algorithm Iterated digits squaring step by step in the Racket programming language
Table of Contents
Problem Statement
If you add the square of the digits of a Natural number (an integer bigger than zero), you always end with either 1 or 89: An example in Python:
Or, for much less credit - (showing that your algorithm and/or language is slow): This problem derives from the Project Euler problem 92. For a quick algorithm for this task see the talk page
Let's start with the solution:
Step by Step solution about How to resolve the algorithm Iterated digits squaring step by step in the Racket programming language
Source code in the racket programming language
#lang racket
;; Tim-brown 2014-09-11
;; The basic definition.
;; It is possible to memoise this or use fixnum (native) arithmetic, but frankly iterating over a
;; hundred million, billion, trillion numbers will be slow. No matter how you do it.
(define (digit^2-sum n)
(let loop ((n n) (s 0))
(if (= 0 n) s (let-values ([(q r) (quotient/remainder n 10)]) (loop q (+ s (sqr r)))))))
(define (iterated-digit^2-sum n)
(match (digit^2-sum n) [0 0] [1 1] [89 89] [(app iterated-digit^2-sum rv) rv]))
;; Note that: ids(345) = ids(354) = ids(435) = ids(453) = ids(534) = ids(543) = 50 --> 89
;; One calculation does for 6 candidates.
;; The plan:
;; - get all the ordered combinations of digits including 0's which can be used both as digits and
;; "padding" digits in the most significant digits. (n.b. all-zeros is not in the range to be
;; tested and should be dropped)
;; - find the digit sets that have an IDS of 89
;; - find out how many combinations there are of these digits
;; output: a list of n-digits long lists containing all of the digit combinations.
;; a smart bunny would figure out the sums of the digits as they're generated but I'll plod
;; along step-by-step. a truly smart bunny would also count the combinations. that said, I
;; don't think I do much unnecessary computation here.
(define (all-digit-lists n-digits)
(define (inner remain acc least-digit)
(cond
[(zero? remain) (list (list))]
[(= least-digit 10) null]
[else
(for*/list
((ld+ (in-range least-digit 10))
(rgt (in-list (inner (sub1 remain) empty ld+))))
(append acc (cons ld+ rgt)))]))
(inner n-digits '() 0))
;; We calculate IDS differently since we're presented with a list of digits rather than a number
(define (digit-list-IDS c)
(define (digit-combo-IDS c)
(apply + (map sqr c)))
(iterated-digit^2-sum (digit-combo-IDS c)))
;; ! (factiorial) -- everyone's favourite combinatorial function! (that's just an exclamation mark)
;; there's one in (require math/number-theory) for any heavy lifting, but we're not or I could import
;; it from math/number-theory -- but this is about all I need. A lookup table is going to be faster
;; than a more general function.
(define (! n)
(case n [(0 1) 1] [(2) 2] [(3) 6] [(4) 24] [(5) 120] [(6) 720] [(7) 5040] [(8) 40320] [(9) 362880]
[else (* n (! (sub1 n)))] ; I expect this clause'll never be called
))
;; We need to count the permutations -- digits are in order so we can use the tail (cdr) function for
;; determining my various k's. See: https://en.wikipedia.org/wiki/Combination
(define (count-digit-list-permutations c #:length (l (length c)) #:length! (l! (! l)))
(let loop ((c c) (i 0) (prev -1 #;"never a digit") (p l!))
(match c
[(list) (/ p (! i))]
[(cons (== prev) d) (loop d (+ i 1) prev p)]
[(cons a d) (loop d 1 a (/ p (! i)))])))
;; Wrap it all up in a neat function
(define (count-89s-in-100... n)
(define n-digits (order-of-magnitude n))
(define combos (drop (all-digit-lists n-digits) 1)) ; don't want first one which is "all-zeros"
(for/sum ((c (in-list combos)) #:when (= 89 (digit-list-IDS c)))
(count-digit-list-permutations c #:length n-digits)))
(displayln "Testing permutations:")
(time (printf "1000000:\t~a~%" (count-89s-in-100... 1000000)))
(time (printf "100000000:\t~a~%" (count-89s-in-100... 100000000)))
(time (printf "1000000000:\t~a~%" (count-89s-in-100... 1000000000)))
(time (printf "1000000000000:\t~a~%" (count-89s-in-100... 1000000000000)))
(newline)
;; Do these last, since the 10^8 takes longer than my ADHD can cope with
(displayln "Testing one number at a time (somewhat slower):")
(time (printf "1000000:\t~a~%" (for/sum ((n (in-range 1 1000000))
#:when (= 89 (iterated-digit^2-sum n))) 1)))
(time (printf "100000000:\t~a~%" (for/sum ((n (in-range 1 100000000))
#:when (= 89 (iterated-digit^2-sum n))) 1)))
{module+ test
(require tests/eli-tester)
[test
(iterated-digit^2-sum 15) => 89
(iterated-digit^2-sum 7) => 1
(digit-combo-perms '()) => 1
(digit-combo-perms '(1 2 3)) => 6
(digit-combo-perms '(1 1 3)) => 3
(for/sum ((n (in-range 1 1000000)) #:when (= 89 (iterated-digit^2-sum n))) 1) => 856929
(all-digit-lists 1) => '((0) (1) (2) (3) (4) (5) (6) (7) (8) (9))
(length (all-digit-lists 2)) => 55
(length (all-digit-lists 3)) => 220
(count-89s-in-100... 1000000) => 856929]
}
You may also check:How to resolve the algorithm Abbreviations, easy step by step in the C++ programming language
You may also check:How to resolve the algorithm French Republican calendar step by step in the Kotlin programming language
You may also check:How to resolve the algorithm Environment variables step by step in the Modula-3 programming language
You may also check:How to resolve the algorithm Repeat step by step in the Stata programming language
You may also check:How to resolve the algorithm User input/Graphical step by step in the Go programming language