Created
July 11, 2017 18:57
-
-
Save urielieli/5842ba6f23cee2b829224d4b1b074375 to your computer and use it in GitHub Desktop.
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 string | |
from math import inf | |
class base: | |
"""manages metadata and conversions methods for unary and positional numeric systems""" | |
def __init__ (self, base = 10, | |
charset = string.digits + string.ascii_uppercase + string.ascii_lowercase, | |
radix_point = '.', | |
precision = 30): | |
""" | |
@ parameters | |
base : int, optional | |
used for conversions | |
limitations: | |
encoding : ∀ base, base ϵ 𝓝, base ϵ [1, ∞) | |
decoding : ∀ base, base ϵ 𝒞, base ϵ [-∞, 0), (0, ∞] | |
charset : string, optional | |
used to determine the value of every character | |
radix_point : string, optional | |
used to show and determine the radix point form | |
precision : int, optional | |
used to determine precision in conversion | |
""" | |
self.base = base | |
self.charset = charset | |
self.radix_point = radix_point | |
self.precision = precision | |
def encode (self, number): | |
""" | |
encodes a number in the base | |
@ parameters | |
number : numerical data-type | |
decimal number to be encoded in the base | |
the data-type must support: | |
__abs__, __floordiv__, __mod__, | |
__mul__, __gt__, __lt__, __int__ | |
@ returns | |
string | |
the decimal number encoded in the base | |
""" | |
sign, integer, fraction = '-' * (number < 0), int(abs(number) // 1), abs(number) % 1 | |
if self.base == 1: | |
return sign + ('1' * integer or self.charset[0]) + \ | |
(self.radix_point + \ | |
self.radix_point.join( | |
map('1'.__mul__, | |
map(int, str(fraction).rpartition(self.radix_point)[2]) | |
) | |
) | |
) if fraction else '' | |
if isinstance(self.base, complex): | |
real_integer, real_fraction = base((self.base ** 2).real).encode(number.real).split(self.radix_point) | |
imag_integer, imag_fraction = base((self.base ** 2).real).encode(number.imag).split(self.radix_point) | |
integer_part = ''.join(zip(imag_fraction, real_fraction)) | |
fraction_part = ''.join(zip(real_fraction, imag_fraction)) | |
return (integer_part or self.charset[0]) + (self.radix_point + fractional_part) if fractional_part else '' | |
integer_part = '' | |
while integer > 0: | |
integer_part = (self.charset[integer % self.base] if integer % self.base < len(self.charset) else '?') + integer_part | |
integer //= self.base | |
fractional_part = '' | |
while fraction % 1 > 0 and len(fractional_part) < self.precision: | |
fraction = fraction % 1 * self.base | |
fractional_part = fractional_part + (self.charset[int(fraction // 1)] if int(fraction // 1) < len(self.charset) else '?') | |
return sign + (integer_part or self.charset[0]) + (fractional_part and (self.radix_point + fractional_part) or '') | |
def decode (self, number): | |
""" | |
decodes a number in the base back to decimal | |
@ parameters | |
number : string | |
representing a number in the base to be converted to decimal | |
@ returns | |
float | |
the number converted to decimal | |
""" | |
sign = 2 * (len(number) == 0 or number[0] != '-') - 1 | |
integer_part, _, fractional_part = number.partition(self.radix_point) | |
integer_part = integer_part.lstrip('-') | |
if self.base == 1: | |
fraction, exponent = 0, 0.1 | |
for section in fractional_part.split(self.radix_point): | |
fraction += len(section) * exponent | |
exponent /= 10 | |
return sign * (len(integer_part) + fraction) | |
integer, exponent = 0, 1 | |
for digit in integer_part[::-1]: | |
integer += self.charset.index(digit) * exponent | |
exponent *= self.base | |
fraction, exponent = 0, 1 / self.base | |
for digit in fractional_part: | |
fraction += self.charset.index(digit) * exponent | |
exponent /= self.base | |
return sign * (integer + fraction) | |
def convert (self, base): | |
""" | |
provides a converter from the current base to the given base | |
@ parameters | |
base : base | |
the base to which the converter will convert | |
@ returns | |
lambda (numerical data-type) | |
a function converting a number from the base to the other base | |
""" | |
return lambda number: base.encode(self.decode(number)) | |
def __contains__ (self, number): | |
""" | |
provides indication whether the given number is valid in the | |
context of the current base | |
@ parameters | |
number : string | |
representing a number in the base | |
@ returns | |
bool | |
thruthy value if number is valid, otherwise falsy value | |
""" | |
if self.base == 1: | |
return all(digit in '1.' for digit in number) | |
if self.base == inf: | |
return True | |
return all(digit in self.charset[:self.base] or digit == '-' for digit in number) | |
def __eq__ (self, base): | |
""" | |
provides indication whether the base shares the same properties | |
with another base | |
@ parameters | |
base : base | |
the base tested for equality | |
@ returns | |
bool | |
thruthy value if bases shares the same properties, otherwise falsy value | |
""" | |
return (self.base, self.charset, self.precision) == (base.base, base.charset, base.precision) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment