2019.03.09 - support for different bases
This commit is contained in:
parent
2822d471e9
commit
e56c275376
|
@ -1,2 +1,3 @@
|
||||||
.ipynb_checkpoints/
|
.ipynb_checkpoints/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
|
.vscode/
|
219
duodecimal.py
219
duodecimal.py
|
@ -1,35 +1,39 @@
|
||||||
class duo:
|
class BaseConverter:
|
||||||
''' class to represent duodecimal numbers
|
''' class to represent numbers in diferent bases
|
||||||
|
|
||||||
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , X , E
|
|
||||||
|
|
||||||
Input:
|
Input:
|
||||||
------
|
------
|
||||||
either string (base12) or float/int (base10)
|
numbers : either string (baseX) or float/int (base10)
|
||||||
|
digits :string of digits used in the base (e.g. binary: '01')
|
||||||
|
|
||||||
|
Variables:
|
||||||
|
----------
|
||||||
|
value : holds the decimal value
|
||||||
|
string : holds the representation in BaseConverter.base
|
||||||
|
|
||||||
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
|
||||||
'''
|
'''
|
||||||
|
|
||||||
def __init__(self,number):
|
def __init__(self,number,digits):
|
||||||
''' determine type of input and convert to decimal/duodecimal '''
|
''' determine type of input and convert to decimal/duodecimal '''
|
||||||
|
|
||||||
self.duo_digits = {0: '0', 1: '1', 2: '2', 3: '3', 4: '4', 5: '5',
|
BaseConverter.digits = digits
|
||||||
6: '6', 7: '7', 8: '8', 9: '9', 10: 'X', 11: 'E'}
|
BaseConverter.base = len(digits)
|
||||||
self.dec_digits = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5,
|
BaseConverter.to_digits = {k: v for k,v in enumerate(digits)}
|
||||||
'6': 6, '7': 7, '8': 8, '9': 9, 'E': 11, 'X': 10}
|
BaseConverter.from_digits = {v: k for k,v in enumerate(digits)}
|
||||||
self.base = 12
|
|
||||||
|
|
||||||
if type(number) == int or type(number) == float:
|
if type(number) == int or type(number) == float:
|
||||||
self.decimal = number
|
self.value = number
|
||||||
self.duodecimal = self.dec_to_duo(number)
|
self.string = BaseConverter.from_dec(number,BaseConverter.base)
|
||||||
|
|
||||||
elif type(number) == str:
|
elif type(number) == str:
|
||||||
self.decimal = self.duo_to_dec(number)
|
self.value = BaseConverter.to_dec(number,BaseConverter.base)
|
||||||
self.duodecimal = number
|
self.string = number
|
||||||
else:
|
else:
|
||||||
raise TypeError('unkown type')
|
raise TypeError('input type must be str or float/int')
|
||||||
|
|
||||||
def dec_to_duo(self,number):
|
@staticmethod
|
||||||
|
def from_dec(number,base):
|
||||||
''' convert decimal float/int to duodecimal string '''
|
''' convert decimal float/int to duodecimal string '''
|
||||||
|
|
||||||
# handle negative numbers
|
# handle negative numbers
|
||||||
|
@ -43,26 +47,27 @@ class duo:
|
||||||
out = []
|
out = []
|
||||||
quotient = integer
|
quotient = integer
|
||||||
while quotient != 0:
|
while quotient != 0:
|
||||||
quotient, remainder = divmod(quotient,self.base)
|
quotient, remainder = divmod(quotient,base)
|
||||||
out.insert(0,remainder)
|
out.insert(0,remainder)
|
||||||
integer = ''.join([self.duo_digits[dig] for dig in out])
|
integer = ''.join([BaseConverter.to_digits[dig] for dig in out])
|
||||||
|
|
||||||
if fractional:
|
if fractional:
|
||||||
out = []
|
out = []
|
||||||
remainder = fractional
|
remainder = fractional
|
||||||
for i in range(len(str(fractional).split('.')[1])+1):
|
for i in range(len(str(fractional).split('.')[1])+1):
|
||||||
quotient, remainder = divmod(remainder*self.base,1)
|
quotient, remainder = divmod(remainder*base,1)
|
||||||
out.append(quotient)
|
out.append(quotient)
|
||||||
if remainder > 0.5:
|
if remainder > 0.5:
|
||||||
out.append(1)
|
out.append(1)
|
||||||
decimal = '.' + ''.join([self.duo_digits[dig] for dig in out])
|
decimal = '.' + ''.join([BaseConverter.to_digits[dig] for dig in out])
|
||||||
else:
|
else:
|
||||||
decimal = ''
|
decimal = ''
|
||||||
|
|
||||||
return sign + integer + decimal.rstrip('0')
|
return sign + integer + decimal.rstrip('0')
|
||||||
|
|
||||||
def duo_to_dec(self,string):
|
@staticmethod
|
||||||
''' convert duodecimal string to decimal float/int '''
|
def to_dec(string,base):
|
||||||
|
''' convert string to decimal float/int '''
|
||||||
|
|
||||||
# handle negative numbers
|
# handle negative numbers
|
||||||
if string.startswith('-'):
|
if string.startswith('-'):
|
||||||
|
@ -71,8 +76,8 @@ class duo:
|
||||||
else:
|
else:
|
||||||
sign = 1
|
sign = 1
|
||||||
|
|
||||||
if set(string) > set('123456789XE'):
|
if set(string) > set(BaseConverter.digits):
|
||||||
invalid = set(string) - set('123456789XE')
|
invalid = set(string) - set(BaseConverter.digits)
|
||||||
raise ValueError('invalid character'.format(invalid))
|
raise ValueError('invalid character'.format(invalid))
|
||||||
|
|
||||||
if '.' in string:
|
if '.' in string:
|
||||||
|
@ -82,76 +87,122 @@ class duo:
|
||||||
|
|
||||||
out = 0
|
out = 0
|
||||||
for power, digit in enumerate(integer[::-1]):
|
for power, digit in enumerate(integer[::-1]):
|
||||||
out += self.dec_digits[digit] * self.base**power
|
out += BaseConverter.form_digits[digit] * base**power
|
||||||
for power, digit in enumerate(str(fractional),1):
|
for power, digit in enumerate(str(fractional),1):
|
||||||
out += self.dec_digits[digit] * self.base**(-power)
|
out += BaseConverter.from_digits[digit] * base**(-power)
|
||||||
|
|
||||||
return out
|
return out
|
||||||
|
|
||||||
def __add__(self,other):
|
def __add__(self,other):
|
||||||
'''add two duodecimal numbers'''
|
if not isinstance(other, BaseConverter):
|
||||||
|
other = BaseConverter(other,BaseConverter.digits)
|
||||||
if isinstance(other, duo):
|
|
||||||
result = self.decimal + other.decimal
|
return BaseConverter(self.value + other.value,BaseConverter.digits)
|
||||||
elif type(other) == int or type(other) == float:
|
|
||||||
result = self.decimal + other
|
def __iadd__(self,other):
|
||||||
elif type(other) == str:
|
if not isinstance(other, BaseConverter):
|
||||||
result = self.decimal + self.duo_to_dec(other)
|
other = BaseConverter(other,BaseConverter.digits)
|
||||||
else:
|
self.value = self.value + other.value
|
||||||
raise TypeError('unkown type')
|
self.string = BaseConverter.from_dec(self.value,BaseConverter.base)
|
||||||
return duo(result)
|
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __radd__(self,other):
|
||||||
|
return BaseConverter(other,BaseConverter.digits) + self
|
||||||
|
|
||||||
def __sub__(self,other):
|
def __sub__(self,other):
|
||||||
''' subtract two duodecimal numbers '''
|
if not isinstance(other, BaseConverter):
|
||||||
|
other = BaseConverter(other,BaseConverter.digits)
|
||||||
if isinstance(other, duo):
|
|
||||||
result = self.decimal - other.decimal
|
return BaseConverter(self.value - other.value,BaseConverter.digits)
|
||||||
elif type(other) == int or type(other) == float:
|
|
||||||
result = self.decimal - other
|
def __isub__(self,other):
|
||||||
elif type(other) == str:
|
if not isinstance(other, BaseConverter):
|
||||||
result = self.decimal - self.duo_to_dec(other)
|
other = BaseConverter(other,BaseConverter.digits)
|
||||||
else:
|
self.value = self.value - other.value
|
||||||
raise TypeError('unkown type')
|
self.string = BaseConverter.from_dec(self.value,BaseConverter.base)
|
||||||
return duo(result)
|
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __rsub__(self,other):
|
||||||
|
return BaseConverter(other,BaseConverter.digits) - self
|
||||||
|
|
||||||
def __mul__(self,other):
|
def __mul__(self,other):
|
||||||
''' multiply two duodecimal numbers '''
|
if not isinstance(other, BaseConverter):
|
||||||
|
other = BaseConverter(other,BaseConverter.digits)
|
||||||
if isinstance(other, duo):
|
|
||||||
result = self.decimal * other.decimal
|
return BaseConverter(self.value * other.value,BaseConverter.digits)
|
||||||
elif type(other) == int or type(other) == float:
|
|
||||||
result = self.decimal * other
|
def __imul__(self,other):
|
||||||
elif type(other) == str:
|
if not isinstance(other, BaseConverter):
|
||||||
result = self.decimal * self.duo_to_dec(other)
|
other = BaseConverter(other,BaseConverter.digits)
|
||||||
else:
|
self.value = self.value * other.value
|
||||||
raise TypeError('unkown type')
|
self.string = BaseConverter.from_dec(self.value,BaseConverter.base)
|
||||||
return duo(result)
|
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __rmul__(self,other):
|
||||||
|
return BaseConverter(other,BaseConverter.digits) * self
|
||||||
|
|
||||||
def __truediv__(self,other):
|
def __truediv__(self,other):
|
||||||
''' divide two duodecimal numbers '''
|
if not isinstance(other, BaseConverter):
|
||||||
|
other = BaseConverter(other,BaseConverter.digits)
|
||||||
if isinstance(other, duo):
|
|
||||||
result = self.decimal / other.decimal
|
return BaseConverter(self.value / other.value,BaseConverter.digits)
|
||||||
elif type(other) == int or type(other) == float:
|
|
||||||
result = self.decimal / other
|
def __itruediv__(self,other):
|
||||||
elif type(other) == str:
|
if not isinstance(other, BaseConverter):
|
||||||
result = self.decimal / self.duo_to_dec(other)
|
other = BaseConverter(other,BaseConverter.digits)
|
||||||
else:
|
self.value = self.value / other.value
|
||||||
raise TypeError('unkown type')
|
self.string = BaseConverter.from_dec(self.value,BaseConverter.base)
|
||||||
return duo(result)
|
|
||||||
|
return self
|
||||||
def dec(self):
|
|
||||||
''' return the decimal representation '''
|
def __rtruediv__(self,other):
|
||||||
return self.decimal
|
return BaseConverter(other,BaseConverter.digits) / self
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
if '.' in self.duodecimal:
|
if '.' in self.string:
|
||||||
return self.duodecimal[:7].rstrip('0') + '(base12)'
|
return self.string[:7].rstrip('0') + f'(base{BaseConverter.base})'
|
||||||
else:
|
else:
|
||||||
return self.duodecimal + '(base12)'
|
return self.string + f'(base{BaseConverter.base})'
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.duodecimal
|
return self.string
|
||||||
|
|
||||||
def __format__(self,format):
|
def __format__(self,format):
|
||||||
return self.duodecimal
|
return self.string
|
||||||
|
|
||||||
|
def decimal(self):
|
||||||
|
''' return the decimal representation '''
|
||||||
|
return self.value
|
||||||
|
|
||||||
|
def to_base(self,base):
|
||||||
|
''' give out in different base '''
|
||||||
|
return BaseConverter.from_dec(self.value,base)
|
||||||
|
|
||||||
|
class duo(BaseConverter):
|
||||||
|
''' class to represent duodecimal numbers
|
||||||
|
|
||||||
|
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , X , E
|
||||||
|
|
||||||
|
Input:
|
||||||
|
------
|
||||||
|
either string (base12) or float/int (base10)
|
||||||
|
'''
|
||||||
|
|
||||||
|
def __init__(self,number):
|
||||||
|
BaseConverter.__init__(self,number,'0123456789XE')
|
||||||
|
|
||||||
|
class binary(BaseConverter):
|
||||||
|
def __init__(self,number):
|
||||||
|
BaseConverter.__init__(self,number,'01')
|
||||||
|
|
||||||
|
class hexa(BaseConverter):
|
||||||
|
def __init__(self,number):
|
||||||
|
BaseConverter.__init__(self,number,'0123456789ABCDEF')
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
a = duo(2)
|
||||||
|
a /= 4
|
||||||
|
print(a)
|
|
@ -11,13 +11,11 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 1,
|
"execution_count": 12,
|
||||||
"metadata": {
|
"metadata": {},
|
||||||
"collapsed": true
|
|
||||||
},
|
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"from duodecimal import duo"
|
"from duodecimal import BaseConverter, duo, binary"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -111,7 +109,7 @@
|
||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text/plain": [
|
"text/plain": [
|
||||||
"1(base12)"
|
"10(base12)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"execution_count": 6,
|
"execution_count": 6,
|
||||||
|
@ -152,7 +150,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 8,
|
"execution_count": 10,
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [
|
||||||
{
|
{
|
||||||
|
@ -178,34 +176,74 @@
|
||||||
],
|
],
|
||||||
"source": [
|
"source": [
|
||||||
"multiplication_table = []\n",
|
"multiplication_table = []\n",
|
||||||
"for i in range(1,duo('10').dec()+1):\n",
|
"for i in range(1,duo('10').decimal()+1):\n",
|
||||||
" row = ['{:>2}|'.format(duo(i))]\n",
|
" row = ['{:>2}|'.format(duo(i))]\n",
|
||||||
" for j in range(1,duo('10').dec()+1):\n",
|
" for j in range(1,duo('10').decimal()+1):\n",
|
||||||
" row.append(duo(i*j).__str__())\n",
|
" row.append(duo(i*j).__str__())\n",
|
||||||
" multiplication_table.append(row)\n",
|
" multiplication_table.append(row)\n",
|
||||||
"print('\\t'+' \\t'.join([str(duo(i)) for i in range(1,duo('10').dec()+1)]) + '\\n'+99*'-')\n",
|
"print('\\t'+' \\t'.join([str(duo(i)) for i in range(1,duo('10').decimal()+1)]) + '\\n'+99*'-')\n",
|
||||||
"for row in multiplication_table:\n",
|
"for row in multiplication_table:\n",
|
||||||
" print(' \\t'.join(row))"
|
" print(' \\t'.join(row))"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 5,
|
"execution_count": 13,
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [
|
||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text/plain": [
|
"text/plain": [
|
||||||
"10"
|
"16(base12)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"execution_count": 5,
|
"execution_count": 13,
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"output_type": "execute_result"
|
"output_type": "execute_result"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"source": [
|
"source": [
|
||||||
"duo('X').dec()"
|
"binary(8) + duo('X')"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 18,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/plain": [
|
||||||
|
"X(base12)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"execution_count": 18,
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "execute_result"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"binary(8) + duo(2)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 19,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/plain": [
|
||||||
|
"'0123456789XE'"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"execution_count": 19,
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "execute_result"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"binary.digits"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
Loading…
Reference in New Issue