Math::GMPq - perl interface to the GMP library's rational (mpq) functions.

This module needs the GMP C library - available from: http://gmplib.org.

A bigrational module utilising the Gnu MP (GMP) library. Basically this module simply wraps all of the 'mpq' (rational number) functions provided by that library. The documentation below extensively plagiarises the GMP documentation (which can be found at http://gmplib.org). See also the Math::GMPq test suite for examples of usage. IMPORTANT: If your perl was built with '-Duse64bitint' you need to assign all integers larger than 52-bit in a 'use integer;' block. Failure to do so can result in the creation of the variable as an NV (rather than an IV) - with a resultant loss of precision.

use Math::GMPq qw(:mpq); my $str = '123542/4'; # numerator = 123542 # denominator = 4 my $base = 10; # Create the Math::GMPq object my $bn1 = Rmpq_init(); # Value set to 0/1 # Assign a value. Rmpq_set_str($str, $base); # Remove any factors common to both numerator and # denominator so that gcd(numerator, denominator) == 1. Rmpq_canonicalize($bn1); # or just use the new() function: my $rational = Math::GMPq->new('1234/1179'); # Perform some operations, either by using function calls # or by utilising operator overloading ... see 'FUNCTIONS' # below. . . # print out the value held by $bn1 (in octal): print Rmpq_get_str($bn1, 8), "\n"; # prints '170513/2' # print out the value held by $bn1 (in decimal) with: print Rmpq_get_str($bn1, 10), "\n"; # prints '61771/2'. # or, courtesy of operator loading, simply with: print $bn1, "\n"; # again prints '61771/2'. # print out the value held by $bn1 (in base 29) # using the (alternative) Rmpq_out_str() # function. (This function doesn't print a newline.) Rmpq_out_str($bn1, 29);

Objects created with Rmpq_create_init() have been blessed into package Math::GMPq. They will therefore be automatically cleaned up by the DESTROY() function whenever they go out of scope. If you wish, you can create unblessed objects with Rmpq_init_nobless(). It will then be up to you to clean up the memory associated with these objects by calling Rmpq_clear($op), for each object. Alternatively the objects will be cleaned up when the script ends. I don't know why you would want to create unblessed objects - the point is you can if you want to :-)

See the GMP documentation at http://gmplib.org. These next 3 functions are demonstrated above: $rop = Rmpq_init(); $rop = Rmpq_set_strl($str, $base); # 1 < $base < 63 $str = Rmpq_get_str($op, $base); # 1 < $base < 37 The following functions are simply wrappers around a GMP function of the same name. eg. Rmpq_swap() is a wrapper around mpq_swap() which is fully documented in the GMP manual at http://gmplib.org. "$rop", "$op1", "$op2", etc. are simply Math::GMPq objects - the return value of Rmpq_init or Rmpq_init_nobless functions. They are in fact references to GMP structures. The "$rop" argument(s) contain the result(s) of the calculation being done, the "$op" argument(s) being the input(s) into that calculation. Generally, $rop, $op1, $op2, etc. can be the same perl variable, though usually they will be distinct perl variables referencing distinct GMP structures. Eg. something like Rmpq_add($r1, $r1, $r1), where $r1 *is* the same reference to the same GMP structure, would add $r1 to itself and store the result in $r1. Think of it as $r1 += $r1. Otoh, Rmpq_add($r1, $r2, $r3), where each of the arguments is a different reference to a different GMP structure would add $r2 to $r3 and store the result in $r1. Think of it as $r1 = $r2 + $r3. Mostly, the first argument is the argument that stores the result and subsequent arguments provide the input values. Exceptions to this can be found in some of the functions that actually return a value. Like I say, see the GMP manual for details. I hope it's intuitively obvious or quickly becomes so. Also see the test suite that comes with the distro for some examples of usage. "$ui" means any integer that will fit into a C 'unsigned long int. "$si" means any integer that will fit into a C 'signed long int'. "$double" means any number (not necessarily integer) that will fit into a C 'double'. "$bool" means a value (usually a 'signed long int') in which the only interest is whether it evaluates as true or false. "$str" simply means a string of symbols that represent a number, eg "1234567890987654321234567/7". Valid bases for GMP numbers are 2 to 62 (inclusive). ############ CANONICALIZE Rmpq_canonicalize($op); Remove any factors that are common to the numerator and denominator of $op, and make the denominator positive. ########## INITIALIZE Normally, a variable should be initialized once only or at least be cleared, using `Rmpq_clear', between initializations. 'DESTROY' (which calls 'Rmpq_clear') is automatically called on blessed objects whenever they go out of scope. See the section 'MEMORY MANAGEMENT' (above). $rop = Math::GMPq::new(); $rop = Math::GMPq->new(); $rop = new Math::GMPq(); $rop = Rmpq_init(); $rop = Rmpq_init_nobless(); Initialize $rop and set it to 0/1. #################### ASSIGNMENT FUNCTIONS Rmpq_set($rop, $op); Rmpq_set_z($rop, $z); # $z is a Math::GMPz object Set $rop to value contained in 2nd arg. Rmpq_set_ui($rop, $ui1, $ui2); Rmpq_set_si($rop, $si1, $si2); Set $rop to 2nd arg / 3rd arg. Rmpq_set_d ($rop, $double); Rmpq_set_f ($rop, $f); # $f is a Math::GnumMPf object Rmpq_set_d ($rop, $op); Rmpq_set_NV($rop, $op); # $NV is a perl floating point value Set $rop to the value of the 2nd arg, without rounding. Assigning an Inf or NaN is a fatal error. Rmpq_set_str($rop, $str, $base); Set $rop from $str in the given base $base. The string can be an integer like "41" or a fraction like "41/152". The fraction must be in canonical form, or if not then `Rmpq_canonicalize' must be called. The numerator and optional denominator are parsed the same as in `Rmpz_set_str'. $base can vary from 2 to 62, or if $base is 0 then the leading characters are used: `0x' for hex, `0' for octal, or decimal otherwise. Note that this is done separately for the numerator and denominator, so for instance `0xEF/100' is 239/100, whereas `0xEF/0x100' is 239/256. Rmpq_swap($rop1, $rop2); Swap the values. #################### COMBINED INITIALIZATION AND ASSIGNMENT NOTE: Do NOT use these functions if $rop has already been initialised. Instead use the Rmpq_set* functions in 'Assignment Functions' (above) First read the section 'MEMORY MANAGEMENT' (above). $rop = Math::GMPq->new($arg); $rop = Math::GMPq::new($arg); $rop = new Math::GMPq($arg); Returns a Math::GMPq object with the value of $arg. $arg can be either an integer (signed integer, unsigned integer) or a string that represents a numeric value. If $arg is a string, an optional additional argument that specifies the base of the number can be supplied to new(). If base is 0 (or not supplied) then the leading characters of the string are used: 0x or 0X for hex, 0b or 0B for binary, 0 for octal, or decimal otherwise. Note that this is done separately for the numerator and denominator, so for instance 0xEF/100 is 239/100, whereas 0xEF/0x100 is 239/256. Legal values for the base are 0 and 2..62. #################### RATIONAL CONVERSIONS $double = Rmpq_get_d($op); Convert $op to a 'double'. $str = Rmpq_get_str($op, $base); Convert $op to a string of digits in base $base. The base may vary from 2 to 36. The string will be of the form `num/den', or if the denominator is 1 then just `num'. ################### RATIONAL ARITHMETIC Rmpq_add ($rop, $op1, $op2); Rmpq_add_z($rop, $op1, $z); # $z is a Math::GMPz object 1st arg = 2nd arg + 3rd arg. (The gmp library doesn't provide an mpq_add_z function.) Rmpq_sub ($rop, $op1, $op2); Rmpq_sub_z($rop, $op1, $z); # $z is a Math::GMPz object Rmpq_z_sub($rop, $z, $op1); # $z is a Math::GMPz object 1st arg = 2nd arg - 3rd arg. (The gmp library doesn't provide an mpq_sub_z function or an mpq_z_sub function.) Rmpq_mul ($rop, $op1, $op2); Rmpq_mul_z($rop, $op1, $z); # $z is a Math::GMPz object 1st arg = 2nd arg * 3rd arg. (The gmp library doesn't provide an mpq_mul_z function.) Rmpq_mul_2exp($rop, $op, $ui); $rop = $op * (2 ** $ui). Rmpq_div ($rop, $op1, $op2); Rmpq_div_z($rop, $op1, $z); # $z is a Math::GMPz object Rmpq_z_div($rop, $z, $op1); # $z is a Math::GMPz object 1st arg = 2nd arg / 3rd arg. (The gmp library doesn't provide an mpq_div_z function or an mpq_z_div function.) Rmpq_div_2exp($rop, $op, $ui); $rop = $op / (2 ** $ui). Rmpq_neg($rop, $op); $rop = -$op. Rmpq_abs($rop, $op); $rop = abs($op). Rmpq_inv($rop, $op); $rop = 1 / $op. ########################## APPLYING INTEGER FUNCTIONS Rmpq_numref($z, $op); # $z is a Math::GMPz object Rmpq_denref($z, $op); # $z is a Math::GMPz object Set $rop to the numerator and denominator of $op, respectively. Rmpq_get_num($z, $op); # $z is a Math::GMPz oblect Rmpq_get_den($z, $op); # $z is a Math::GMPz oblect Rmpq_set_num($rop, $z); # $z is a Math::GMPz oblect Rmpq_set_den($rop, $z); # $z is a Math::GMPz oblect Get or set the numerator or denominator of a rational Direct use of `Rmpq_numref' or `Rmpq_denref' is recommended instead of these functions. ################### COMPARING RATIONALS $si = Rmpq_cmp ($op1, $op2); $si = Rmpq_cmp_z($op1, $z); # $z is a Math::GMPz object Compare $op1 and $op2. Return a positive value if 1st arg is greater than 2nd arg, zero if 1st arg == 2nd arg, and a negative value if 1st arg < 2nd arg. To determine if two rationals are equal, `Rmpq_equal' is faster than `Rmpq_cmp'. (The gmp library provides mpq_cmp_z only for gmp-6.1.0 and later but Rmpq_cmp_z is available for all builds of Math::GMPz, irrespective of the underlying version of gmp.) $si = Rmpq_cmp_ui($op, $ui, $ui); $si1 = Rmpq_cmp_si($op, $si2, $ui); Compare $op1 and 2nd arg/3rd arg. Return a positive value if $op1 > 2nd arg/3rd arg, zero if $op1 = 2nd arg/3rd arg, and a negative value if $op1 < 2nd arg/3rd arg. 2nd and 3rd args are allowed to have common factors. Note that the 3rd (NOT 2nd) arg is unsigned. If you want to compare $op with 2/-3, make sure that 2nd arg is '-2' and 3rd arg is '3'. $si = Rmpq_cmp_NV($op, $NV); # $NV is a perl floating point value Return 0 if $op == $NV. Return 1 if $op > $NV. Return -1 if $op < $NV It's a fatal error if $NV is a NaN. $si = Rmpq_sgn($op); Return 1 if $op>0, 0 if $op=0, and -1 if $op < 0. $bool = Rmpq_equal($op1, $op2); # faster than Rmpq_cmp() Return non-zero if $op1 and $op2 are equal, zero if they are non-equal. Although `Rmpq_cmp' can be used for the same purpose, this function is much faster. $si = Rmpq_cmp_z($op, $z);# $z is Math::GMPz or Math::GMP object Return a positive value if $op > $z. Return zero if $op == $z. Return a negative value if $op < $z. ################ I/O of RATIONALS $bytes_written = Rmpq_out_str([$prefix,] $op, $base [, $suffix]); BEST TO USE TRmpq_out_str INSTEAD. Output $op to STDOUT, as a string of digits in base $base. The base may vary from 2 to 36. Output is in the form `num/den' or if the denominator is 1 then just `num'. Return the number of bytes written, or if an error occurred, return 0. The optional first and last arguments ($prefix and $suffix) are strings that will be prepended/appended to the mpq_out_str output. $bytes_written does not include the bytes contained in $prefix and $suffix. $bytes_written = TRmpq_out_str([$prefix,] $stream, $base, $op, [, $suffix]); As for Rmpq_out_str, except that there's the capability to print to somewhere other than STDOUT. Note that the order of the args is different (to match the order of the mpq_out_str args). To print to STDERR: TRmpq_out_str(*stderr, $base, $digits, $op); To print to an open filehandle (let's call it FH): TRmpq_out_str(\*FH, $base, $digits, $op); $bytes_read = Rmpq_inp_str($rop, $base); BEST TO USE TRmpq_inp_str INSTEAD. Read a string of digits from STDIN and convert them to a rational in $rop. Any initial white-space characters are read and discarded. Return the number of characters read (including white space), or 0 if a rational could not be read. The input can be a fraction like `17/63' or just an integer like `123'. Reading stops at the first character not in this form, and white space is not permitted within the string. If the input might not be in canonical form, then `mpq_canonicalize' must be called. $base can be between 2 and 36, or can be 0 in which case the leading characters of the string determine the base, `0x' or `0X' for hexadecimal, `0' for octal, or decimal otherwise. The leading characters are examined separately for the numerator and denominator of a fraction, so for instance `0x10/11' is 16/11, whereas `0x10/0x11' is 16/17. $bytes_read = TRmpq_inp_str($rop, $stream, $base); As for Rmpq_inp_str, except that there's the capability to read from somewhere other than STDIN. To read from STDIN: TRmpq_inp_str($rop, *stdin, $base); To read from an open filehandle (let's call it FH): TRmpq_inp_str($rop, \*FH, $base); ####################### RANDOM NUMBER FUNCTIONS $state = qgmp_randinit_default(); This is the Math::GMPq interface to the gmp library function 'gmp_randinit_default'. $state is blessed into package Math::GMPq::Random and will be automatically cleaned up when it goes out of scope. Initialize $state with a default algorithm. This will be a compromise between speed and randomness, and is recommended for applications with no special requirements. Currently this is the gmp_randinit_mt function (Mersenne Twister algorithm). $state = qgmp_randinit_mt(); This is the Math::GMPq interface to the gmp library function 'gmp_randinit_mt'. Currently identical to fgmp_randinit_default(). $state = qgmp_randinit_lc_2exp($mpz, $ui, $m2exp); This is the Math::GMPq interface to the gmp library function 'gmp_randinit_lc_2exp'. $mpz is a Math::GMP or Math::GMPz object, so one of those modules is required in order to make use of this function. $state is blessed into package Math::GMPq::Random and will be automatically cleaned up when it goes out of scope. Initialize $state with a linear congruential algorithm X = ($mpz*X + $ui) mod (2 ** $m2exp). The low bits of X in this algorithm are not very random. The least significant bit will have a period no more than 2, and the second bit no more than 4, etc. For this reason only the high half of each X is actually used. When a random number of more than m2exp/2 bits is to be generated, multiple iterations of the recurrence are used and the results concatenated. $state = qgmp_randinit_lc_2exp_size($ui); This is the Math::GMPq interface to the gmp library function 'gmp_randinit_lc_2exp_size'. $state is blessed into package Math::GMPf::Random and will be automatically cleaned up when it goes out of scope. Initialize state for a linear congruential algorithm as per gmp_randinit_lc_2exp. a, c and m2exp are selected from a table, chosen so that $ui bits (or more) of each X will be used, ie. m2exp/2 >= $ui. If $ui is bigger than the table data provides then the function fails and dies with an appropriate error message. The maximum value for $ui currently supported is 128. $state2 = qgmp_randinit_set($state1); This is the Math::GMPq interface to the gmp library function 'gmp_randinit_set'. $state2 is blessed into package Math::GMPf::Random and will be automatically cleaned up when it goes out of scope. Initialize $state2 with a copy of the algorithm and state from $state1. $state = qgmp_randinit_default_nobless(); $state = qgmp_randinit_mt_nobless(); $state = qgmp_randinit_lc_2exp_nobless($mpz, $ui, $m2exp); $state2 = qgmp_randinit_set_nobless($state1); As for the above comparable function, but $state is not blessed into any package. (Generally not useful - but they're available if you want them.) qgmp_randseed($state, $mpz); # $mpz is a Math::GMPz or Math::GMP object qgmp_randseed_ui($state, $ui); These are the Math::GMPz interfaces to the gmp library functions 'gmp_randseed' and 'gmp_randseed_ui'. Seed an initialised (but not yet seeded) $state with $mpz/$ui. Either Math::GMP or Math::GMPz is required for 'gmp_randseed'. $ui = qgmp_urandomb_ui($state, $bits); This is the Math::GMPq interface to the gmp library function 'gmp_urandomb_ui'. Return a uniformly distributed random number of $bits bits, ie. in the range 0 to 2 ** ($bits - 1) inclusive. $bits must be less than or equal to the number of bits in an unsigned long. $ui2 = qgmp_urandomm_ui($state, $ui1); This is the Math::GMPq interface to the gmp library function 'gmp_urandomm_ui'. Return a uniformly distributed random number in the range 0 to $ui1 - 1, inclusive. qgmp_randclear($state); Destroys $state, as also does Math::GMPq::Random::DESTROY - two identical functions. Use only if $state is an unblessed object - ie if it was initialised using one of the qgmp_randinit*_nobless functions. #################### OPERATOR OVERLOADING Overloading occurs with numbers, strings,Math::GMPq objects and, to a limited extent, with Math::GMPz objects, and Math::MPFR objects (iff version 3.13 or later of Math::MPFR has been installed). Strings are first converted to Math::GMPq objects, then canonicalized. See the Rmpq_set_str documentation (above) in the section "ASSIGNMENT FUNCTIONS" regarding permissible string formats. The following operators are overloaded: + - * / += -= *= /= ++ -- == != ! < <= > >= <=> = "" abs Atempting to use the overloaded operators with objects that have been blessed into some package other than 'Math::GMPq' or 'Math::MPFR'/'Math::GMPz' (limited applications) will not work. Math::MPFR objects can be used only with '+', '-', '*', '/' and '**' operators, and will work only if Math::MPFR is at version 3.13 or later - in which case the operation will return a Math::MPFR object. Math::GMPz (or Math::GMP) objects can be used only with the comparison operators ( == != < <= > >= <=> ) and with the '+', '+=', '-', '-=', '*', '*=', '/', '/=', '**' and '**=' operators. In those situations where the overload subroutine operates on 2 perl variables, then obviously one of those perl variables is a Math::GMPq object. To determine the value of the other variable the subroutine works through the following steps (in order), using the first value it finds, or croaking if it gets to step 6: 1. If the variable is an unsigned long then that value is used. The variable is considered to be an unsigned long if (perl 5.8 and later) the UOK flag is set or if (perl 5.6) SvIsUV() returns true. 2. If the variable is a signed long int, then that value is used. The variable is considered to be a signed long int if the IOK flag is set. (In the case of perls built with -Duse64bitint, the variable is treated as a signed long long int if the IOK flag is set.) 3. If the variable is an NV, then that value is used. The variable is considered to be a NV if the NOK flag is set && the POK flag is unset. 4. If the variable is a string (ie the POK flag is set) then the value of that string is used. Octal strings must begin with '0', hex strings must begin with either '0x' or '0X' - otherwise the string is assumed to be decimal. If the POK flag is set, but the string is not a valid base 8, 10, or 16 number, the subroutine croaks with an appropriate error message. If the string is of the form 'numerator/denominator', then the bases of the numerator and the denominator are assessed individually. ie '0xa123/ff' is not a valid number (because 'ff' is not a valid base 10 number). That needs to be rewritten as '0xa123/0xff'. 5. If the variable is a Math::GMPq object (or, for operators specified above, a Math::MPFR/Math::GMP/Math::GMPz object) then the value of that object is used. 6. If none of the above is true, then the second variable is deemed to be of an invalid type. The subroutine croaks with an appropriate error message. ############## MISCELLANEOUS $bool = Rmpq_integer_p($op); Returns true if $op is an integer (ie denominator of $op is 1). Else returns false. The mpq_integer_p function is not implemented in gmp. ##### OTHER $GMP_version = Math::GMPq::gmp_v; Returns the version of the GMP library (eg 4.1.3) being used by Math::GMPq. The function is not exportable. $GMP_cc = Math::GMPq::__GMP_CC; $GMP_cflags = Math::GMPq::__GMP_CFLAGS; If Math::GMPq has been built against gmp-4.2.3 or later, returns respectively the CC and CFLAGS settings that were used to compile the gmp library against which Math::GMPq was built. (Values are as specified in the gmp.h that was used to build Math::GMPq.) Returns undef if Math::GMPq has been built against an earlier version of the gmp library. (These functions are in @EXPORT_OK and are therefore exportable by request. They are not listed under the ":mpq" tag.) $major = Math::GMPq::__GNU_MP_VERSION; $minor = Math::GMPq::__GNU_MP_VERSION_MINOR; $patchlevel = Math::GMPq::__GNU_MP_VERSION_PATCHLEVEL; Returns respectively the major, minor, and patchlevel numbers for the GMP library version used to build Math::GMPq. Values are as specified in the gmp.h that was used to build Math::GMPq. (These functions are in @EXPORT_OK and are therefore exportable by request. They are not listed under the ":mpq" tag.) ################ FORMATTED OUTPUT NOTE: The format specification can be found at: http://gmplib.org/manual/Formatted-Output-Strings.html#Formatted-Output-Strings However, the use of '*' to take an extra variable for width and precision is not allowed in this implementation. Instead, it is necessary to interpolate the variable into the format string - ie, instead of: Rmpq_printf("%*Zd\n", $width, $mpz); we need: Rmpq_printf("%${width}Zd\n", $mpz); $si = Rmpq_printf($format_string, $var); This function changed with the release of Math-GMPq-0.27. Now (unlike the GMP counterpart), it is limited to taking 2 arguments - the format string, and the variable to be formatted. That is, you can format only one variable at a time. If there is no variable to be formatted, then the final arg can be omitted - a suitable dummy arg will be passed to the XS code for you. ie the following will work: Rmpq_printf("hello world\n"); Returns the number of characters written, or -1 if an error occurred. $si = Rmpq_fprintf($fh, $format_string, $var); This function (unlike the GMP counterpart) is limited to taking 3 arguments - the filehandle, the format string, the variable to be formatted. That is, you can format only one variable at a time. If there is no variable to be formatted, then the final arg can be omitted - a suitable dummy arg will be passed to the XS code for you. ie the following will work: Rmpq_fprintf($fh, "hello world\n"); Other than that, the rules outlined above wrt Rmpq_printf apply. Returns the number of characters written, or -1 if an error occurred. $si = Rmpq_sprintf($buffer, $format_string, $var, $buflen); This function (unlike the GMP counterpart) is limited to taking 4 arguments - the buffer, the format string, the variable to be formatted and the size of the buffer. If there is no variable to be formatted, then the third arg can be omitted - a suitable dummy arg will be passed to the XS code for you. ie the following will work: Rmpf_sprintf($buffer, "hello world", 12); $buffer must be large enough to accommodate the formatted string. The formatted string is placed in $buffer. Returns the number of characters written, or -1 if an error occurred. $si = Rmpq_snprintf($buffer, $bytes, $format_string, $var, $buflen); Form a null-terminated string in $buffer. No more than $bytes bytes will be written. To get the full output, $bytes must be enough for the string and null-terminator. $buffer must be large enough to accommodate the string and null-terminator, and is truncated to the length of that string (and null-terminator). The return value is the total number of characters which ought to have been produced, excluding the terminating null. If $si >= $bytes then the actual output has been truncated to the first $bytes-1 characters, and a null appended. This function (unlike the GMP counterpart) is limited to taking 5 arguments - the buffer, the maximum number of bytes to be returned, the format string, the variable to be formatted and the size of the buffer. If there is no variable to be formatted, then the 4th arg can be omitted - a suitable dummy arg will be passed to the XS code for you. ie the following will work: Rmpf_snprintf($buffer, 6, "hello world", 12); ################ ################

You can get segfaults if you pass the wrong type of argument to the functions - so if you get a segfault, the first thing to do is to check that the argument types you have supplied are appropriate.

This program is free software; you may redistribute it and/or modify it under the same terms as Perl itself. Copyright 2006-2011, 2013-17, Sisyphus

Sisyphus <sisyphus at(@) cpan dot (.) org>

syntax highlighting: