Skip to content

Instantly share code, notes, and snippets.

@yunruse
Last active May 22, 2021 14:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yunruse/04de73f71f27af9b1c91c115759a667d to your computer and use it in GitHub Desktop.
Save yunruse/04de73f71f27af9b1c91c115759a667d to your computer and use it in GitHub Desktop.
Math, in arbitrary bases! Even irrational ones!
import re
from math import log, ceil
DIGITS = '0123456789abcdefghijklmnopqrtstuvwxyz'
def to_number(
base,
string_or_digits,
decimal_digits=None,
assert_base=True,
):
'''
Turn a string into a number using this base.
If assert_base is True, verifies that digits are below the base.
'''
if isinstance(string_or_digits, str):
a = string_or_digits.lower()
if '.' in a:
a, b = a.split('.', 1)
else:
b = ''
digits = [DIGITS.index(c) for c in a[::-1]]
decimal_digits = [DIGITS.index(c) for c in b]
else:
digits = string_or_digits
decimal_digits = decimal_digits or []
if assert_base:
for d in digits[::-1] + decimal_digits:
if d >= abs(base):
raise ValueError(f'Cannot have digit {d} with base {base}.')
value = 0
for i, d in enumerate(digits):
value += d * base ** i
for i, d in enumerate(decimal_digits):
value += d * base ** (-i-1)
return value
def to_digits(base, number, delta=1e-10):
if number == 0:
return [0], []
pos_digits = ceil(log(number, base))
digits = []
i = pos_digits - 1
# this avoids trailing .9999 or equivalent
if number > 1:
number += delta
while number > delta:
digit = int(number // (base ** i))
digits.append(digit)
number -= digit * base ** i
i -= 1
return digits[:pos_digits][::-1], digits[pos_digits:]
def digits_to_string(digits, decimal_digits=None):
string = ''.join(DIGITS[i] for i in digits[::-1])
if decimal_digits:
string += '.' + ''.join(DIGITS[i] for i in decimal_digits)
return string
def to_string(base, number):
return digits_to_string(*to_digits(base, number))
if __name__ == '__main__':
def print_integers(N, base):
print(f'Integers in base {base}:')
for i in range(1, N+1):
d = to_string(base, i)
print(f'{i:>5} {d}')
phi = (1 + 5**0.5)/2
from math import pi
print_integers(20, phi)
print_integers(20, pi)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment