From 74d442439c7013c52772a431dd7eee0dfecc8ad4 Mon Sep 17 00:00:00 2001 From: Fabian Scheuermann Date: Sat, 9 Mar 2019 11:56:35 +0100 Subject: [PATCH] 2019.03.09 - initial commit --- .gitignore | 2 + duodecimal.py | 151 +++++++++++++++++++++++++++++++ example_usage.ipynb | 213 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 366 insertions(+) create mode 100644 .gitignore create mode 100644 duodecimal.py create mode 100644 example_usage.ipynb diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8f18f3c --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.ipynb_checkpoints/ +__pycache__/ diff --git a/duodecimal.py b/duodecimal.py new file mode 100644 index 0000000..8d7c8b1 --- /dev/null +++ b/duodecimal.py @@ -0,0 +1,151 @@ +class duo: + ''' 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) + + http://www.dozenal.org/drupal/sites_bck/default/files/DSA-ConversionRules_0.pdf + ''' + + def __init__(self,number): + ''' 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 + + if type(number) == int or type(number) == float: + self.decimal = number + self.duodecimal = self.dec_to_duo(number) + + elif type(number) == str: + self.decimal = self.duo_to_dec(number) + self.duodecimal = number.rstrip('0') + else: + raise TypeError('unkown type') + + def dec_to_duo(self,number): + ''' convert decimal float/int to duodecimal string ''' + + # handle negative numbers + if number <0: + number = abs(number) + sign = '-' + else: + sign = '' + integer, fractional = divmod(number,1) + + out = [] + quotient = integer + while quotient != 0: + quotient, remainder = divmod(quotient,self.base) + out.insert(0,remainder) + integer = ''.join([self.duo_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) + out.append(quotient) + if remainder > 0.5: + out.append(1) + decimal = '.' + ''.join([self.duo_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 ''' + + # handle negative numbers + if string.startswith('-'): + string = string[1:] + sign = -1 + else: + sign = 1 + + if set(string) > set('123456789XE'): + invalid = set(string) - set('123456789XE') + raise ValueError('invalid character'.format(invalid)) + + if '.' in string: + integer, fractional = string.split('.') + else: + integer, fractional = string, '' + + out = 0 + for power, digit in enumerate(integer[::-1]): + out += self.dec_digits[digit] * self.base**power + for power, digit in enumerate(str(fractional),1): + out += self.dec_digits[digit] * self.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) + + 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) + + 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) + + 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 + + def __repr__(self): + return self.duodecimal[:7].rstrip('0') + '(base12)' + + def __str__(self): + return self.duodecimal \ No newline at end of file diff --git a/example_usage.ipynb b/example_usage.ipynb new file mode 100644 index 0000000..6f168bd --- /dev/null +++ b/example_usage.ipynb @@ -0,0 +1,213 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Example usage of the duo class\n", + "\n", + "## Basic operations" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "from duodecimal import duo" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "36(base12)" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "duo(42)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "24(base12)" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "duo('24')" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "5X(base12)" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "a = duo(42)\n", + "b = duo(28)\n", + "\n", + "a + b" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "12(base12)" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "a - b" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1(base12)" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "duo(3) * 4" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3.4(base12)" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "duo(10) / '3'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create a multiplication table" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\t1 \t2 \t3 \t4 \t5 \t6 \t7 \t8 \t9 \t10 \t11 \t12\n", + "---------------------------------------------------------------------------------------------------\n", + " 1| \t1 \t2 \t3 \t4 \t5 \t6 \t7 \t8 \t9 \tX \tE \t10\n", + " 2| \t2 \t4 \t6 \t8 \tX \t10 \t12 \t14 \t16 \t18 \t1X \t20\n", + " 3| \t3 \t6 \t9 \t10 \t13 \t16 \t19 \t20 \t23 \t26 \t29 \t30\n", + " 4| \t4 \t8 \t10 \t14 \t18 \t20 \t24 \t28 \t30 \t34 \t38 \t40\n", + " 5| \t5 \tX \t13 \t18 \t21 \t26 \t2E \t34 \t39 \t42 \t47 \t50\n", + " 6| \t6 \t10 \t16 \t20 \t26 \t30 \t36 \t40 \t46 \t50 \t56 \t60\n", + " 7| \t7 \t12 \t19 \t24 \t2E \t36 \t41 \t48 \t53 \t5X \t65 \t70\n", + " 8| \t8 \t14 \t20 \t28 \t34 \t40 \t48 \t54 \t60 \t68 \t74 \t80\n", + " 9| \t9 \t16 \t23 \t30 \t39 \t46 \t53 \t60 \t69 \t76 \t83 \t90\n", + "10| \tX \t18 \t26 \t34 \t42 \t50 \t5X \t68 \t76 \t84 \t92 \tX0\n", + "11| \tE \t1X \t29 \t38 \t47 \t56 \t65 \t74 \t83 \t92 \tX1 \tE0\n", + "12| \t10 \t20 \t30 \t40 \t50 \t60 \t70 \t80 \t90 \tX0 \tE0 \t100\n" + ] + } + ], + "source": [ + "multiplication_table = []\n", + "for i in range(1,13):\n", + " row = ['{:>2}|'.format(i)]\n", + " for j in range(1,13):\n", + " row.append(duo(i*j).__str__())\n", + " multiplication_table.append(row)\n", + "print('\\t'+' \\t'.join(map(str,range(1,13)))+ '\\n'+99*'-')\n", + "for row in multiplication_table:\n", + " print(' \\t'.join(row))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +}