class SmallDecimal: """Provides a mutable, modest-precision, fixed-point decimal number for clinical calculations. The constructor allows two possible arguments, both of which have been given default values. The scale is determined by the "scaling" argument. If this argument is equal to one or greater it is used as the scale directly (after making sure it is in the proper range. If the scaling argument is less than one, it is assumed to be an interval and the scale is calculated as the reciprocal. The default interval is 0.01 so the default scale is 100. The number of fraction digits to be displayed can be specified by the "digits" argument independent of the interval or scale. The default is two fraction digits. Finally, the numeric "value" can be set at initialization if desired, with the default value being zero. In addition to the constructor there are seven methods, six public methods and one private. Although the scaling factor is determined at instance creation and rarely changed thereafter, setScale() has been left public for use by the programmer if needed. The integer scaling factor can be read with the getScale() method. The value of the instance can be read one of two ways. The getValue() method returns a floating-point representation of the scaled value. When the integer unscaled value is needed, the getUnscaled() method may be called. There are two ways to set the value of the SmallDecimal instance. The first is through the setValue() method, which takes any numeric value. The second is via the setUnscaled() method, which sets the unscaled (integer) value directly. The setValue() method unscales this number (multiplies it by the scaling factor and rounds the result) and sends the result to setUnscaled(). The setUnscaled() method calls the private method __change(), which returns TRUE (0) if the new value is different from the old value or FALSE (1) if not. This Boolean value is not used in the base version of setUnscaled(), but setUnscaled() can be overridden to make the SmallDecimal into an 'observable' object.""" #----------------------------------------------------------------------------------- def __init__(self, scaling=0.01): """The constructor initializes __unscaled, and __scale""" self.__unscaled = 0 # always initialize value to zero if scaling < 1: self.setInterval(scaling) else: self.setScale(scaling) #----------------------------------------------------------------------------------- def rescale(self, value): """...""" denominator = float(self.__scale) return (value / denominator) def unscale(self, value): return int(round(value * self.__scale)) #----------------------------------------------------------------------------------- def setScale(self, scale): """Set the scale of this object after checking validity""" scale = min(100000, scale) scale = max(1, scale) self.__scale = int(scale) def setInterval(self, interval): """Set the scale of this object from desired interval""" self.setScale(int(1 / interval)) def getScale(self): """Returns an integer value for the scaling factor""" return self.__scale #----------------------------------------------------------------------------------- def change(self, value): """The final common pathway for all changes made to the value of the SmallDecimal object. Called ONLY by .setUnscaled()""" if (value == self.__unscaled): return 0 # if no change in value, return FALSE else: self.__unscaled = value return 1 # if value changed, return TRUE def setUnscaled(self, value): """A call to .setUnscaled() which makes no change does not trigger observers. Can be overridden to make object observable.""" if self.change(value): # put code here to to notify observers, typically: # self.notifyObservers() pass def getUnscaled(self): """Returns the unscaled value of the SmallDecimal (as an integer)""" return self.__unscaled def setValue(self, value): """Set instance value from scaled value from any valid representation.""" self.setUnscaled(self.unscale(value)) #unscale and round def getValue(self): """Returns a floating-point representation of the SmallDecimal""" value = float(self.__unscaled) return (self.scale(value)) # rescales the value