Friday, May 1, 2009

4.N.13

Apropos of the Sugar 4th grade math activity that David and I are working on, I wrote an integer like class that prints nicely and that allow each digit to be addressed as if it were a list.

__iter__ goes through the digits - allowing gui code to build digit boxes easily.

e.g.:

>>> print maths_4_N_13.LongDivFormatted(15670,3)
5,223
-------- R=1
3 | 15,670
>>>




from types import IntType, LongType

THOUSANDS_SEP = ','
DECIMAL_SEP = ''

class TeachingWholeNumber(object):
"""An integer whole number (>= 0) where each digit is addressable
list style. the 0th element of the 'digits' attribute
is the ones place, the 1st element is the
tens place and so on.
"""

def __init__(self,n=0):
"""New object with default value of 0
"""
if n == 0:
self.digits=[0]
else:
n=int(n)
self.digits=[]
while n > 0:
self.digits.append(n%10)
n=n/10

def __int__(self):
"""Returns the corresponding integer value
"""
retValue = 0
for i,v in enumerate(self.digits):
retValue += (10**i)*v
return retValue


#
# listy methods
#
def __len__(self):
"""Returns the length of the digits list
"""
return len(self.digits)

def __getitem__(self,i):
if type(i) not in (IntType,LongType):
return TypeError, "Index must be an integer type"
else:
return self.digits[i]

def __setitem__(self,i,v):
if type(i) not in (IntType,LongType):
return TypeError, "Index must be an integer type"
if type(v) != IntType or v > 9 or v < 0:
return ValueError, "value, v, must be an integer between 0 and 9"
if i < len(self):
self.digits[i]=v
elif v > 0:
# appending 0 past the last non-zero is a null op
while i> len(self):
self.digits.append(0)
self.digits.append(v)

#
# Expected methods for number-like type
#
def __lt__(self, other):
return int(self) < int(other)

def __le__(self, other):
return int(self) <= int(other)

def __eq__(self, other):
return int(self) == int(other)

def __ne__(self, other):
return int(self) != int(other)

def __gt__(self, other):
return int(self) > int(other)

def __ge__(self, other):
return int(self) >= int(other)

def __add__(self, other):
return self.__class__(int(self)+int(other))

def __sub__(self, other):
return self.__class__(int(self)-int(other))

def __mul__(self, other):
return self.__class__(int(self)*int(other))

def __floordiv__(self, other):
return self.__class__(int(self)/int(other))

def __mod__(self, other):
return self.__class__(int(self)%int(other))

def __divmod__(self, other):
return tuple([self.__class__(x)
for x in divmod(int(self),int(other))])

def __pow__(self, other):
return

def __lshift__(self, other):
return NotImplemented

def __rshift__(self, other):
return NotImplemented

def __and__(self, other):
return NotImplemented

def __xor__(self, other):
return NotImplemented

def __or__(self, other):
return NotImplemented

def __div__(self, other):
return self.__class__(int(self)/int(other))

def __truediv__(self, other):
return NotImplemented

def __neg__(self):
return NotImplemented

def __pos__(self):
return NotImplemented

def __abs__(self):
return abs(int(self))

def __invert__(self):
return NotImplemented

def __complex__(self):
return NotImplemented

def __long__(self):
return long(int(self))

def __float__(self):
return float(int(self))

def __repr__(self):
return str(int(self))

def __str__(self):
"""pretty string
"""

dgtList=[]
for i,v in enumerate(self):
if i>0 and (i-1)%3 == 2:
dgtList.append(THOUSANDS_SEP)
dgtList.append(str(v))
dgtList.reverse()
return ''.join(dgtList)

def rshift(self,places=1):
"""right shift (in base 10) disgarding 'places' least significant digits

Arguments:
- `self`:
- `places`:
"""
# is this better implememted by overriding >> ?

while places > 0:
self.digits.pop(0)
places -= 1

def lshift(self,places=1):
"""left shift (in base 10) disgarding 'places' least significant digits.
Arguments:
- `self`:
- `places`:
"""
# is this better implememted by overriding << ?
while places > 0:
self.digits.insert(0,0)
places -= 1

def randomTWN(low,high):
"""factory fcn to return a random TeachingWholeNumber,
between low and high inclusive.
"""

if high < 0 or low < 0:
raise ValueError, "high and low must be > 0"

i = random.randint(low,high)
return TeachingWholeNumber(i)


class Division (object):
"""Division Container
"""

def __init__ (self,dividend,divisor):
"""New one!
"""
self.dividend = dividend
self.divisor = divisor
self.quotent, self.remainder = divmod(dividend,divisor)


class LongDivFormatted(Division):
"""Knows how to print itself
"""
leftMargin = 1
rightMargin = 2
midMargin = 1
vertbar='|'
horizbar='-'

def __init__ (self,dividend,divisor,useTWN=True):
"""New one!
"""
if useTWN:
dividend=TeachingWholeNumber(dividend)
divisor=TeachingWholeNumber(divisor)
Division.__init__(self,dividend,divisor)


def __str__ (self):
"""ASCII representation.
"""
mainWidth = (self.leftMargin+
len(str(self.divisor))+
(self.midMargin *2)+
len(self.vertbar)+
len(str(self.dividend)))

remainderWidth = ((self.rightMargin) +
len(str(self.remainder))+
len('R='))

totalWidth = mainWidth+remainderWidth

retLines=[]
retLines.append(('%'+str(mainWidth)+'s')%(self.quotent))
retLines.append((' '*(self.leftMargin +
len(str(self.divisor))+
self.midMargin)) +
(self.horizbar*(len(self.vertbar)+
self.midMargin+
len(str(self.dividend)))) +
('%'+str(remainderWidth)+'s')%('R='+str(self.remainder)))
retLines.append((' ' * self.leftMargin) +
str(self.divisor) +
(' ' * self.midMargin) +
self.vertbar +
(' ' * self.midMargin) +
str(self.dividend))

return '\n'.join(retLines)

No comments:

Post a Comment