Re: Monetary calculations in CL



On Feb 14, 8:08 am, "John Thingstad" <jpth...@xxxxxxxxx> wrote:
På Thu, 14 Feb 2008 13:50:18 +0100, skrev Greg Menke <guse...@xxxxxxxxxxx>:
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)

What? Given exact rationals, you can implement the rounding rules
arithmetically. You don't need to depend on how those numbers are
implemented.

E.g. suppose you are to round to the nearest 0.01 such that:

0.xy4... -> 0.xy

0.xy5 -> (if (evenp y) 0.xy (+ 0.xy 0.01))

0.xy5... -> 0.xy + 0.01

You multiply the input by 100 to obtain xy.zw. To get the y digit, if
necessary, truncate the number to integer, and compute the residue
modulo 10. If the fractional part is less than half, take the
truncated number and divide by 100. If it's greater than half, add 1
and divide by 100. If it's exactly half, apply the test to y.

Here is some code, which has a few simplifying assumptions. One is
that the input is rational. The second is that EXPT gives us a
rational (and even if the exponent is negative). This works in CLISP
but is nonportable.


(defun round-even-odd-rule (input digits)
(let* ((multiplier (expt 10 digits))
(sign (signum input))
(scaled (* (abs input) multiplier)))
(multiple-value-bind (int frac) (truncate scaled)
(* sign
(/ (cond
((< frac 1/2) int)
((> frac 1/2) (1+ int))
(t (let ((leastdigit (mod int 10)))
(if (evenp leastdigit)
int (1+ int)))))
multiplier)))))


;; round to integer:
(round-even-odd-rule 1/2 0) -> 1

;; round to multiple of 10:
(round-even-odd-rule 1/2 1) -> 0

;; round 1.125 to nearest hundredth:
;; should be 1.12 since 2 is even.
(round-even-odd-rule 1125/1000 2) -> 28/25 ;; i.e. 112/100 or 1.12

;; round 1.135 to nearest hundredth:
;; should be 1.14 since 3 is odd:
(round-even-odd-rule 1135/1000 2) -> 57/50 ;; i.e. 114/100

;; round 7885 to nearest thousand:
(round-even-odd-rule 7885 -3) -> 8000

Of course, with BCD, to do the rounding, you just duplicate the input
number, and then work on the digits directly. Converting BCD between
internal representation and text is also trivial. (Have I, as I
suspect, just summed up the complete gamut of the advantages of BCD?)
.



Relevant Pages

  • Re: System.Math.Round bug (repost)
    ... Round(double value, int digits) ... It always seems to use the Round(decimal value, int decimals) version, no ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Round float to X significant digits
    ... > David Corby wrote: ... >> I'm trying to round a double to a particular number of significant ... int main{ ... x=2453126.722708, round to 2,3,4,5 digits: ...
    (comp.lang.cpp)
  • Re: XQ and ->Qpi bug on large X
    ... you shouldn't be rounding to only two digits ... I am trying to make a similar point here about rounding; ... and round it, ... prior to using the input values in calculations. ...
    (comp.sys.hp48)
  • Re: Decimall Float Question
    ... the number other than to round the decimal part. ... 'bankers rounding' to the nearest even number is not required). ... the FAQ code includes having a variable number of digits after ... // Convert number to string and split ... ...
    (comp.lang.javascript)
  • Re: check decimal and if numeric
    ... so effectively truncates an subsequent digits for positive numbers. ... It's different when you round negative numbers down, ... decimals, who's to say the third or fourth digit was the one that was in error? ...
    (microsoft.public.access.formscoding)

Loading