PHP RFC: GMP Floating Point Support


@yohgaki suggested adding support for libgmp's arbitrary precision floating point numbers to the PHP extension, and I offered to implement it, so here's my proposal.

Proposal #1

Extend `gmp_object` struct to the following:

#define PHP_GMP_TYPE_INT 0
typedef struct _gmp_object {
  zend_object std;
  char type;
  union {
     mpz_t inum;
     mpf_t fnum;
} gmp_object;

The existing gmp_init() function will create a gmp_object with type == PHP_GMP_TYPE_INT.

Add gmp_init_float(int|string $number[, $base = 0]) to create a gmp_object with type == PHP_GMP_TYPE_FLOAT

Extend all other gmp_*() functions (and overload operators) to check type on the input object(s) and call the appropriate libgmp function and return the appropriate gmp_object type.

Add gmp_floatval(), gmp_isint(), gmp_isfloat(), and similar introspection functions.

Proposal #2

Rather than overload the GMP class for integer/float representations, organize Integer and Floating-Point GMP objects into a class heirarchy as so:

abstract class GMPNumber {}
class GMPInt extends GMPNumber {}
class GMPFloat extends GMPNumber {}

The same open questions exist for this approach (i.e. should int/int yield float?)

Backward Incompatible Changes

gmp_init_float() is being added to specifically avoid breakage in code currently supplying numbers which may (or may not) have decimal separators in them. Note that overloading gmp_init() to detect floating point numbers would also present a challenge as GMP parses numbers based on system locale which may use '.', ',', or other separators. Having a unique initializer avoids that problem.

Actor functions and operator overloads should remain unaffected (with one exception, below) as code producing gmp_objects now will continue to do so, with the single (invisible) addition of the type byte.

gmp_div() (aka gmp_div_q()), may result in a non-integer result. This function currently has three modes: GMP_ROUND_ZERO, GMP_ROUND_PLUSINF, GMP_ROUND_MINUSINF which define what to do with the leftover fractional portion. This proposal suggests adding GMP_ROUND_NONE which will produce a floating point GMP object. The existing three modes will continue to produce integer results.

gmp_div_qr() would not be modified to handle GMP_ROUND_NONE as it is specifically designed to return a remainder. It would, however, still need to be extended to handle division of floating point numbers with integer 'q' and floating point 'r' results.

Open Question: The division operator overload uses the default division mode of GMP_ROUND_ZERO. It may coincide with “The PHP Way” to change to GMP_ROUND_NONE so that floating-point results may be produced from expressions such as: gmp_init(3) / gmp_init(2) This has limited BC issues since operator overloading for GMP is very new.

Proposed PHP Version(s)

5.next (master branch)

php.ini Defaults

Add INI setting: gmp.default_precision=(libgmp-initial-default-precision)


  • Version 1.0: 2014-01-04 Initial Draft
  • Version 1.1: 2014-01-05 Added proposal #2


Pending discussion to decide what direction we should go.

rfc/gmp-floating-point.txt · Last modified: 2014/01/05 23:40 by pollita