From:

Date:

September 3, 2009 09:36Subject:

Proposal: perl with financial valuesMessage ID:

1ffb04f20909030659j6228713cy3f1bac17f48f1956@mail.gmail.comFirst of all, let me state that my XS- and C-programming skills are not very good, so I would not be able to program what I am about to propose. But I would like to ask p5p if my thoughts make any sense. Here is my idea: I propose a new lexically scoped pragma 'use financial;' (and its counter-part 'no financial;') to replace the usual floating point arithmetric by decimal numbers which allows for accurate arithmetic in financial perl applications. My idea is a replacement for the existing "NV"-value by a new "financial" value (what I would call "YV"-value), which consists of a signed 64-bit mantissa (even on 32-bit perls) and a signed 8-bit exponent. The mantissa is a normal integer in the range (2**63 - 1) .. (-2**63), the exponent is in the range (127 .. -128). The important point here is that the exponent represents a power of 10 (and not of 2), which allows for accurate representations of numbers such as 0.01, 14.7, 0.0597, etc... (i.e.: 0.01 ==> 1 * 10**(-2), 14.7 = 147 * 10**(-1), 0.0597 = 597 * 10**(-4)), that don't have accurate representations in binary form. "Simple" arithmetic between "YV"-values (addition, substraction, multiplication and exponentiation with positive integer exponents) would be implemented as C-code: Addition/Subtraction of two "YV"-values ==> normalize the two exponents to the lower of the two, then perform addition/substraction of the two mantissas (on 32-bit perls, the mantissa still would be 64-bit long, therefore the addition would have to be performed in two steps). Normalisation: if the resulting mantissa is a power of 10 itself, then divide the mantissa by that power of 10 and increase the exponent accordingly. Multiplication and exponentiation with positive integer exponents of "YV" values ==> multiply the two 64-bit mantissas into a 128-bit temp-variable, then add the two exponents. Normalisation: if the resulting mantissa is a power of 10 itself, then divide the mantissa by that power of 10 and increase the exponent accordingly. Final adjustment: if the 128-bit result is greater than 2**63, then divide mantissa by 10 (and add 1 to exponent) until the 128-bit mantissa falls below 2**63. More complicated arithmetic between "YV"-values (division, exponentiation with a negative or non-integer exponent, square-root, sine, cosine, log, etc ...) would be perfomed by first converting the "YV"-values into temporary "NV"-values, then performing the traditional arithmetic, and finally converting the result back to a "YV"-value. Converting from traditional "NV" values to the new "YV" values would be performed with a C-algorithm that is the equivalent of the already existing function sprintf("%.128f", ...) and converting from the new "YV"-values back to traditional "NV"-values would be performed with a C-algorithm that is the equivalent of the already existing function that converts strings ("PV"-values) into "NV"-values. Arithmetic with "YV" values would be slower than the usual "double" arithmetic, but still sufficiently fast, because "financial" arithmetic is implemented as efficient C-code. When we encounter "YV"-values, mixed with traditional "NV"-values, the following rules apply: Inside a lexically scoped "use financial;" ==> we convert the "NV"-value into a temporary "YV"-variable and perform the "YV"-arithmetic with the temporary variable. All numerical constants inside a lexically scoped "use financial;" are either integers ("IV") or "YV"-values. Outside a lexically scoped "use financial;" ==> we convert the "YV"-value into a temporary "NV"-variable and perform the "NV"-arithmetic with the temporary variable. All numerical constants outside a lexically scoped "use financial;" are either integers ("IV") or "NV"-values. Here is a simple test (which, of course, fails, because "use financial;" is not yet implemented): ===================================================== use strict; use warnings; use Test::More tests => 2; { use financial; my $z = 0; for (1..100) { $z += 0.01; } ok($z == 1, 'use financial --> 0.01 * 100 == 1'); } { no financial; my $z = 0; for (1..100) { $z += 0.01; } ok($z != 1, 'no financial --> 0.01 * 100 != 1'); } ===================================================== -- klaus03@gmail.comThread Next

**Proposal: perl with financial values**by Klaus- Re: Proposal: perl with financial values by Zefram
- Re: Proposal: perl with financial values by John Peacock

nntp.perl.org: Perl Programming lists via nntp and http.

Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About