prePEP: Money data type

Batista, Facundo FBatista at uniFON.com.ar
Fri Oct 17 16:55:44 EDT 2003


Here I send it.

Suggestions and all kinds of recomendations are more than welcomed.

If it all goes ok, it'll be a PEP when I finish writing the code.

Thank you.

.	Facundo


------------------------------------------------------------------------

PEP: XXXX
Title: Money data type
Version: $Revision: 0.1 $
Last-Modified: $Date: 2003/10/17 17:34:00 $
Author: Facundo Batista <fbatista at unifon.com.ar>
Status: Draft
Type: Standards Track
Content-Type: text/x-rst
Created: 17-Oct-2003
Python-Version: 2.3.3


Abstract
========

The idea is to make a Money data type, basically for financial uses, where
decimals are needed but floating point is too inexact.  The Money data type
should support the Python standard functions and operations.


Rationale
=========

The detail of the requeriments are in the `Requirements`_ section.  Here
I'll
include all the decisions made and why, and all the subjects still in
discussion.  The requirements will be numbered, to simplify discussion on
each point.

As an XP exercise, I'll write the test cases before de class itself, so
it'll
comply exactly the requeriments of those tests.  Please see them for an
exact
specification (and if you propose a different behaviour, please propose the
corresponding test case if possible, thanks).


Why Not To Use Tim Peters' FixedPoint?
--------------------------------------

As we'll see in Requeriments, thera are items that FixedPoint doesn´t comply
(because doesn't do something or does it different).  It could be extended
or
modified to comply the Requeriments, but some needs are own to currency, and
some features of FixedPoint are too much for Money, so taking them out will
make this class simplier.

Anyway, sometime maybe one could be made subclass of the other, or just make
one from both.  The code of the Money class is based in large part on the
code of Tim Peters' FixedPoint: thank you for your (very) valuable ideas.


Items In Discussion
-------------------

6. About repr(). Should ``myMoney == eval(repr(myMoney))``?


Requirements
============

1. The sintaxis should be ``Money(value, [precision])``.

2. The value could of the type:

       - another money (if you don't include *precision*, it get
inheritated)
       
       - int or long (default *precision*: 0)::
       
           Money(45): 45
           Money(45, 2): 45.00
           Money(5000000000,3): 5000000000.000
           
       - float (*precision* must be included)::
       
           Money(50.33, 3): 50.330
           
       - string (*precision* get extracted from the string)::
       
           Money('25.32'): 25.32
           Money('25.32', 4): 25.3200
           
       - something that could be coerced by long() or float()

3. Not to support strings with engineer notation (you don't need this when
   using money).

4. Precision must be a non negative integer, and after created the object
   you could not change it.

5. Attributes ``decimalSeparator``, ``currencySymbol`` and
   ``thousandSeparator`` could be overloaded, just to easy change them
   subclassing. This same *decimalSeparator* is that used by the constructor
   when receives a string. Defaults are::
   
       decimalSeparator = '.'
       currencySimbol = '$'
       thousandSeparator = ''

6. Calling repr() should not return str(self), because if the subclass
   indicates that ``decimalSeparator=''``, this could carry to a confusion.
   So, repr() should show a tuple of three values: IntPart, FracPart,
   Precision.

7. To comply the test case of Mark McEahern::

       cost = Money('5.99')
       percentDiscount = 10
       months = 3
       subTotal = cost * months
       discount = subTotal * (percentDiscount * 1.0) / 100
       total = subTotal - discount
       assertEqual(total, Money('16.17'))
    
8. To support the basic aritmetic (``+, -, *, /, //, **, %, divmod``) and
the
   comparisons (``==, !=, <, >, <=, >=, cmp``) in the following cases:
   
       - Money op Money
       - Money op otherType
       - otherType op Money
       - Money op= otherType
   
   OtherType could be int, float or long. Automaticlly will be converted to
   Money, inheritating the precision from the other component of the
   operation (and, in the case of the float, maybe losing precision
**before**
   the operation).
   
   When both are Moneys, the result has the larger precision from both.
    
9. To support unary operators (``-, +, abs``).

10. To support the built-in methods:

        - min, max
        - float, int, long (int and long are rounded by Money)
        - str, repr
        - hash
        - copy, deepcopy
        - bool (0 is false, otherwise true)

11. To have methods that return its components. The value of Money will be
    ``(int part) + (frac part) / (10 ** precision)``.
    
        - ``getPrecision()``: the precision
        - ``getFracPart()``: the fractional part (as long)
        - ``getIntPart()``: the int part (as long)

12. The rounding to be financial. This means that to round a number in a
    position, if the digit at the right of that position is bigger than 5,
    the digit at the left of that position is incremented by one, if it's
    smaller than 5 isn't::
    
        1.123 --> 1.12
        1.128 --> 1.13
    
    But when the digit at the right of that position is ==5. There, if the
    digit at the left of that position is odd, it gets incremented,
otherwise
    isn't::
    
        1.125 --> 1.12
        1.135 --> 1.14


Reference Implementation
========================

To be included later:

	- code
	- test code
	- documentation


Copyright
=========

This document has been placed in the public domain.





More information about the Python-list mailing list