Skip to content

Commit

Permalink
Clean up digit_count lookup table generation
Browse files Browse the repository at this point in the history
  • Loading branch information
soraros committed Oct 15, 2024
1 parent b5e78fe commit 8ed5402
Showing 1 changed file with 34 additions and 30 deletions.
64 changes: 34 additions & 30 deletions 2021/06/03/generate.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,35 @@
from functools import partial
import math

from math import floor, log, ceil
def log2(x):
return len(bin(x))-2
table = []
def mylog10(x):
return int(ceil(log(x)/log(10)))
table.append(0)
for j in range(1,33):
smallest = 2**(j-1)
largest = 2**(j) - 1
if(j < 31):
print("(1 << 32) - "+str(10**mylog10(smallest)) + " + ("+str(mylog10(smallest))+ " << 32), // ceil(log10("+str(smallest)+")) = "+str(mylog10(smallest)))
table.append((2**32 - 10**mylog10(smallest)) + (mylog10(smallest) <<32))
else:
print(" ("+str(mylog10(smallest))+ " << 32), // ceil(log10("+str(smallest)+")) = "+str(mylog10(smallest)))
table.append((mylog10(smallest) <<32))



print(table)
print(len(table))
def fast_digit_count(x):
return (x+table[log2(x)])//(2**32)#return (x+table[log2(x)]) >> 32
#for x in range(1100):
# print(x, fast_digit_count(x))

#print (mylog10(100))
print(fast_digit_count(1073741824))
print(mylog10(1073741824))
print(log2(1073741824))
def log2(n: int) -> int:
return int(math.log2(n | 1))

def log10(n: int) -> int:
return int(math.log10(n | 1))

def row(i: int, for_digit_count: bool = False) -> int:
d = log10(2**i)
# max(0, _) to avoid overflow
return ((d + for_digit_count) << 32) + max(0, ((1 << 32) - 10**(d + 1)))

log10_table = list(map(row, range(32)))

def log10_fast(n: int) -> int:
assert 0 <= n < 2**32, n
return (n + log10_table[log2(n)]) >> 32

digit_count_table = list(map(partial(row, for_digit_count=True), range(32)))

def digit_count(n: int) -> int:
assert 0 <= n < 2**32, n
return (n + digit_count_table[log2(n)]) >> 32

tests = [
0, 1, 2, 3, 9, 10, 99, 100, 999, 1000, 9999, 10000, 99999, 100000, 999999, 1000000, 9999999,
10000000, 99999999, 100000000, 999999999, 1000000000, (1 << 32) - 1
]

for i in tests:
log10_ref, log10_res = log10(i), log10_fast(i)
dc_ref, dc_res = digit_count(i), digit_count(i)
assert log10_ref == log10_res == dc_ref - 1 == dc_res - 1

0 comments on commit 8ed5402

Please sign in to comment.