Showing posts with label xo. Show all posts
Showing posts with label xo. Show all posts

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)