Math::Decimal64 - perl interface to C's _Decimal64 operations.
In order to compile this module, a C compiler that provides the _Decimal64 type is needed.
Math::Decimal64 supports up to 16 decimal digits of significand (mantissa) and an exponent range of -383 to +384. The smallest expressable value is -9.999999999999999e384 (which is also equivalent to -9999999999999999e369). The largest expressable value is 9.999999999999999e384 (which also equivalent to 9999999999999999e369). The closest we can get to zero is (plus or minus) 1e-384 (which is also equivalent to 1000000000000000e-399). This module allows decimal floating point arithmetic via operator overloading - see "OVERLOADING". In the documentation that follows, "$mantissa" is a perl scalar holding a string of up to 16 decimal digits, optionally prefixed with a '+' or '-' sign: $mantissa = '1234'; $mantissa = '1234567890123456';
use Math::Decimal64 qw(:all); my $d64_1 = MEtoD64('9927', -2); # the decimal 99.27 my $d64_2 = MEtoD64('3', 0); # the decimal 3.0 $d64_1 /= $d64_2; print $d64_1; # prints 3309e-2 (33.09)
The following operations are overloaded: + - * / += -= *= /= != == <= >= <=> < > ++ -- = abs bool int print neg Arguments to the overloaded operations must be Math::Decimal64 objects, integer (IV/UV) values or string (PV) values. Strings can match /^(\-|\+)?(nan|inf)/i or be in floating point, scientific notation or integer formats. Eg '113', '12.34', '12e-9', '-12.34e+106', '-9E8', '-NaN', 'inf' are all valid strings. $d64_2 = $d64_1 + $d128_0; #ok $d64_2 = $d64_1 + 15; #ok $d64_2 = $d64_1 + 3.1; # Error If you really want to add the NV 3.1 you need to: $d64_2 = $d64_1 + NVtoD64(3.1); If you instead wish to add the decimal value 3.1: $d64_2 = $d64_1 + '3.1'; Overloading of floats (NV values) will probably never be enabled as that would make it very easy to inadvertently introduce a value that was not intended.
The following create and assign a new Math::Decimal64 object. ################################## # Create, and assign from a string $d64 = PVtoD64($string); eg: $d64 = PVtoD64('-9427199254740993'); $d64 = PVtoD64('-9307199254740993e-15'); $d64 = Math::Decimal64->new('-9787199254740.993e-20'); $d64 = Math::Decimal64->new('-9307199254740993e-23'); $d64 = Math::Decimal64->new('-inf'); $d64 = Math::Decimal64->new('nan'); If the string arg contains characters that (according to perl's looks_like_number API function) don't make sense in numeric context, then a global non-numeric flag which was initialised to 0 is incremented - and the value assigned is in accordance with perl's usual rules. If $Math::Decimal64::NNW (set to 0 by default) is set to 1, then a non-numeric warning is also issued whenever the non-numeric flag is incremented. The arg can be in either integer format, scientific notation, float format or (+-)inf/nan. Doing Math::Decimal64->new($string) will also create and assign using PVtoD64(). The nnumflag function returns the current value of the global. It can be cleared to 0 by running clear_nnum() and set to x with set_nnum(x). PVtoD64 is now a much improved way of creating and assigning - so much so that I'm now recommending it as the preferred way of creating a Math::Decimal64 object. If you have a ($mantissa, $exponent) pair as your value and you wish to create a Math::Decimal64 object using PVtoD64 you can do: $d64 = PVtoD64(MEtoPV($mantissa, $exponent)); or simply: $d64 = PVtoD64($mantissa . 'e' . $exponent); ############################################### # Create, and assign from mantissa and exponent $d64 = MEtoD64($mantissa, $exponent); eg: $d64 = MEtoD64('12345', -3); # 12.345 It's a little kludgy, but this is a safe and sure way of creating the Math::Decimal64 object with the intended value. Checks are conducted to ensure that the arguments are suitable. The mantissa string must represent an integer. (There's an implicit '.0' at the end of the string.) Doing Math::Decimal64->new($mantissa, $exponent) will also create and assign using MEtoD64(), and is equally acceptable. ############################################### # Create, and assign from mantissa and exponent $d64 = DPDtoD64($mantissa, $exponent); eg: $d64 = DPDtoD64('12345', -3); # 12.345 This is perhaps a quicker way of creating the Math::Decimal64 object with the intended value - but works only for DPD format - ie only if d64_fmt() returns 'DPD'. The mantissa string can be 'inf' or 'nan', optionally prefixed with '-' or '+'. Otherwise, the mantissa string must represent an integer value (with implied '.0' at the end) - ie cannot contain a decimal point. ################################################# # Create, and assign from a UV (unsigned integer) $d64 = UVtoD64($uv); eg: $d64 = UVtoD64(~0); Doing Math::Decimal64->new($uv) will also create and assign using UVtoD64(). Assigns the designated UV value to the Math::Decimal64 object (but loses precision if the _Decimal64 type has insufficient precision to accommodate the precision of the IV). ################################################ # Create, and assign from an IV (signed integer) $d64 = IVtoD64($iv); eg: $d64 = IVtoD64(-15); # -15.0 Doing Math::Decimal64->new($iv) will also create and assign using IVtoD64(). Assigns the designated IV value to the Math::Decimal64 object (but loses precision if the _Decimal64 type has insufficient precision to accommodate the precision of the IV). ############################################################ # Create, and assign from an existing Math::Decimal64 object $d64 = D64toD64($d64_0); Also: $d64 = Math::Decimal64->new($d64_0); $d64 = $d64_0; # uses overloaded '=' ####################################### # Create, and assign from an NV (real)) $d64 = NVtoD64($nv); eg: $d64 = NVtoD64(-3.25); Doing Math::Decimal64->new($nv) is now a fatal error. NV's can now be assigned using only either NVtoD64() or assignNV(). Might not always assign the value you think it does, but should be fine for assigning decimal values that have en exact base 2 representation. (Eg, see test 5 in t/overload_cmp.t.) ################################ # Create, and assign using new() $d64 = Math::Decimal64->new([$arg1, [$arg2]]); This function calls one of the above functions. It determines the appropriate function to call by examining the argument(s) provided. If no argument is provided, a Math::Decimal64 object with a value of NaN is returned. If 2 arguments are supplied it uses MEtoD64(). If one argument is provided, that arg's internal flags are used to determine the appropriate function to call. Dies if that argument is an NV - allowing an NV argument makes it very easy to inadvertently assign an unintended value, and is therefore now disallowed. ################################### # Create, and assign using STRtoD64 $d64 = STRtoD64($string); If your C compiler provides the strtod64 function, and you configured the Makefile.PL to enable access to that function then you can use this function. Usage is is as for PVtoD64(). ##############################
##################################### assignME($d64, $mantissa, $exponent); Assigns the value represented by ($mantissa, $exponent) to the Math::Decimal64 object, $d64. Performs same argument checking as MEtoD64. eg: assignME($d64, '123459', -6); # 0.123459 ###################################### assignDPD($d64, $mantissa, $exponent); Assigns the value represented by ($mantissa, $exponent) to the Math::Decimal64 object, $d64. This might work more efficiently than assignME(), but works only when the _Decimal64type is DPD-formatted. (The d64_fmt function will tell you whether the _Decimal64 is DPD-formatted or BID-formatted.) eg: assignDPD($d64, '123459', -6); # 0.123459 ######################## assignIV ($d64, $iv); assignUV ($d64, $uv); assignNV ($d64, $nv); assignPV ($d64, $string); # See PVtoD64 doc (above) assignD64($d64, $d64_0); Assigns the value represented by the second arg (resp. the IV,UV,NV,PV, Math::Decimal64 object) to the Math::Decimal64 object, $d64. eg: assignPV($d64, '12.3459e-6'); # 0.0000123459 ################ assignNaN($d64); Assigns a NaN to the Math::Decimal64 object, $d64. ####################### assignInf($d64, $sign); Assigns an Inf to the Math::Decimal64 object, $d64. If $sign is negative, assigns -Inf; otherwise +Inf. #######################
##################### $d64 = InfD64($sign); If $sign < 0, creates a new Math::Decimal64 object set to negative infinity; else creates a Math::Decimal64 object set to positive infinity. ################ $d64 = NaND64(); Creates a new Math::Decimal64 object set to NaN. Same as "$d64 = Math::Decimal64->new();" ###################### $d64 = ZeroD64($sign); If $sign < 0, creates a new Math::Decimal64 object set to negative zero; else creates a Math::Decimal64 object set to zero. #######################
The following functions provide ways of seeing the value of Math::Decimal64 objects. ########################### $string = decode_d64($d64); This function calls either decode_dpd() or decode_bid(), depending upon the formatting used to encode the _Decimal64 value (as determined by the d64_fmt() sub). It returns the value as a string of the form (-)ME, where: "M" is the mantissa, containing up to 16 base 10 digits; "E" is the letter "e" followed by the exponent; A minus sign is prefixed to any -ve number (incl -0), but no sign at all is prefixed for +ve numbers (incl +0). Returns the strings '+inf', '-inf', 'nan' for (respectively) +infinity, -infinity, NaN. The value will be decoded correctly. ################################## $string = decode_dpd($d64_binary); $string = decode_bid($d64_binary); As for decode_d64(), except it takes the 64-bit binary representation of the _Decimal64 value as its argument. This argument is derived from the Math::Decimal64 object ($d64) by doing: $binary = hex2bin(d64_bytes($d64)); DPD and BID formats will return different strings - so you need to know which encoding (DPD or BID) was used, and then call the appropriate decode_*() function for that encoding. $Math::Decimal64::fmt will tell you which encoding is in use, as also will the d64_fmt() subroutine. ########################### $fstring = D64toFSTR($d64); Returns a string in floating point format (as distinct from scientific notation) - ie as 0.123 instead of 123e-3. And, yes, (eg) the _Decimal64 value 123e201 will be returned as a string consisting of '123' followed by 201 zeroes. #################################### $rstring = D64toRSTR($d64, $places); Same as D64toFSTR() but the returned string has been rounded (to nearest, ties to even) to the number of decimal places specified by $places. Croaks with appropriate error message if $places < 0. ####################################### ($mantissa, $exponent) = D64toME($d64); Returns the value of the Math::Decimal64 object as a mantissa (string of up to 16 decimal digits) and exponent. You can then manipulate those values to output the value in your preferred format. Afaik, the value will be decoded accurately. ######################################## ($mantissa, $exponent) = FR64toME($d64); Requires that Math::MPFR version 3.18 or later has been loaded. It also requires that Math:MPFR has been built with support for the mpfr library's Decimal64 conversion functions - in which case Math::MPFR::_WANT_DECIMAL_FLOATS() will return true. (Otherwise it returns false.) Afaik, the value will be decoded accurately. #################### $nv = D64toNV($d64); This function returns the value of the Math::Decimal64 object to a perl scalar (NV). Under certain conditions it may not translate the value accurately. ########### print $d64; Will print the value in the format (eg) -12345e-2, which equates to the decimal -123.45. Uses D64toME(). ######### pFR $d64; Will print the value in the format (eg) -12345e-2, which equates to the decimal -123.45. Uses FR64toME() - which should always print the value accurately, but requires that Math::MPFR: 1) has been loaded; 2) supports the Decimal64 mpfr conversion functions. #########
################################## $iv = Math::Decimal64::nnumflag(); # not exported Returns the value of the non-numeric flag. This flag is initialized to zero, but incemented by 1 whenever the _atodecimal function (used internally by assignPV and PVtoD64) is handed a string containing non-numeric characters. The value of the flag therefore tells us how many times _atodecimal() was handed such a string. The flag can be reset to 0 by running clear_nnum(). ############################### Math::Decimal64::set_nnum($iv); # not exported Resets the global non-numeric flag to the value specified by $iv. ############################## Math::Decimal64::clear_nnum(); # not exported Resets the global non-numeric flag to 0.(Essentially the same as running set_nnum(0).) ################################ ($man, $exp) = PVtoME($string); $string is a string representing a floating-point value - eg 'inf', '+nan', '123.456', '-1234.56e-1', or '12345.6E-2'. The function returns an array of (mantissa, exponent), where the mantissa is a string of base 10 digits (prefixed with a '-' for -ve values) with an implied decimal point at the end of the string. For strings such as 'inf' and 'nan', the mantissa will be set to $string, and the exponent to 0. For the example strings given above, the returned arrays would be ('inf', 0), ('+nan', 0), ('123456', -3), ('-123456', -3) and ('123456', -3) respectively. ####################################### $string = MEtoPV($mantissa, $exponent); If $mantissa =~ /inf|nan/i returns $mantissa. Else returns $mantissa . 'e' . $exponent. ################# $fmt = d64_fmt(); Returns either 'DPD' or 'BID', depending upon whether the (internal) _Decimal64 values are encoded using the 'Densely Packed Decimal' format or the 'Binary Integer Decimal' format. ####################### $hex = d64_bytes($d64); Returns the hex representation of the _Decimal64 value as a string of 16 hex characters. ############################ $binary = hex2bin($d64_hex); Takes the string returned by d64_bytes (above) and rewrites it in binary form - ie as a string of 64 base 2 digits. ################# $d64 = DEC64_MAX; # 9999999999999999e369 $d64 = DEC64_MIN; # 1e-398 DEC64_MAX is the largest positive finite representable _Decimal64 value. DEC64_MIN is the smallest positive non-zero representable _Decimal64 value. Multiply these by -1 to get their negative counterparts. ################### $d64 = Exp10($pow); Returns a Math::Decimal64 object with a value of 10 ** $pow, for $pow in the range (-398 .. 384). Croaks with appropriate message if $pow is not within that range. ######################## $bool = have_strtod64(); Returns true if, when building Math::Decimal64, the Makefile.PL was configured to make the STRtoD64() function available for your build of Math::Decimal64. Else returns false. (No use making this function available if your compiler's C library doesn't provide the strtod64 function.) ######################### $test = is_ZeroD64($d64); Returns: -1 if $d64 is negative zero; 1 if $d64 is zero, but not negative zero; 0 if $d64 is not zero. ######################## $test = is_InfD64($d64); Returns: -1 if $d64 is negative infinity; 1 if $d64 is positive infinity; 0 if $d64 is not infinity. ######################## $bool = is_NaND64($d64); Returns: 1 if $d64 is a NaN; 0 if $d64 is not a NaN. ################### LDtoD64($d64, $ld); # $ld is a Math::LongDouble object D64toLD($ld, $d64); # $ld is a Math::LongDouble object Conversions between Math::LongDouble and Math::Decimal64 objects - done by simply casting the long double value to a _Decimal64 value, or (resp.) vice-versa. Requires that Math::LongDouble has been loaded. ####################### $sign = get_sign($d64); Returns the sign ('+' or '-') of $d64. ##################### $exp = get_exp($d64); Returns the exponent of $d64. This is the exponent value that's stored internally within the encapsulated _Decimal64 value; it may differ from the value that you assigned. For example, if you've assigned the value MEtoD64('100', 0) it will probably be held internally as '1e2', not '100e0', in which case get_exp() would return 2, not 0. ####################
This program is free software; you may redistribute it and/or modify it under the same terms as Perl itself. Copyright 2012-15 Sisyphus
Sisyphus <sisyphus at(@) cpan dot (.) org>
To install Math::Decimal64, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Math::Decimal64
CPAN shell
perl -MCPAN -e shell install Math::Decimal64
For more information on module installation, please visit the detailed CPAN module installation guide.