2025-07-22

[EN] A Curio about the Digits of Pi

;;;; pi-digits.cl -*- mode: lisp; -*-
;;; 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

[EN] A Curio about the Digits of Pi

;;;; pi-digits.cl -*- mode: lisp; -*- ;;; Illustrate a curio about the first 40 (decimal) digits of π. ;;; Time-stamp: <2025-07-22 16:52...