2019.03.09 - support for different bases

This commit is contained in:
Fabian Scheuermann 2019-03-09 17:56:47 +01:00
parent 2822d471e9
commit e56c275376
3 changed files with 188 additions and 98 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
.ipynb_checkpoints/ .ipynb_checkpoints/
__pycache__/ __pycache__/
.vscode/

View File

@ -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)

View File

@ -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"
] ]
} }
], ],