crystal-lang / crystal

The Crystal Programming Language
https://crystal-lang.org
Apache License 2.0
19.32k stars 1.61k forks source link

Using MPFR for `BigFloat` #11410

Open HertzDevil opened 2 years ago

HertzDevil commented 2 years ago

The MPFR library addresses several deficiencies in the mpf_* functions provided by GMP:

So I think we should use that on top of GMP (we cannot replace it because GMP as a whole also provides BigInt and BigRational). MPFR provides functions to convert to and from GMP's mpf_t in case any Crystal code depends on LibGMP::MPF directly.

HertzDevil commented 2 years ago

I was thinking about how to bridge the differences between our rounding modes and MPFR's. MPFR defines seven:

Those rounding modes are available in almost every operation, where rounding occurs in the least significant bits in the mantissa, not just mpfr_round (round to integer). There is also a default rounding mode configurable by mpfr_set_default_rounding_mode, but it doesn't appear to be used by MPFR itself, and is only for the GMP MPF compatibility mode shown here. Thus it would make no sense to bind that function here, because adding MPFR to the standard library implies not using LibGMP::MPF at all.

I don't think the standard library would enjoy supplying a rounding mode parameter to every method on BigFloat. So outside of the few rounding-related methods, MPFR_RNDN should be passed to MPFR. #11097 might mean that we could roll our own default mode.

HertzDevil commented 1 year ago

One particular benefit is it provides mpfr_frexp which avoids an overflow in our current implementation of Math.frexp(BigFloat):

LibGMP.mpf_get_d_2exp(out exp, 2.to_big_f ** (UInt64::MAX // 2))
Errno.value # => Errno::EINVAL
exp         # => -9223372036854775808