;;; Illustrate a curio about the first 40 (decimal) digits of π.
;;; Time-stamp: <2025-07-22 16:52:39>
#|
Output:
1588419
3.14159265358979323846264338327950288419
--------------------^20------------^35--
|#
;; Four magic numbers.
(defconstant n-groups 3
"The magic number of groups of digits of pi.")
(defconstant group-length 6
"The magic length of groups of digits of pi.")
(defconstant magic-prefix-length 2
"The length of the distance to the next occurrence.")
(defconstant fractional-part-start (+ (position #\. (prin1-to-string pi)) 1)
"The start of pi's fractional part in the string of its digits.")
#-clisp (error "We require Clisp so we can obtain enough digits for pi.")
(setf (ext:long-float-digits) 1000)
;;; All digits are decimal; digit sequences are strings.
;;; (In a perfect world, they would be of type `(vector (integer 0 9))'.)
(defun sum-digit-groups (digits &key (start fractional-part-start)
(count n-groups)
(length group-length))
"Sum COUNT LENGTH-digit groups from START in DIGITS.
Return (1) the sum as a string and (2) the position where the groups end."
(loop for i from 0 below count
for group-start = (+ start (* length i))
sum (parse-integer (subseq digits group-start (+ group-start length)))
into result
finally (return (values (prin1-to-string result)
(+ start (* count length))))))
(defun make-ruler (length &rest ps)
"Return \"---...---^pp-...---^pp-...\" of the given LENGTH.
The carets are at positions PS and 'pp' are the positions as numbers."
(loop with ruler = (make-string length :initial-element #\-)
for p in ps
do (setf (aref ruler p) #\^)
(replace ruler (prin1-to-string p) :start1 (+ p 1))
finally (return ruler)))
(defun main ()
"Demonstrate a curio about the digits of pi."
(let ((pi-digits (prin1-to-string pi)))
(multiple-value-bind (magic-sum group-end)
(sum-digit-groups pi-digits)
(let* ((magic-distance (parse-integer magic-sum
:end magic-prefix-length))
(magic-start (+ group-end magic-distance))
(magic-end (+ magic-start (- (length magic-sum)
magic-prefix-length)))
(ruler (make-ruler magic-end group-end magic-start)))
(format *trace-output*
"~v@A~%~A~%~A~%"
magic-end magic-sum
(subseq pi-digits 0 magic-end)
ruler)
(assert (string= magic-sum pi-digits
:start1 magic-prefix-length
:start2 magic-start :end2 magic-end))))))
;;; A poor programmer's unit test.
(assert (equal (multiple-value-list (sum-digit-groups "90102034" :start 1 :length 2))
'("6" 7)))
No comments:
Post a Comment