diff --git a/.gitignore b/.gitignore index 8f18f3c..b9c5594 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .ipynb_checkpoints/ __pycache__/ +.vscode/ \ No newline at end of file diff --git a/duodecimal.py b/duodecimal.py index 35c625e..ab11d19 100644 --- a/duodecimal.py +++ b/duodecimal.py @@ -1,35 +1,39 @@ -class duo: - ''' class to represent duodecimal numbers - - 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , X , E +class BaseConverter: + ''' class to represent numbers in diferent bases 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 ''' - def __init__(self,number): + def __init__(self,number,digits): ''' determine type of input and convert to decimal/duodecimal ''' - self.duo_digits = {0: '0', 1: '1', 2: '2', 3: '3', 4: '4', 5: '5', - 6: '6', 7: '7', 8: '8', 9: '9', 10: 'X', 11: 'E'} - self.dec_digits = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, - '6': 6, '7': 7, '8': 8, '9': 9, 'E': 11, 'X': 10} - self.base = 12 + BaseConverter.digits = digits + BaseConverter.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: - self.decimal = number - self.duodecimal = self.dec_to_duo(number) + self.value = number + self.string = BaseConverter.from_dec(number,BaseConverter.base) elif type(number) == str: - self.decimal = self.duo_to_dec(number) - self.duodecimal = number + self.value = BaseConverter.to_dec(number,BaseConverter.base) + self.string = number else: - raise TypeError('unkown type') - - def dec_to_duo(self,number): + raise TypeError('input type must be str or float/int') + + @staticmethod + def from_dec(number,base): ''' convert decimal float/int to duodecimal string ''' # handle negative numbers @@ -43,26 +47,27 @@ class duo: out = [] quotient = integer while quotient != 0: - quotient, remainder = divmod(quotient,self.base) + quotient, remainder = divmod(quotient,base) 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: out = [] remainder = fractional 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) if remainder > 0.5: out.append(1) - decimal = '.' + ''.join([self.duo_digits[dig] for dig in out]) + decimal = '.' + ''.join([BaseConverter.to_digits[dig] for dig in out]) else: decimal = '' return sign + integer + decimal.rstrip('0') - - def duo_to_dec(self,string): - ''' convert duodecimal string to decimal float/int ''' + + @staticmethod + def to_dec(string,base): + ''' convert string to decimal float/int ''' # handle negative numbers if string.startswith('-'): @@ -71,8 +76,8 @@ class duo: else: sign = 1 - if set(string) > set('123456789XE'): - invalid = set(string) - set('123456789XE') + if set(string) > set(BaseConverter.digits): + invalid = set(string) - set(BaseConverter.digits) raise ValueError('invalid character'.format(invalid)) if '.' in string: @@ -82,76 +87,122 @@ class duo: out = 0 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): - out += self.dec_digits[digit] * self.base**(-power) + out += BaseConverter.from_digits[digit] * base**(-power) return out def __add__(self,other): - '''add two duodecimal numbers''' - - if isinstance(other, duo): - result = self.decimal + other.decimal - elif type(other) == int or type(other) == float: - result = self.decimal + other - elif type(other) == str: - result = self.decimal + self.duo_to_dec(other) - else: - raise TypeError('unkown type') - return duo(result) + if not isinstance(other, BaseConverter): + other = BaseConverter(other,BaseConverter.digits) + + return BaseConverter(self.value + other.value,BaseConverter.digits) + + def __iadd__(self,other): + if not isinstance(other, BaseConverter): + other = BaseConverter(other,BaseConverter.digits) + self.value = self.value + other.value + self.string = BaseConverter.from_dec(self.value,BaseConverter.base) + + return self + + def __radd__(self,other): + return BaseConverter(other,BaseConverter.digits) + self def __sub__(self,other): - ''' subtract two duodecimal numbers ''' - - if isinstance(other, duo): - result = self.decimal - other.decimal - elif type(other) == int or type(other) == float: - result = self.decimal - other - elif type(other) == str: - result = self.decimal - self.duo_to_dec(other) - else: - raise TypeError('unkown type') - return duo(result) + if not isinstance(other, BaseConverter): + other = BaseConverter(other,BaseConverter.digits) + + return BaseConverter(self.value - other.value,BaseConverter.digits) + + def __isub__(self,other): + if not isinstance(other, BaseConverter): + other = BaseConverter(other,BaseConverter.digits) + self.value = self.value - other.value + self.string = BaseConverter.from_dec(self.value,BaseConverter.base) + + return self + + def __rsub__(self,other): + return BaseConverter(other,BaseConverter.digits) - self def __mul__(self,other): - ''' multiply two duodecimal numbers ''' - - if isinstance(other, duo): - result = self.decimal * other.decimal - elif type(other) == int or type(other) == float: - result = self.decimal * other - elif type(other) == str: - result = self.decimal * self.duo_to_dec(other) - else: - raise TypeError('unkown type') - return duo(result) - + if not isinstance(other, BaseConverter): + other = BaseConverter(other,BaseConverter.digits) + + return BaseConverter(self.value * other.value,BaseConverter.digits) + + def __imul__(self,other): + if not isinstance(other, BaseConverter): + other = BaseConverter(other,BaseConverter.digits) + self.value = self.value * other.value + self.string = BaseConverter.from_dec(self.value,BaseConverter.base) + + return self + + def __rmul__(self,other): + return BaseConverter(other,BaseConverter.digits) * self + def __truediv__(self,other): - ''' divide two duodecimal numbers ''' - - if isinstance(other, duo): - result = self.decimal / other.decimal - elif type(other) == int or type(other) == float: - result = self.decimal / other - elif type(other) == str: - result = self.decimal / self.duo_to_dec(other) - else: - raise TypeError('unkown type') - return duo(result) - - def dec(self): - ''' return the decimal representation ''' - return self.decimal - + if not isinstance(other, BaseConverter): + other = BaseConverter(other,BaseConverter.digits) + + return BaseConverter(self.value / other.value,BaseConverter.digits) + + def __itruediv__(self,other): + if not isinstance(other, BaseConverter): + other = BaseConverter(other,BaseConverter.digits) + self.value = self.value / other.value + self.string = BaseConverter.from_dec(self.value,BaseConverter.base) + + return self + + def __rtruediv__(self,other): + return BaseConverter(other,BaseConverter.digits) / self + def __repr__(self): - if '.' in self.duodecimal: - return self.duodecimal[:7].rstrip('0') + '(base12)' + if '.' in self.string: + return self.string[:7].rstrip('0') + f'(base{BaseConverter.base})' else: - return self.duodecimal + '(base12)' + return self.string + f'(base{BaseConverter.base})' def __str__(self): - return self.duodecimal + return self.string def __format__(self,format): - return self.duodecimal \ No newline at end of file + 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) \ No newline at end of file diff --git a/example_usage.ipynb b/example_usage.ipynb index 2249be9..7b4a42b 100644 --- a/example_usage.ipynb +++ b/example_usage.ipynb @@ -11,13 +11,11 @@ }, { "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": true - }, + "execution_count": 12, + "metadata": {}, "outputs": [], "source": [ - "from duodecimal import duo" + "from duodecimal import BaseConverter, duo, binary" ] }, { @@ -111,7 +109,7 @@ { "data": { "text/plain": [ - "1(base12)" + "10(base12)" ] }, "execution_count": 6, @@ -152,7 +150,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 10, "metadata": {}, "outputs": [ { @@ -178,34 +176,74 @@ ], "source": [ "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", - " 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", " 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", " print(' \\t'.join(row))" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "10" + "16(base12)" ] }, - "execution_count": 5, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "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" ] } ],