keyongtech


  keyongtech > lisp > 02/2008

 #1  
02-10-08, 07:35 PM
Chaitanya Gupta
This was posted on reddit --
http://cafe.elharo.com/programming/spot-the-bug/

Printed representations aside (that can be taken care of with ~$), how
do you perform monetary calculations in CL?

One way is to represent "cents" using integers. But what I would like to
have is something like Python's decimal type [1]. I don't think standard
CL supports anything like that. Is there any library, etc. which can do
this?

Or is Python's decimal type the wrong way to look? Is there anything
better out there?

Thanks,

Chaitanya

Note:
1. http://cafe.elharo.com/programming/spot-the-bug/
 #2  
02-10-08, 07:47 PM
Chaitanya Gupta
Chaitanya Gupta wrote:
> One way is to represent "cents" using integers. But what I would like to
> have is something like Python's decimal type [1].
> ...
> Note:
> 1. [..]


Oops. That should have been: http://docs.python.org/lib/module-decimal.html

Chaitanya
 #3  
02-10-08, 07:50 PM
Rainer Joswig
In article <fonjmb$kba$1>,
Chaitanya Gupta <mail> wrote:

[..]
>
> Or is Python's decimal type the wrong way to look? Is there anything
> better out there?
>
> Thanks,
>
> Chaitanya
>
> Note:
> 1. [..]




It might also be possible to use 'measures'
for representing and handling monetary data.

'MEASURES is a system to handle engineering numbers and measures in
Common Lisp.'

http://www.cs.cmu.edu/afs/cs/project...easures/0.html

LOOM has probably a newer version of measures.
http://www.isi.edu/isd/LOOM/
 #4  
02-10-08, 08:27 PM
Chaitanya Gupta
Rainer Joswig wrote:
>
> It might also be possible to use 'measures'
> for representing and handling monetary data.
>


Measures looks very interesting. Thanks for the link.
 #5  
02-10-08, 08:54 PM
Kent M Pitman
Chaitanya Gupta <mail> writes:

> Printed representations aside (that can be taken care of with ~$), how
> do you perform monetary calculations in CL?


It depends on your need.

If you're just trying to work out how to manage your personal
mortgage, and can accept slight discrepancies in exchange for speed
and ease of use, floats would probably be fine. If you're trying to
model the dynamics of world economies, which is fuzzy anyway, again
floats are probably fine.

Any use of floats would NOT be adequate to banks, since the roundoff
would be too unpredictable. CL does not offer a packaged solution to
that but does offer some useful tools. e.g., you could use a DOLLARS
class that contained a slot that held an integer number of thousandths
of pennies. And then write whatever methods on the class you wanted
to be able to do. +$, *$, etc.

Even if there were a "fixed decimal" type or something like that,
you'd still have the issue of whether it was proper to do things like
multiply that times another fixed decimal. Using the DOLLARS class,
you could actually control it enough that it could add two DOLLARS
classes but forbid you to add a regular integer to that class, or that
could let you multiply DOLLARS times an integer, but not times
DOLLARS.
 #6  
02-10-08, 11:36 PM
JohnW
On Feb 10, 11:35 am, Chaitanya Gupta <m> wrote:
> Printed representations aside (that can be taken care of with ~$), how
> do you perform monetary calculations in CL?


Chaitanya, I have a written a library whose express intent is
supporting monetary calculations in Common Lisp. You can even do
multi-currency calculations, in which case "balance" objects are
creating which track the individual sub-totals of each currency. You
can convert between currencies using a conversion price, and track the
history of known prices in order to support historical reporting of
market values.

The library is called CAMBL, or the Commoditized Amounts and Balances
Library, and you can find it here:

http://hg.newartisans.com/cambl

It depends on the LOCAL-TIME module (see Google), and also on two
others modules which are also available on the same server:

http://hg.newartisans.com/red-black
http://hg.newartisans.com/periods

The library is very close to its first release. I'm currently using
it as the back-end for an accounting engine, CL-Ledger, which is also
available at the same location. Note that even though it has not been
formally released yet, the code is quite mature, as it represents a
direct port from C++ of a library which has been in active use for
over 4 years now. It comes with a suite of unit tests -- you will
need XLUNIT to run them -- which you should use to verify its
correctness on your platform.

In case you're interested in the implementation, I use rational number
to store all values, plus an integer to indicate how much floating-
point precision to use when printing a particular currency. You don't
have to explicitly specify the precision, either; the library observes
the formatting you use when inputting numbers, and maintains this
format automatically when outputting them. (There are also variants
functions for inputting special numbers whose display characteristics
should not be remembered, like dollar figures with more precision than
2 decimal places).

