Last active
May 22, 2021 14:44
-
-
Save yunruse/04de73f71f27af9b1c91c115759a667d to your computer and use it in GitHub Desktop.
Math, in arbitrary bases! Even irrational ones!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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