Created by: peterwood

on: 21-Jul-2010

Format: html

Downloaded on: 24-Jan-2022

REBOL 2 doesn't support decimal arithmetic and only has 32-bit integers. This leads to accuracy problems when working with large numbers and decimal fractions. When dynamic load library access was made available in REBOL/View 2.7.7, it provided the opportunity to build a short external library to provide simple decimal arithmetic.

I have written the dynamic link library in the Free Pascal (FPC) language as it has a built-in currency field and is implemented on most major platforms. Free Pascal's currency data supports 4 decimal places and at least 53-bit precision. I had planned to write the library to provide decimal arithmetic for numbers with the integral part having up to 12 digits and the fractional part having up to 4 digits. However, after encountering a formatting bug in the current stable version of FPC (2.4.0), I have restricted this early release to supporting up to 12 integral digits with the fractional part fixed at 2 digits. (The bug has been fixed for the next stable release of FPC).

There is a short REBOL script which creates a object called money which provides functions to perform addition, subtraction, multiplication and division.

Money has been tested on Mac OS X 10.6, Windows/XP, Windows/Vista, Windows/7 and Ubuntu 10.4.

The Money unit tests all run successfully on all of the systems. There is a side-effect problem on Mac OS X under REBOL/View 2.7.7. After the Money dynamic link library has been loaded, and even if it has been freed, View crashes with a floating point error if the machine sleeps when View 2.7.7 is still running. I suspect that this relates to a problem between FPC and the Xcode linker on OS X 10.6 but have yet been able to confirm the cause or find a solution.

Money is published under the MIT licence.

The money functions require numbers to be presented as a REBOL string and returns a string. A number can have up to 12 integral digits with 2 fractional digits. (The current version is a little flexible with input, for instance accepting a pure integer, and whilst it is likely that this will work with any future versions it is not guaranteed to do so.)

Some examples:

"1.00" "-1.00" "123456789012.99" "999999999999.99" ;; maximum value "-123456789012.99" "-999999999999.99" ;; minimum value

This function must be called before attempting to use any of the other functions as it loads the dynamic link library.

Input: A REBOL file! datatype for the dynamic link library

Returns: unset!

>>money/init %libmoney.dylib ;; Mac >>money/init %libmoney.so ;; Ubuntu >>money/init %money.dll ;; Windows

This function frees the dynamic link library.

Input: No input

Returns: unset!

>>money/free-lib

Adds two numbers together.

Input: two money numbers

Output: a money number or error

>> money/add "1.00" "-1.00" == "0.00" >> money/add "1.00" "1.00" == "2.00" >> money/add "1.00" "-1.00" == "0.00" >> money/add "999999999999.98" "0.01" == "999999999999.99" >> money/add "999999999999.99" "0.01" == "error"

Subtracts the second number from the first

Input: two money numbers

Output: a money number or error

>> money/subtract "1.00" "1.00" == "0.00" >> money/subtract "-1.00" "-1.00" == "0.00" >> money/subtract "999999999999.98" "-0.01" == "999999999999.99" >> money/subtract "-999999999999.98" "0.01" == "-999999999999.99" >> money/subtract "-999999999999.99" "999999999999.99" == "error"

Multiplies the first number by the second. The answer is rounded to two decimal places using banker's rounding.

Input: two money numbers

Output: a money number or error

>> money/multiply "1.0" "3.0" == "3.00" >> money/multiply "3.0" "3.0" == "9.00" >> money/multiply "3.0" "3.33" == "9.99" >> money/multiply "3.33" "3.33" == "11.09" >> money/multiply "6.66" "3.00" == "19.98" >> money/multiply "6.67" "3.00" == "20.01" >> money/multiply "999999999.99" "999999999.99" == "error"

Divides the first number by the second. The answer is rounded to two decimal places using banker's rounding.

Input: two money numbers

Output: a money number or error

>> money/divide "3.00" "2.00" == "1.50" >> money/divide "10.00" "3.00" == "3.33" >> money/divide "10.00" "3.33" == "3.00" >> money/divide "20.00" "3.00" == "6.67" >> money/divide "20.00" "6.67" == "3.00" >> money/divide "50.00" "3.00" == "16.67" >> money/divide "50.00" "16.67" == "3.00" >> money/divide "1.00" "0.00" == "error" >> money/divide "99999999999.99" "0.01" == "error"

Formats a number with thousand separators.

Input: a money number

Output: a money number or error

>> money/format "999.99" == "999.99" >> money/format "1234.56" == "1,234.56" >> money/format "123456789012.34" == "123,456,789,012.34"

Formats a number with thousand separators and negative numbers enclosed in parentheses.

Input: a money number

Output: a money number or error

>> money/accounting-format "123456789012.34" == "123,456,789,012.34" >> money/accounting-format "-123456789012.34" == "(123,456,789,012.34)" >> money/accounting-format "-1234.56" == "(1,234.56)"

The dynamic link library has been written for the Free Pascal Compiler version 2.4.0. There is one source code file, money.pas, which can be compiled on any platform on which FPC runs.

The library can be compiled from the command-line using the following command:

fpc money.pas

Due to previousl mentioned confict between FPC and the Mac OS X Snow Leopard linker, the following command is needed to compile the library on Snow Leopard:

fpc -k-no_order_inits money.pas