There is preliminary usage documentation at the top of the Lisp file.
I would be happy to work with you if changes are needed to suit the
library to your needs.

John
 #7  
02-11-08, 07:32 PM
Chaitanya Gupta
JohnW wrote:
> Chaitanya, I have a written a library whose express intent is
> supporting monetary calculations in Common Lisp. You can even do
> multi-currency calculations, in which case "balance" objects are
> creating which track the individual sub-totals of each currency. You
> can convert between currencies using a conversion price, and track the
> history of known prices in order to support historical reporting of
> market values.


This is great. I just checked out cambl from the repository. Will try it
and see how it works out. Is there any mailing list for the project?

> The library is very close to its first release. I'm currently using
> it as the back-end for an accounting engine, CL-Ledger, which is also
> available at the same location. Note that even though it has not been
> formally released yet, the code is quite mature, as it represents a
> direct port from C++ of a library which has been in active use for
> over 4 years now.


Actually, I was looking at Ledger/CL-Ledger just a few weeks back. Never
got around to installing it, but it has been on my todo list for
sometime. Perhaps now I'll be able to take a look. ;)

Chaitanya
 #8  
02-11-08, 07:51 PM
Chaitanya Gupta
Kent M Pitman wrote:
>
> Any use of floats would NOT be adequate to banks, since the roundoff
> would be too unpredictable. CL does not offer a packaged solution to
> that but does offer some useful tools. e.g., you could use a DOLLARS
> class that contained a slot that held an integer number of thousandths
> of pennies. And then write whatever methods on the class you wanted
> to be able to do. +$, *$, etc.
>
> Even if there were a "fixed decimal" type or something like that,
> you'd still have the issue of whether it was proper to do things like
> multiply that times another fixed decimal. Using the DOLLARS class,
> you could actually control it enough that it could add two DOLLARS
> classes but forbid you to add a regular integer to that class, or that
> could let you multiply DOLLARS times an integer, but not times
> DOLLARS.


That's a very interesting way of handling it. I would certainly like to
try it out.

Also, is this technique being used widely? What could be the potential
drawbacks of this?

Chaitanya
 #9  
02-11-08, 08:46 PM
JohnW
On Feb 11, 11:32 am, Chaitanya Gupta <m> wrote:
> This is great. I just checked out cambl from the repository. Will try it
> and see how it works out. Is there any mailing list for the project?


There are web forums for the Ledger project at:

http://forums.newartisans.com/

Anything posted here I usually respond to right away, since Apple Mail
notifies me of all new posts along with my regular e-mail. Or, if you
loathe web interfaces, just send me e-mail directly. I consider CAMBL
"done" at this time, and so am highly motivated to weed out any final
bugs before release.

There is also a Trac for CL-Ledger, in which you could register CAMBL
bugs and suggestions too:

http://trac.newartisans.com/ledger

You will need to register an account for both of these web services,
since allowing public posting and bug creation was resulting in far
too much spam.

John
 #10  
02-12-08, 10:10 PM
Thomas A. Russ
Chaitanya Gupta <mail> writes:

> Printed representations aside (that can be taken care of with ~$), how
> do you perform monetary calculations in CL?
>
> One way is to represent "cents" using integers. But what I would like to
> have is something like Python's decimal type [1]. I don't think standard
> CL supports anything like that. Is there any library, etc. which can do
> this?


Well, another solution that works with standard Common Lisp datatypes
would be to use rational numbers to represent your monetary values.

Dollars, for example, would be integer values and the cents would be
represented as the appropriate fractions. So, for example, you would
write $5.27 as 527/100 or (+ 5 27/100) or even (rationalize 5.27). If
you go the latter route, it is important to use RATIONALIZE rather than
RATIONAL, since the former will give you a nicer rational number.
 #11  
02-14-08, 06:12 AM
Chaitanya Gupta
Thomas A. Russ wrote:
> Dollars, for example, would be integer values and the cents would be
> represented as the appropriate fractions. So, for example, you would
> write $5.27 as 527/100 or (+ 5 27/100) or even (rationalize 5.27). If
> you go the latter route, it is important to use RATIONALIZE rather than
> RATIONAL, since the former will give you a nicer rational number.


Thanks for the heads up on RATIONALIZE/RATIONAL -- I didn't even know
that these functions existed.

Chaitanya
 #12  
02-14-08, 12:50 PM
Greg Menke
Chaitanya Gupta <mail> writes:

> Kent M Pitman wrote:
>
> That's a very interesting way of handling it. I would certainly like to
> try it out.
>
> Also, is this technique being used widely? What could be the potential
> drawbacks of this?
>


