Skip to content

Commit

Permalink
math: add count-digits
Browse files Browse the repository at this point in the history
  • Loading branch information
yitzchak committed Jul 27, 2024
1 parent e9d7f31 commit af6e86d
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 1 deletion.
59 changes: 59 additions & 0 deletions code/math/count-digits.lisp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
(in-package #:quaviver.math)

(declaim (ftype (function ((integer 2 36) unsigned-byte) (unsigned-byte 22))
count-digits)
(inline count-digits))

(defvar *count-digits-table*
(compute-count-digits +min-base+ +max-base+
(quaviver:arithmetic-size #+quaviver/long-float
'long-float
#-quaviver/long-float
'double-float)))

(defun count-digits (base value)
(declare (optimize speed))
(cond ((zerop value)
1)
((eql base 2)
(integer-length value))
((= (logcount base) 1)
(values (ceiling (integer-length value)
(1- (integer-length base)))))
(t
(let* ((value-length (integer-length value))
(lower (ceiling-log-expt base 2 (1- value-length)))
(upper (ceiling-log-expt base 2 value-length)))
(if (or (= lower upper)
(< value
(let ((table (svref *count-digits-table* (- base +min-base+))))
(if (< lower (length table))
(svref table lower)
(cl:expt base lower)))))
lower
upper)))))

(define-compiler-macro count-digits (&whole whole base value)
(cond ((not (constantp base))
whole)
((eql base 2)
`(integer-length ,value))
((= (logcount base) 1)
`(values (ceiling (integer-length ,value)
,(1- (integer-length base)))))
(t
`(let ((value ,value))
(declare (optimize speed))
(if (zerop value)
1
(let* ((value-length (integer-length value))
(lower (ceiling-log-expt ,base 2 (1- value-length)))
(upper (ceiling-log-expt ,base 2 value-length)))
(if (or (= lower upper)
(< value
(let ((table ,(svref *count-digits-table* (- base +min-base+))))
(if (< lower (length table))
(svref table lower)
(cl:expt ,base lower)))))
lower
upper)))))))
10 changes: 10 additions & 0 deletions code/math/utility.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,13 @@
do (setf (getf tables arithmetic-size)
(max (getf tables arithmetic-size 0)
bound))))

(defun compute-count-digits (min-base max-base width)
(make-array (- max-base min-base -1)
:initial-contents
(loop for base from min-base upto max-base
for max-power = (floor (log (ash 1 (1- width)) base))
collect (make-array (1+ max-power)
:initial-contents
(loop for power from 0 upto max-power
collect (cl:expt base power))))))
3 changes: 2 additions & 1 deletion code/packages.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@
#:floor-multiply/64-128q128
#:floor-multiply/evenp/64-128q128
#:floor-log-expt
#:ceiling-log-expt))
#:ceiling-log-expt
#:count-digits))

#+sbcl
(pushnew :quaviver.math/smallnum *features*)
Expand Down
1 change: 1 addition & 0 deletions quaviver.asd
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
:serial t
:components ((:file "log-expt")
(:file "utility")
(:file "count-digits")
(:file "implementation")
(:file "expt")
(:file "round-to-odd")))
Expand Down

0 comments on commit af6e86d

Please sign in to comment.