mirror of
https://github.com/fschmnn/duodecimal.git
synced 2024-06-19 23:29:31 +00:00
2019.03.09 - more magicmethods
This commit is contained in:
parent
e56c275376
commit
4957c34e45
148
duodecimal.py
148
duodecimal.py
|
@ -13,29 +13,42 @@ class BaseConverter:
|
||||||
|
|
||||||
http://www.dozenal.org/drupal/sites_bck/default/files/DSA-ConversionRules_0.pdf
|
http://www.dozenal.org/drupal/sites_bck/default/files/DSA-ConversionRules_0.pdf
|
||||||
'''
|
'''
|
||||||
|
bases = {
|
||||||
|
2 : '01',
|
||||||
|
8 : '01234567',
|
||||||
|
10 : '0123456789',
|
||||||
|
12 : '0123456789XE',
|
||||||
|
16 : '0123456789ABCDEF'
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(self,number,digits):
|
def __init__(self,number,digits):
|
||||||
''' determine type of input and convert to decimal/duodecimal '''
|
''' determine type of input and convert to decimal/duodecimal '''
|
||||||
|
|
||||||
BaseConverter.digits = digits
|
self.digits = digits
|
||||||
BaseConverter.base = len(digits)
|
self.base = len(digits)
|
||||||
BaseConverter.to_digits = {k: v for k,v in enumerate(digits)}
|
|
||||||
BaseConverter.from_digits = {v: k for k,v in enumerate(digits)}
|
|
||||||
|
|
||||||
if type(number) == int or type(number) == float:
|
if type(number) == int or type(number) == float:
|
||||||
self.value = number
|
self.value = number
|
||||||
self.string = BaseConverter.from_dec(number,BaseConverter.base)
|
self.string = BaseConverter.from_dec(number,digits)
|
||||||
|
|
||||||
elif type(number) == str:
|
elif type(number) == str:
|
||||||
self.value = BaseConverter.to_dec(number,BaseConverter.base)
|
self.value = BaseConverter.to_dec(number,digits)
|
||||||
self.string = number
|
self.string = number
|
||||||
|
elif isinstance(number,BaseConverter):
|
||||||
|
self.value = number.value
|
||||||
|
self.string = BaseConverter.from_dec(number,digits)
|
||||||
else:
|
else:
|
||||||
raise TypeError('input type must be str or float/int')
|
raise TypeError('input type must be str or float/int')
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_dec(number,base):
|
def from_dec(number,digits=None,base=None):
|
||||||
''' convert decimal float/int to duodecimal string '''
|
''' convert decimal float/int to duodecimal string '''
|
||||||
|
|
||||||
|
if digits:
|
||||||
|
base = len(digits)
|
||||||
|
to_digits = {k: v for k,v in enumerate(digits)}
|
||||||
|
elif base:
|
||||||
|
to_digits = {k: v for k,v in enumerate(BaseConverter.bases[base])}
|
||||||
|
|
||||||
# handle negative numbers
|
# handle negative numbers
|
||||||
if number <0:
|
if number <0:
|
||||||
number = abs(number)
|
number = abs(number)
|
||||||
|
@ -49,7 +62,7 @@ class BaseConverter:
|
||||||
while quotient != 0:
|
while quotient != 0:
|
||||||
quotient, remainder = divmod(quotient,base)
|
quotient, remainder = divmod(quotient,base)
|
||||||
out.insert(0,remainder)
|
out.insert(0,remainder)
|
||||||
integer = ''.join([BaseConverter.to_digits[dig] for dig in out])
|
integer = ''.join([to_digits[dig] for dig in out])
|
||||||
|
|
||||||
if fractional:
|
if fractional:
|
||||||
out = []
|
out = []
|
||||||
|
@ -59,16 +72,22 @@ class BaseConverter:
|
||||||
out.append(quotient)
|
out.append(quotient)
|
||||||
if remainder > 0.5:
|
if remainder > 0.5:
|
||||||
out.append(1)
|
out.append(1)
|
||||||
decimal = '.' + ''.join([BaseConverter.to_digits[dig] for dig in out])
|
decimal = '.' + ''.join([to_digits[dig] for dig in out])
|
||||||
else:
|
else:
|
||||||
decimal = ''
|
decimal = ''
|
||||||
|
|
||||||
return sign + integer + decimal.rstrip('0')
|
return sign + integer + decimal.rstrip('0')
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def to_dec(string,base):
|
def to_dec(string,digits=None,base=None):
|
||||||
''' convert string to decimal float/int '''
|
''' convert string to decimal float/int '''
|
||||||
|
|
||||||
|
if digits:
|
||||||
|
base = len(digits)
|
||||||
|
from_digits = {v: k for k,v in enumerate(digits)}
|
||||||
|
elif base:
|
||||||
|
from_digits = {v: k for k,v in enumerate(BaseConverter.bases[base])}
|
||||||
|
|
||||||
# handle negative numbers
|
# handle negative numbers
|
||||||
if string.startswith('-'):
|
if string.startswith('-'):
|
||||||
string = string[1:]
|
string = string[1:]
|
||||||
|
@ -76,8 +95,8 @@ class BaseConverter:
|
||||||
else:
|
else:
|
||||||
sign = 1
|
sign = 1
|
||||||
|
|
||||||
if set(string) > set(BaseConverter.digits):
|
if set(string) > set(digits):
|
||||||
invalid = set(string) - set(BaseConverter.digits)
|
invalid = set(string) - set(digits)
|
||||||
raise ValueError('invalid character'.format(invalid))
|
raise ValueError('invalid character'.format(invalid))
|
||||||
|
|
||||||
if '.' in string:
|
if '.' in string:
|
||||||
|
@ -87,85 +106,122 @@ class BaseConverter:
|
||||||
|
|
||||||
out = 0
|
out = 0
|
||||||
for power, digit in enumerate(integer[::-1]):
|
for power, digit in enumerate(integer[::-1]):
|
||||||
out += BaseConverter.form_digits[digit] * base**power
|
out += from_digits[digit] * base**power
|
||||||
for power, digit in enumerate(str(fractional),1):
|
for power, digit in enumerate(str(fractional),1):
|
||||||
out += BaseConverter.from_digits[digit] * base**(-power)
|
out += from_digits[digit] * base**(-power)
|
||||||
|
|
||||||
return out
|
return out
|
||||||
|
|
||||||
def __add__(self,other):
|
def __add__(self,other):
|
||||||
if not isinstance(other, BaseConverter):
|
if not isinstance(other, BaseConverter):
|
||||||
other = BaseConverter(other,BaseConverter.digits)
|
other = BaseConverter(other,self.digits)
|
||||||
|
return BaseConverter(self.value + other.value,digits=self.digits)
|
||||||
return BaseConverter(self.value + other.value,BaseConverter.digits)
|
|
||||||
|
|
||||||
def __iadd__(self,other):
|
def __iadd__(self,other):
|
||||||
if not isinstance(other, BaseConverter):
|
if not isinstance(other, BaseConverter):
|
||||||
other = BaseConverter(other,BaseConverter.digits)
|
other = BaseConverter(other,self.digits)
|
||||||
self.value = self.value + other.value
|
self.value = self.value + other.value
|
||||||
self.string = BaseConverter.from_dec(self.value,BaseConverter.base)
|
self.string = BaseConverter.from_dec(self.value,digits=self.digits)
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __radd__(self,other):
|
def __radd__(self,other):
|
||||||
return BaseConverter(other,BaseConverter.digits) + self
|
return BaseConverter(other,self.digits) + self
|
||||||
|
|
||||||
def __sub__(self,other):
|
def __sub__(self,other):
|
||||||
if not isinstance(other, BaseConverter):
|
if not isinstance(other, BaseConverter):
|
||||||
other = BaseConverter(other,BaseConverter.digits)
|
other = BaseConverter(other,self.digits)
|
||||||
|
return BaseConverter(self.value - other.value,digits=self.digits)
|
||||||
return BaseConverter(self.value - other.value,BaseConverter.digits)
|
|
||||||
|
|
||||||
def __isub__(self,other):
|
def __isub__(self,other):
|
||||||
if not isinstance(other, BaseConverter):
|
if not isinstance(other, BaseConverter):
|
||||||
other = BaseConverter(other,BaseConverter.digits)
|
other = BaseConverter(other,self.digits)
|
||||||
self.value = self.value - other.value
|
self.value = self.value - other.value
|
||||||
self.string = BaseConverter.from_dec(self.value,BaseConverter.base)
|
self.string = BaseConverter.from_dec(self.value,digits=self.digits)
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __rsub__(self,other):
|
def __rsub__(self,other):
|
||||||
return BaseConverter(other,BaseConverter.digits) - self
|
return BaseConverter(other,self.digits) - self
|
||||||
|
|
||||||
def __mul__(self,other):
|
def __mul__(self,other):
|
||||||
if not isinstance(other, BaseConverter):
|
if not isinstance(other, BaseConverter):
|
||||||
other = BaseConverter(other,BaseConverter.digits)
|
other = BaseConverter(other,self.digits)
|
||||||
|
return BaseConverter(self.value * other.value,digits=self.digits)
|
||||||
return BaseConverter(self.value * other.value,BaseConverter.digits)
|
|
||||||
|
|
||||||
def __imul__(self,other):
|
def __imul__(self,other):
|
||||||
if not isinstance(other, BaseConverter):
|
if not isinstance(other, BaseConverter):
|
||||||
other = BaseConverter(other,BaseConverter.digits)
|
other = BaseConverter(other,self.digits)
|
||||||
self.value = self.value * other.value
|
self.value = self.value * other.value
|
||||||
self.string = BaseConverter.from_dec(self.value,BaseConverter.base)
|
self.string = BaseConverter.from_dec(self.value,digits=self.digits)
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __rmul__(self,other):
|
def __rmul__(self,other):
|
||||||
return BaseConverter(other,BaseConverter.digits) * self
|
return BaseConverter(other,self.digits) * self
|
||||||
|
|
||||||
def __truediv__(self,other):
|
def __truediv__(self,other):
|
||||||
if not isinstance(other, BaseConverter):
|
if not isinstance(other, BaseConverter):
|
||||||
other = BaseConverter(other,BaseConverter.digits)
|
other = BaseConverter(other,self.digits)
|
||||||
|
return BaseConverter(self.value / other.value,self.digits)
|
||||||
return BaseConverter(self.value / other.value,BaseConverter.digits)
|
|
||||||
|
|
||||||
def __itruediv__(self,other):
|
def __itruediv__(self,other):
|
||||||
if not isinstance(other, BaseConverter):
|
if not isinstance(other, BaseConverter):
|
||||||
other = BaseConverter(other,BaseConverter.digits)
|
other = BaseConverter(other,self.digits)
|
||||||
self.value = self.value / other.value
|
self.value = self.value / other.value
|
||||||
self.string = BaseConverter.from_dec(self.value,BaseConverter.base)
|
self.string = BaseConverter.from_dec(self.value,digits=self.digits)
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __rtruediv__(self,other):
|
def __rtruediv__(self,other):
|
||||||
return BaseConverter(other,BaseConverter.digits) / self
|
return BaseConverter(other,self.digits) / self
|
||||||
|
|
||||||
|
def __pow__(self,other):
|
||||||
|
if not isinstance(other, BaseConverter):
|
||||||
|
other = BaseConverter(other,self.digits)
|
||||||
|
return BaseConverter(self.value ** other.value,self.digits)
|
||||||
|
|
||||||
|
def __ipow__(self,other):
|
||||||
|
if not isinstance(other, BaseConverter):
|
||||||
|
other = BaseConverter(other,self.digits)
|
||||||
|
self.value = self.value ** other.value
|
||||||
|
self.string = BaseConverter.from_dec(self.value,digits=self.digits)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __rpow__(self,other):
|
||||||
|
return BaseConverter(other,self.digits) ** self
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
if '.' in self.string:
|
if '.' in self.string:
|
||||||
return self.string[:7].rstrip('0') + f'(base{BaseConverter.base})'
|
return self.string[:7].rstrip('0') + f'(base{self.base})'
|
||||||
else:
|
else:
|
||||||
return self.string + f'(base{BaseConverter.base})'
|
return self.string + f'(base{self.base})'
|
||||||
|
|
||||||
|
def __lt__(self, other):
|
||||||
|
if not isinstance(other, BaseConverter):
|
||||||
|
other = BaseConverter(other,self.digits)
|
||||||
|
return self.value < other.value
|
||||||
|
|
||||||
|
def __le__(self, other):
|
||||||
|
if not isinstance(other, BaseConverter):
|
||||||
|
other = BaseConverter(other,self.digits)
|
||||||
|
return self.value <= other.value
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
if not isinstance(other, BaseConverter):
|
||||||
|
other = BaseConverter(other,self.digits)
|
||||||
|
return self.value == other.value
|
||||||
|
|
||||||
|
def __ne__(self, other):
|
||||||
|
if not isinstance(other, BaseConverter):
|
||||||
|
other = BaseConverter(other,self.digits)
|
||||||
|
return self.value != other.value
|
||||||
|
|
||||||
|
def __ge__(self, other):
|
||||||
|
if not isinstance(other, BaseConverter):
|
||||||
|
other = BaseConverter(other,self.digits)
|
||||||
|
return self.value >= other.value
|
||||||
|
|
||||||
|
def __gt__(self, other):
|
||||||
|
if not isinstance(other, BaseConverter):
|
||||||
|
other = BaseConverter(other,self.digits)
|
||||||
|
return self.value > other.value
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.string
|
return self.string
|
||||||
|
@ -179,7 +235,7 @@ class BaseConverter:
|
||||||
|
|
||||||
def to_base(self,base):
|
def to_base(self,base):
|
||||||
''' give out in different base '''
|
''' give out in different base '''
|
||||||
return BaseConverter.from_dec(self.value,base)
|
return BaseConverter.from_dec(self.value,base=base)
|
||||||
|
|
||||||
class duo(BaseConverter):
|
class duo(BaseConverter):
|
||||||
''' class to represent duodecimal numbers
|
''' class to represent duodecimal numbers
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 12,
|
"execution_count": 1,
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
|
@ -150,7 +150,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 10,
|
"execution_count": 8,
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [
|
||||||
{
|
{
|
||||||
|
@ -188,36 +188,36 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 13,
|
"execution_count": 8,
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [
|
||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text/plain": [
|
"text/plain": [
|
||||||
"16(base12)"
|
"1000(base2)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"execution_count": 13,
|
"execution_count": 8,
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"output_type": "execute_result"
|
"output_type": "execute_result"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"source": [
|
"source": [
|
||||||
"binary(8) + duo('X')"
|
"binary(8)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 18,
|
"execution_count": 9,
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [
|
||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text/plain": [
|
"text/plain": [
|
||||||
"X(base12)"
|
"1010(base2)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"execution_count": 18,
|
"execution_count": 9,
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"output_type": "execute_result"
|
"output_type": "execute_result"
|
||||||
}
|
}
|
||||||
|
@ -228,22 +228,43 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 19,
|
"execution_count": 26,
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [
|
||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text/plain": [
|
"text/plain": [
|
||||||
"'0123456789XE'"
|
"False"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"execution_count": 19,
|
"execution_count": 26,
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"output_type": "execute_result"
|
"output_type": "execute_result"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"source": [
|
"source": [
|
||||||
"binary.digits"
|
"binary('10000') < duo('X')"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 31,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/plain": [
|
||||||
|
"'42'"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"execution_count": 31,
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "execute_result"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"x = duo('2X')\n",
|
||||||
|
"x.to_base(8)"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
Loading…
Reference in New Issue
Block a user