It sounds reasonable for accounting purposes but is insufficient for
financial arithmetic- there are often rules for the application of
things like yield rates that specify a number of places of precision and
specific rules for rouding; for example, maintain 12 decimal places and
round the 13th (by implication do not employ precision to more than the
13th place to the right of the decimal). Intermediate products of some
calculations can easily consume 20 or more significant digits.

Simple arithmetic on such calculations is inappropriate. Cobol handles
this sort of thing quite well (intentionally I am sure). CL's numeric
types will easily handle the required precision but the rounding rules
will probably be somewhat troublesome. The class-based approach is
probably the way to handle it- perhaps an "interest" class where the #
of places of significance and the rounding policy are supplied.

Gregm
 #13  
02-14-08, 04:08 PM
John Thingstad
På Thu, 14 Feb 2008 13:50:18 +0100, skrev Greg Menke <gusenet>:

>
> It sounds reasonable for accounting purposes but is insufficient for
> financial arithmetic- there are often rules for the application of
> things like yield rates that specify a number of places of precision and
> specific rules for rouding; for example, maintain 12 decimal places and
> round the 13th (by implication do not employ precision to more than the
> 13th place to the right of the decimal). Intermediate products of some
> calculations can easily consume 20 or more significant digits.
>
> Simple arithmetic on such calculations is inappropriate. Cobol handles
> this sort of thing quite well (intentionally I am sure). CL's numeric
> types will easily handle the required precision but the rounding rules
> will probably be somewhat troublesome. The class-based approach is
> probably the way to handle it- perhaps an "interest" class where the #
> of places of significance and the rounding policy are supplied.
>
> Gregm


Well the most straightforward way is Binary Coded Decimal (BCD).
One nibble (4 bits) is reserved for each digit 0-9. So you write a library
to access numbers this way.
(Many processors have support for this.) Writing such a library is a bit
cumbersome, but still easier than dealing with the imprecision explicitly
in bignums I would think. (Because humans think of precision in digits
not binary)

--------------
John Thingstad
 #14  
02-14-08, 06:57 PM
Greg Menke
"John Thingstad" <jpthing> writes:

> På Thu, 14 Feb 2008 13:50:18 +0100, skrev Greg Menke <gusenet>:
>> Well the most straightforward way is Binary Coded Decimal (BCD).

> One nibble (4 bits) is reserved for each digit 0-9. So you write a
> library to access numbers this way.
> (Many processors have support for this.) Writing such a library is a bit
> cumbersome, but still easier than dealing with the imprecision
> explicitly in bignums I would think. (Because humans think of precision
> in digits not binary)



Probably the easiest way would be to try and do it how COBOL does- since
it was designed to handle this sort of problem. Its worth observing
that when doing this kind of math, conformance to the specified rounding
policy is far more important than speed, both in the operational sense,
and when the time comes to audit the system, and maybe even more
importantly when you have to start tracking down where the 1 cent error
came from...

This is perhaps an example of an "Anti-Greenspun Law", such as, "Any
sufficiently complex financial application contains an ad-hoc,
informally specified, bug ridden slow implementation of COBOL's fixed
place numeric types".

I've seen it happen on a number of occasions, and I've perpetrated it
myself.

Gregm
 #15  
02-14-08, 07:11 PM
Thomas A. Russ
Rainer Joswig <joswig> writes:

> It might also be possible to use 'measures'
> for representing and handling monetary data.
>
> 'MEASURES is a system to handle engineering numbers and measures in
> Common Lisp.'
>
> [..]
>
> LOOM has probably a newer version of measures.
> [..]



It would certainly be possible to do that.

One additional advantage of using the measures package is that one could
then, in principle, also support multiple currencies and automatically
convert between them. The only drawback is that the measures package
assumes that conversion factors are constant, instead of fluctuating.
Although one could keep redefining the conversions to track the market.


Internally, the measures package uses rational numbers for everything
(converted from decimal input using RATIONALIZE), just in order to avoid
floating point rounding issues. People generally like it better if a
units and measures package has 1mm*3.2 => 3.2mm instead of 3.2000002mm ;)

Similar Threads
monetary values

Why do monetary values show up as the pound sign's?

How do I add a column of monetary numbers

I have a column of amounts of money. Just want excel to add them up and give me a total.

Matching a name to a specified monetary amount

I need to find the formula that can match a specified monetary value to a name. For instance if I type in A1 Name1 then in B1 $14.00 comes in or if I would have typed in...

Monetary Format

Hi, Well, I'm developing one application that will have support for many languages and countries, in the application I need to show and to format the currency for the chosen...

Help on Monetary figures

Someone must know but not me. Can i get my figure amounts to only display to 2d.p. while it is linked back to an access dbase? Thanks in advance


All times are GMT. The time now is 11:20 PM. | Privacy Policy