View on GitHub

malachite

An arbitrary-precision arithmetic library for Rust.

Malachite for MPFR Users: Floats

This page maps the functions of MPFR’s floating-point type, mpfr_t, onto their Malachite counterpart: Float, from the malachite-float crate. It follows the organization of the MPFR Interface chapter of the MPFR manual, as of MPFR 4.2.2, and the mapping index lists the whole family of pages. The word-type and aliasing conventions of the GMP integers page apply here as well.

This page has a different character from the others. GMP and FLINT map onto types that Malachite designed independently; Float was designed to follow MPFR. Its documentation states the contract outright: Float uses “the same representation used by MPFR, and all Malachite functions produce exactly the same result as their counterparts in MPFR, unless otherwise noted”, and much of its arithmetic is ported directly from MPFR’s. The consequence for the mapping is that agreement here is usually exact, down to the rounding of the last bit and the sign of a zero, and the notes can spend their time on the exceptions. The other consequence is that this is the page with the most ✗ rows: Float is younger than its model, and the rows mark, function by function, what remains to be built.

Conventions

The representation

An mpfr_t and a Float are the same mathematical object: a radix-2 floating-point number with a sign, an arbitrary-precision normalized significand, and a bounded exponent, alongside the three special values shared with IEEE 754, signed zero, signed infinity, and NaN. The agreement extends to the fine print. “MPFR has a single kind of NaN and does not have subnormals”, and both statements are true of Float as well: one NaN with no payload, and gradual underflow only by explicit request, which for Malachite means never. Both libraries also place the radix point before the first digit of the significand, so that, as MPFR’s manual notes, “the exponent values in MPFR and in IEEE 754 differ by 1”; the number 1 has exponent 1 in both MPFR and Malachite. mpfr_t is a one-element array, the same pass-by-reference device as every _t on these pages.

Two structural differences are worth knowing from the start. First, in MPFR every variable carries a precision, including one holding NaN, an infinity, or a zero; in Malachite, only finite nonzero Floats have a precision, significand, or exponent. The rows touching mpfr_get_prec and mpfr_set_prec say what this means in practice. Second, the component types differ in fixity: mpfr_prec_t and mpfr_exp_t are configuration- and platform-dependent, while a Float’s precision is always a u64 and its exponent always an i32. A Float whose precision is 64 bits or less is stored inline, with no allocated memory, the same small-value economy as the other Malachite types.

One function, a family of spellings

An MPFR function reads its output precision from a variable the caller prepared: mpfr_log(rop, op, rnd) rounds into whatever precision rop was given. Malachite returns its results, so the precision travels as an argument, and each MPFR function corresponds to a family of spellings built from one base name. The exact counterpart of mpfr_log is ln_prec_round: op.ln_prec_round(prec, rm) returns the rounded result and the ternary value. From there the family abbreviates: ln_prec(prec) rounds to nearest, ln_round(rm) keeps the input’s precision, and the plain trait spelling op.ln() does both. Each has a _ref form that borrows instead of consuming, and an _assign form that mutates in place and returns the bare ternary value. The tables below list each row’s base name once and leave the family implied; operations that Rust spells through standard traits, like the arithmetic operators, are listed as traits, as on the other pages.

The ternary value

Nearly every MPFR function returns an int about which the manual says: “If the ternary value is zero, it means that the value stored in the destination variable is the exact result of the corresponding mathematical function”, and a positive or negative value means the stored result is greater or lower than the exact one. This is precisely an Ordering, and Malachite’s families return one: Equal for exact, Greater and Less for the two inexact directions. Both libraries are correctly rounding, behaving “as if it computed the result with an infinite precision, then rounded it to the precision of this variable”, and both regard input variables “as exact (in particular, their precision does not affect the result)”.

Rounding modes

MPFR Malachite
MPFR_RNDN (to nearest, ties to even) Nearest
MPFR_RNDZ (toward zero) Down
MPFR_RNDU (toward \(+\infty\)) Ceiling
MPFR_RNDD (toward \(-\infty\)) Floor
MPFR_RNDA (away from zero) Up
MPFR_RNDF (faithful)  

The five deterministic modes correspond exactly, ties-to-even rule included; only the names’ points of view differ, MPFR describing the direction on the number line and Malachite the effect on the absolute value. MPFR_RNDF, faithful rounding, which MPFR describes as “currently experimental”, has no counterpart. Malachite adds a sixth mode in the other direction: Exact panics if any rounding would occur, turning what an MPFR caller expresses by checking the ternary value into a mode of its own.

Precision

Precision belongs to each value in both libraries, and the floor is the same: “MPFR_PREC_MIN is equal to 1”, and Malachite’s prec arguments accept any nonzero u64, panicking on zero. At the top there is no practical difference; MPFR’s manual warns against approaching MPFR_PREC_MAX, and in both libraries the working limit is memory. What Malachite does not have is mpfr_set_default_prec’s global default precision: there is no implicit precision anywhere, and every function either takes prec explicitly or inherits the precision of its input. The rows for the default-precision functions are under Initialization Functions.

The exponent range

MPFR’s default exponent range is \([-(2^{30}-1), 2^{30}-1]\), and Malachite’s constants Float::MIN_EXPONENT and Float::MAX_EXPONENT are those same two numbers. The difference is that MPFR’s range is a mutable global, movable with mpfr_set_emin and mpfr_set_emax out to roughly \(\pm(2^{62}-1)\), while Malachite’s is fixed. Against a default-configured MPFR the two libraries overflow to infinity and underflow to zero at exactly the same boundaries, with the same ternary values; a program that widens MPFR’s range computes values that a Float cannot represent, and has no counterpart here. The functions that manage the range, and the flags raised at its edges, are treated together under Exception Related Functions.

Global state

The exponent range is one instance of a general pattern. MPFR keeps several pieces of global (in recent versions, thread-local) state: the default precision, the default rounding mode, the exponent range, the sticky exception flags, and internal caches for constants like π, freed with mpfr_free_cache. Malachite keeps none: precision and rounding mode are arguments, exactness is a return value, the range is fixed, and constants are computed at the requested precision on demand. Sections whose subject is that state, chiefly Exception Related Functions, are where this design difference is settled row by row.

Equality, and equality

Float’s == behaves like MPFR’s mpfr_equal_p: NaN is unequal to everything including itself, positive and negative zero are equal, and precision plays no part. When identity rather than numeric equality is wanted, Malachite wraps the value in ComparableFloat, under which NaN equals NaN, the zeros separate, and precision counts; this pairs with MPFR’s mpfr_total_order_p in the Comparison Functions section, where the differences between the two total orders are spelled out.

Categories

Each function falls into one of four categories:

  meaning
A Malachite function does the same thing.
A Malachite function serves the same purpose, but its specification differs. The notes say how.
No counterpart is needed, either because Rust handles it for you or because it is outside Malachite’s scope. The notes say which.
Malachite does not fully support this yet, but will in a future version.

Initialization Functions

The manual opens this section with a sentence that has no translation: “An mpfr_t object must be initialized before storing the first value in it.” A Float begins life holding a value, so most of these rows tell the familiar story from the other pages, with one new warning about a name that means different things in the two libraries.

  MPFR Malachite
void mpfr_init2 (mpfr_t x, mpfr_prec_t prec) Float::NAN
void mpfr_inits2 (mpfr_prec_t prec, mpfr_t x, ...)  
void mpfr_clear (mpfr_t x)  
void mpfr_clears (mpfr_t x, ...)  
void mpfr_init (mpfr_t x) Float::NAN
void mpfr_inits (mpfr_t x, ...)  
MPFR_DECL_INIT (name, prec)  
void mpfr_set_default_prec (mpfr_prec_t prec)  
mpfr_prec_t mpfr_get_default_prec (void)  
void mpfr_set_prec (mpfr_t x, mpfr_prec_t prec)  
mpfr_prec_t mpfr_get_prec (mpfr_t x) get_prec

mpfr_init, mpfr_init2, and the clearing family. let x = Float::NAN; produces the value that mpfr_init produces, and dropping replaces mpfr_clear, as usual. The ≈ on mpfr_init2 is its first half: “set its precision to be exactly prec bits and its value to NaN” assigns a precision to the NaN, and a Malachite NaN carries no precision, nor is there significand storage to size in advance, since every result manages its own. The variadic mpfr_inits2, mpfr_clears, and mpfr_inits, and the stack-allocating MPFR_DECL_INIT macro, are C conveniences with nothing left to abbreviate in a let.

mpfr_set_default_prec, mpfr_get_default_prec. The global default precision, 53 bits initially and thread-local in thread-safe builds, is a piece of state Malachite does not have: precision is always explicit, either an argument or the precision of an input. MPFR’s own manual describes the hazard of the global, warning that “some other libraries might change the default precision and not restore it. Thus it is safer to use mpfr_init2”; in Malachite there is no default to change, and nothing to restore.

mpfr_set_prec. A storage-management operation: reset the precision “and set its value to NaN. The previous value stored in x is lost”, equivalent to clear-then-init but reusing the allocation. Nothing corresponds, because destinations are not prepared in advance; spelled literally it is x = Float::NAN. The warning is the name: Float::set_prec is not this function. Malachite’s set_prec keeps the value, rounding it to the new precision and returning the ternary value, which is the behavior of MPFR’s mpfr_prec_round, treated with the other precision-changing functions under Rounding-Related Functions.

mpfr_get_prec. get_prec returns “the number of bits used to store its significand” as an Option: Some for a finite nonzero value, and None for a NaN, an infinity, or a zero, where mpfr_get_prec reports the precision the variable carries. This is the structural difference from the top of the page paying its first visit to a table.

Assignment Functions

“These functions assign new values to already initialized floats.” In Malachite there is no initialized-but-empty state to fill, so assignment and construction are the same act, and every mpfr_set_* maps to a constructor: from_TYPE_prec_round(op, prec, rm) returns the rounded Float and the ternary value, with the usual family of spellings around it, including plain From conversions that are exact. The generic constructors accept every width of primitive, so the _ui/_uj and _si/_sj distinctions collapse.

  MPFR Malachite
int mpfr_set (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd) from_float_prec_round, Clone
int mpfr_set_ui (mpfr_t rop, unsigned long int op, mpfr_rnd_t rnd) from_unsigned_prec_round
int mpfr_set_si (mpfr_t rop, long int op, mpfr_rnd_t rnd) from_signed_prec_round
int mpfr_set_uj (mpfr_t rop, uintmax_t op, mpfr_rnd_t rnd) from_unsigned_prec_round
int mpfr_set_sj (mpfr_t rop, intmax_t op, mpfr_rnd_t rnd) from_signed_prec_round
int mpfr_set_flt (mpfr_t rop, float op, mpfr_rnd_t rnd) from_primitive_float_prec_round
int mpfr_set_d (mpfr_t rop, double op, mpfr_rnd_t rnd) from_primitive_float_prec_round
int mpfr_set_ld (mpfr_t rop, long double op, mpfr_rnd_t rnd)  
int mpfr_set_float128 (mpfr_t rop, mpfr_float128 op, mpfr_rnd_t rnd)  
int mpfr_set_decimal64 (mpfr_t rop, _Decimal64 op, mpfr_rnd_t rnd)  
int mpfr_set_decimal128 (mpfr_t rop, _Decimal128 op, mpfr_rnd_t rnd)  
int mpfr_set_z (mpfr_t rop, mpz_t op, mpfr_rnd_t rnd) from_integer_prec_round
int mpfr_set_q (mpfr_t rop, mpq_t op, mpfr_rnd_t rnd) from_rational_prec_round
int mpfr_set_f (mpfr_t rop, mpf_t op, mpfr_rnd_t rnd)  
int mpfr_set_ui_2exp (mpfr_t rop, unsigned long int op, mpfr_exp_t e, mpfr_rnd_t rnd) IntegerMantissaAndExponent
int mpfr_set_si_2exp (mpfr_t rop, long int op, mpfr_exp_t e, mpfr_rnd_t rnd) IntegerMantissaAndExponent
int mpfr_set_uj_2exp (mpfr_t rop, uintmax_t op, intmax_t e, mpfr_rnd_t rnd) IntegerMantissaAndExponent
int mpfr_set_sj_2exp (mpfr_t rop, intmax_t op, intmax_t e, mpfr_rnd_t rnd) IntegerMantissaAndExponent
int mpfr_set_z_2exp (mpfr_t rop, mpz_t op, mpfr_exp_t e, mpfr_rnd_t rnd) IntegerMantissaAndExponent
int mpfr_set_str (mpfr_t rop, const char *s, int base, mpfr_rnd_t rnd) set_str
int mpfr_strtofr (mpfr_t rop, const char *nptr, char **endptr, int base, mpfr_rnd_t rnd) strtofr
void mpfr_set_nan (mpfr_t x) Float::NAN
void mpfr_set_inf (mpfr_t x, int sign) Float::INFINITY, Float::NEGATIVE_INFINITY
void mpfr_set_zero (mpfr_t x, int sign) Float::ZERO, Float::NEGATIVE_ZERO
void mpfr_swap (mpfr_t x, mpfr_t y)  

The mpfr_set family. Each source type has its constructor family, and the semantics carry over to the letter: the input is “regarded as exact”, the result is rounded once to prec, and a zero input becomes \(+0\) “regardless of the rounding mode” in both libraries. For mpfr_set itself, Float::from_float_prec_round(op, prec, rm) is the precision-changing copy, and a copy that keeps the precision is Clone; MPFR’s remark that the sign of a NaN is propagated has nothing to attach to here, there being only one NaN. The integer constructors are generic, so u64 covers mpfr_set_uj and u128 goes beyond it, and from_natural_prec_round exists alongside from_integer_prec_round for Naturals. The manual’s advice about decimal constants transfers unchanged: just as it recommends mpfr_set_str over mpfr_set_d, so that a constant is not “first converted into a reduced-precision (e.g., 53-bit) binary” value, Float::from(0.1f64) inherits the double’s rounding error, while parsing "0.1" at the target precision gives the correctly rounded constant.

The types Rust does not have. long double, mpfr_float128, _Decimal64, and _Decimal128 have no Rust counterparts, so their four rows are outside Malachite’s scope; MPFR itself treats most of them as optional, built only under configure options. mpfr_set_f is the GMP boundary again, in mpf_t form; the whole of GMP’s float type is taken up under Compatibility With MPF at the end of this page.

The _2exp constructors. \(op \cdot 2^e\) is assembled exactly by Float::from_integer_mantissa_and_exponent(m, e), from the IntegerMantissaAndExponent trait, with a word-sized op lifted by Natural::from and a negative one handled by negating the result; set_prec_round then supplies the rounding half of the MPFR semantics.

mpfr_set_str, mpfr_strtofr. The parsing engine is a port of MPFR’s, and the two entry points keep MPFR’s names. strtofr(s, base, prec, rm) reads the longest valid prefix and returns the value, the ternary value, and the number of bytes consumed, which is endptr as a count; when nothing parses, both libraries return zero, MPFR’s doc saying “for consistency with strtod”. The full grammar carries over: bases 2 through 62 with base 0 detecting 0b and 0x prefixes, e/p/@ exponent prefixes, and the nan, inf, and @nan@-style specials with their base-16 cutoff. set_str is the whole-string version, and its return conventions differ in Malachite’s usual direction: MPFR’s mpfr_set_str returns 0 or -1 and directs “users interested in the ternary value” to mpfr_strtofr, while Malachite’s returns Option<(Float, Ordering)>, keeping the ternary value in the success case. These two functions speak MPFR’s grammar; Malachite’s own string conversions, FromStr and the from_sci_string family, speak Malachite’s, and the grammars differ in corners such as the spelling of specials in high bases.

mpfr_set_nan, mpfr_set_inf, mpfr_set_zero. The five constants: Float::NAN, and the signed pairs Float::INFINITY/Float::NEGATIVE_INFINITY and Float::ZERO/Float::NEGATIVE_ZERO, the sign argument becoming a choice of constant. The manual leaves mpfr_set_nan’s sign bit unspecified, which the single NaN settles by having none.

mpfr_swap. std::mem::swap, which exchanges the values “without rounding” as mpfr_swap does; precisions travel with the values, and the warning about MPFR_DECL_INIT-allocated variables has no analogue, there being no allocation methods to mix.

Combined Initialization and Assignment Functions

As on the GMP pages, combining initialization with assignment is not a convenience in Rust but the only thing a binding can do, so this section maps onto the previous one. The first eight entries are macros, and what they add to mpfr_set_*, taking the precision “from the active default precision”, is the global that Malachite does not have; the precision is passed explicitly instead.

  MPFR Malachite
int mpfr_init_set (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd) from_float_prec_round, Clone
int mpfr_init_set_ui (mpfr_t rop, unsigned long int op, mpfr_rnd_t rnd) from_unsigned_prec_round
int mpfr_init_set_si (mpfr_t rop, long int op, mpfr_rnd_t rnd) from_signed_prec_round
int mpfr_init_set_d (mpfr_t rop, double op, mpfr_rnd_t rnd) from_primitive_float_prec_round
int mpfr_init_set_ld (mpfr_t rop, long double op, mpfr_rnd_t rnd)  
int mpfr_init_set_z (mpfr_t rop, mpz_t op, mpfr_rnd_t rnd) from_integer_prec_round
int mpfr_init_set_q (mpfr_t rop, mpq_t op, mpfr_rnd_t rnd) from_rational_prec_round
int mpfr_init_set_f (mpfr_t rop, mpf_t op, mpfr_rnd_t rnd)  
int mpfr_init_set_str (mpfr_t x, const char *s, int base, mpfr_rnd_t rnd) set_str

Each row behaves as its mpfr_set_* counterpart above does, including the two — rows, absent for the same reasons as there.

Conversion Functions

The outward direction. One theme runs through this section: where a conversion loses information or has no reasonable answer, MPFR reports through the sticky inexact and erange flags, and Malachite reports in the return value, with an Ordering for rounding, an Option or Result for failure, or a panic where the caller asked for something the value cannot do. The notes call out each case.

  MPFR Malachite
float mpfr_get_flt (mpfr_t op, mpfr_rnd_t rnd) RoundingFrom
double mpfr_get_d (mpfr_t op, mpfr_rnd_t rnd) RoundingFrom
long double mpfr_get_ld (mpfr_t op, mpfr_rnd_t rnd)  
mpfr_float128 mpfr_get_float128 (mpfr_t op, mpfr_rnd_t rnd)  
_Decimal64 mpfr_get_decimal64 (mpfr_t op, mpfr_rnd_t rnd)  
_Decimal128 mpfr_get_decimal128 (mpfr_t op, mpfr_rnd_t rnd)  
long int mpfr_get_si (mpfr_t op, mpfr_rnd_t rnd) RoundingFrom, TryFrom
unsigned long int mpfr_get_ui (mpfr_t op, mpfr_rnd_t rnd) RoundingFrom, TryFrom
intmax_t mpfr_get_sj (mpfr_t op, mpfr_rnd_t rnd) RoundingFrom
uintmax_t mpfr_get_uj (mpfr_t op, mpfr_rnd_t rnd) RoundingFrom
double mpfr_get_d_2exp (long *exp, mpfr_t op, mpfr_rnd_t rnd) sci_mantissa_and_exponent_round
long double mpfr_get_ld_2exp (long *exp, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_frexp (mpfr_exp_t *exp, mpfr_t y, mpfr_t x, mpfr_rnd_t rnd) SciMantissaAndExponent
mpfr_exp_t mpfr_get_z_2exp (mpz_t rop, mpfr_t op) IntegerMantissaAndExponent
int mpfr_get_z (mpz_t rop, mpfr_t op, mpfr_rnd_t rnd) RoundingFrom, TryFrom
void mpfr_get_q (mpq_t rop, mpfr_t op) TryFrom
int mpfr_get_f (mpf_t rop, mpfr_t op, mpfr_rnd_t rnd)  
size_t mpfr_get_str_ndigits (int b, mpfr_prec_t p)  
char * mpfr_get_str (char *str, mpfr_exp_t *expptr, int base, size_t n, mpfr_t op, mpfr_rnd_t rnd) get_str
void mpfr_free_str (char *str)  
int mpfr_fits_ulong_p (mpfr_t op, mpfr_rnd_t rnd) ConvertibleFrom
int mpfr_fits_slong_p (mpfr_t op, mpfr_rnd_t rnd) ConvertibleFrom
int mpfr_fits_uint_p (mpfr_t op, mpfr_rnd_t rnd) ConvertibleFrom
int mpfr_fits_sint_p (mpfr_t op, mpfr_rnd_t rnd) ConvertibleFrom
int mpfr_fits_ushort_p (mpfr_t op, mpfr_rnd_t rnd) ConvertibleFrom
int mpfr_fits_sshort_p (mpfr_t op, mpfr_rnd_t rnd) ConvertibleFrom
int mpfr_fits_uintmax_p (mpfr_t op, mpfr_rnd_t rnd) ConvertibleFrom
int mpfr_fits_intmax_p (mpfr_t op, mpfr_rnd_t rnd) ConvertibleFrom

mpfr_get_flt, mpfr_get_d, and the types Rust does not have. f32::rounding_from(&op, rnd) and f64::rounding_from(&op, rnd) return the rounded value together with the ternary value, which mpfr_get_d’s bare double return cannot carry. The special values travel intact, f64 having all of them: NaN to NaN, infinities with their signs, and zero signs preserved, which MPFR promises only “if possible”. long double, mpfr_float128, and the decimal types are absent from Rust, as under Assignment.

The integer conversions. u64::rounding_from(&op, rnd) and its signed and shorter kin round to an integer and return the ternary value, with TryFrom for the exact-only case; every width is covered, so the _ui/_uj split collapses again. The ≈ is what happens at the edges. MPFR never fails: a NaN becomes 0, an out-of-range value “returns the maximum or the minimum of the corresponding C type, depending on the direction of the overflow”, and the erange flag records the event. Malachite saturates only when the rounding mode points toward the violated bound, and panics otherwise, NaN included: the flag becomes either a defined answer or a loud failure, never a quiet wrong-looking one.

mpfr_get_d_2exp, mpfr_frexp. Both split a value into mantissa and exponent with the mantissa in \([0.5, 1)\), and here the exponent-convention offset from Conventions reappears in mantissa form: Malachite’s sci_mantissa_and_exponent_round produces a mantissa in \([1, 2)\), IEEE 754 style, so MPFR’s \((d, e)\) is Malachite’s \((m/2, e+1)\). The f64-mantissa form with a rounding mode answers mpfr_get_d_2exp; for mpfr_frexp, whose mantissa is a rounded Float, the SciMantissaAndExponent implementation with Float mantissas provides the split, and from_float_prec_round the rounding to y’s precision.

mpfr_get_z_2exp. The exact decomposition \(op = m \cdot 2^e\), with a difference in which \(m\) is chosen: MPFR returns the scaled significand “regarded as an integer, with the precision of op”, trailing zeros included, while integer_mantissa_and_exponent returns the minimal representative, an odd \(m\). The equation is the same and the pairs convert by shifting; code that relies on rop having exactly prec bits notices the difference.

mpfr_get_z, mpfr_get_q. Integer::rounding_from(&op, rnd) returns precisely the ternary value that mpfr_get_z returns, with Natural versions alongside; for both functions a NaN or infinity is a panic or an Err where MPFR sets erange and stores 0. mpfr_get_q “is always exact”, and so is Rational::try_from(&op), the same pairing seen from the other side on the GMP rationals page.

mpfr_get_str_ndigits, mpfr_get_str, mpfr_free_str. get_str is a port of mpfr_get_str and keeps its name and its whole specification: bases 2 to 62 and the negative range \(-2\) to \(-36\) for upper-case digits, kept by MPFR “for compatibility with GMP’s mpf_get_str function”; the digit string as a fraction with an implicit radix point and a separate exponent; @NaN@ and @Inf@; the ties-to-even rule applied to significands even in odd bases; and n = 0 requesting the round-trip digit count. It returns Option<(Vec<u8>, i64, Ordering)>, None standing in for the null-pointer return on an invalid base, and the ternary value coming along where MPFR only sets the inexact flag. mpfr_get_str_ndigits, the round-trip digit count \(m = 1 + \lceil p \log 2 / \log b \rceil\) itself, is implemented inside Malachite’s get_str but not yet exposed on its own, so its row is a gap. mpfr_free_str is the usual absence of manual deallocation.

The fits family. The eight C types collapse into the generic ConvertibleFrom implementations, with one specification difference: MPFR asks whether op fits “when rounded to an integer in the direction rnd”, so that, as the manual notes, \(-0.5\) fits an unsigned long under MPFR_RNDU, while u64::convertible_from(&op) asks whether the value is exactly representable, with no rounding step. To ask MPFR’s question, round first: Integer::rounding_from(&op, rnd) never fails on finite input, and the integer’s fit is then checked exactly. Check the exponent against the type’s width before rounding, though: mpfr_fits_ulong_p answers from the exponent in constant time, while the rounding step materializes the integer part, which is large when the exponent is; only a value within one step of a boundary of the type’s range needs it.

Arithmetic Functions

The operators carry this section: x + y through x / y with the *Assign and borrowing forms, and behind each operator the full family, add_prec_round, sub_prec_round, mul_prec_round, and div_prec_round, whose members return the ternary value. The IEEE 754 special-value rules, signed zeros included, hold on both sides down to the last case, since the arithmetic is ported. For the mixed-operand variants one recipe covers everything: Float::from(c) is exact for every scalar these functions take, an integer of any width, a double, or an Integer, so composing the conversion with the base operation reproduces the mixed function exactly, reversed forms like mpfr_ui_sub included. Rational operands do not even need the recipe: the operators take them directly, through families like add_rational_prec_round and, for the reversed division, rational_div_float_prec_round.

  MPFR Malachite
int mpfr_add (mpfr_t rop, mpfr_t op1, mpfr_t op2, mpfr_rnd_t rnd) Add, AddAssign
int mpfr_add_ui (mpfr_t rop, mpfr_t op1, unsigned long int op2, mpfr_rnd_t rnd) Add
int mpfr_add_si (mpfr_t rop, mpfr_t op1, long int op2, mpfr_rnd_t rnd) Add
int mpfr_add_d (mpfr_t rop, mpfr_t op1, double op2, mpfr_rnd_t rnd) Add
int mpfr_add_z (mpfr_t rop, mpfr_t op1, mpz_t op2, mpfr_rnd_t rnd) Add
int mpfr_add_q (mpfr_t rop, mpfr_t op1, mpq_t op2, mpfr_rnd_t rnd) Add
int mpfr_sub (mpfr_t rop, mpfr_t op1, mpfr_t op2, mpfr_rnd_t rnd) Sub, SubAssign
int mpfr_ui_sub (mpfr_t rop, unsigned long int op1, mpfr_t op2, mpfr_rnd_t rnd) Sub
int mpfr_sub_ui (mpfr_t rop, mpfr_t op1, unsigned long int op2, mpfr_rnd_t rnd) Sub
int mpfr_si_sub (mpfr_t rop, long int op1, mpfr_t op2, mpfr_rnd_t rnd) Sub
int mpfr_sub_si (mpfr_t rop, mpfr_t op1, long int op2, mpfr_rnd_t rnd) Sub
int mpfr_d_sub (mpfr_t rop, double op1, mpfr_t op2, mpfr_rnd_t rnd) Sub
int mpfr_sub_d (mpfr_t rop, mpfr_t op1, double op2, mpfr_rnd_t rnd) Sub
int mpfr_z_sub (mpfr_t rop, mpz_t op1, mpfr_t op2, mpfr_rnd_t rnd) Sub
int mpfr_sub_z (mpfr_t rop, mpfr_t op1, mpz_t op2, mpfr_rnd_t rnd) Sub
int mpfr_sub_q (mpfr_t rop, mpfr_t op1, mpq_t op2, mpfr_rnd_t rnd) Sub
int mpfr_mul (mpfr_t rop, mpfr_t op1, mpfr_t op2, mpfr_rnd_t rnd) Mul, MulAssign
int mpfr_mul_ui (mpfr_t rop, mpfr_t op1, unsigned long int op2, mpfr_rnd_t rnd) Mul
int mpfr_mul_si (mpfr_t rop, mpfr_t op1, long int op2, mpfr_rnd_t rnd) Mul
int mpfr_mul_d (mpfr_t rop, mpfr_t op1, double op2, mpfr_rnd_t rnd) Mul
int mpfr_mul_z (mpfr_t rop, mpfr_t op1, mpz_t op2, mpfr_rnd_t rnd) Mul
int mpfr_mul_q (mpfr_t rop, mpfr_t op1, mpq_t op2, mpfr_rnd_t rnd) Mul
int mpfr_sqr (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd) Square, SquareAssign
int mpfr_div (mpfr_t rop, mpfr_t op1, mpfr_t op2, mpfr_rnd_t rnd) Div, DivAssign
int mpfr_ui_div (mpfr_t rop, unsigned long int op1, mpfr_t op2, mpfr_rnd_t rnd) Div, Reciprocal
int mpfr_div_ui (mpfr_t rop, mpfr_t op1, unsigned long int op2, mpfr_rnd_t rnd) Div
int mpfr_si_div (mpfr_t rop, long int op1, mpfr_t op2, mpfr_rnd_t rnd) Div
int mpfr_div_si (mpfr_t rop, mpfr_t op1, long int op2, mpfr_rnd_t rnd) Div
int mpfr_d_div (mpfr_t rop, double op1, mpfr_t op2, mpfr_rnd_t rnd) Div
int mpfr_div_d (mpfr_t rop, mpfr_t op1, double op2, mpfr_rnd_t rnd) Div
int mpfr_div_z (mpfr_t rop, mpfr_t op1, mpz_t op2, mpfr_rnd_t rnd) Div
int mpfr_div_q (mpfr_t rop, mpfr_t op1, mpq_t op2, mpfr_rnd_t rnd) Div
int mpfr_sqrt (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd) Sqrt, SqrtAssign
int mpfr_sqrt_ui (mpfr_t rop, unsigned long int op, mpfr_rnd_t rnd) sqrt_unsigned_prec_round
int mpfr_rec_sqrt (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd) ReciprocalSqrt
int mpfr_cbrt (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd) Cbrt, CbrtAssign
int mpfr_rootn_ui (mpfr_t rop, mpfr_t op, unsigned long int n, mpfr_rnd_t rnd) root_u_prec_round, Root
int mpfr_rootn_si (mpfr_t rop, mpfr_t op, long int n, mpfr_rnd_t rnd) root_s_prec_round, Root
int mpfr_root (mpfr_t rop, mpfr_t op, unsigned long int n, mpfr_rnd_t rnd)  
int mpfr_neg (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd) Neg, NegAssign
int mpfr_abs (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd) Abs, AbsAssign
int mpfr_dim (mpfr_t rop, mpfr_t op1, mpfr_t op2, mpfr_rnd_t rnd)  
int mpfr_mul_2ui (mpfr_t rop, mpfr_t op1, unsigned long int op2, mpfr_rnd_t rnd) Shl, shl_prec_round
int mpfr_mul_2si (mpfr_t rop, mpfr_t op1, long int op2, mpfr_rnd_t rnd) Shl, shl_prec_round
int mpfr_div_2ui (mpfr_t rop, mpfr_t op1, unsigned long int op2, mpfr_rnd_t rnd) Shr, shr_prec_round
int mpfr_div_2si (mpfr_t rop, mpfr_t op1, long int op2, mpfr_rnd_t rnd) Shr, shr_prec_round
int mpfr_fac_ui (mpfr_t rop, unsigned long int op, mpfr_rnd_t rnd) Factorial, from_natural_prec_round
int mpfr_fma (mpfr_t rop, mpfr_t op1, mpfr_t op2, mpfr_t op3, mpfr_rnd_t rnd)  
int mpfr_fms (mpfr_t rop, mpfr_t op1, mpfr_t op2, mpfr_t op3, mpfr_rnd_t rnd)  
int mpfr_fmma (mpfr_t rop, mpfr_t op1, mpfr_t op2, mpfr_t op3, mpfr_t op4, mpfr_rnd_t rnd)  
int mpfr_fmms (mpfr_t rop, mpfr_t op1, mpfr_t op2, mpfr_t op3, mpfr_t op4, mpfr_rnd_t rnd)  
int mpfr_hypot (mpfr_t rop, mpfr_t x, mpfr_t y, mpfr_rnd_t rnd)  
int mpfr_sum (mpfr_t rop, const mpfr_ptr tab[], unsigned long int n, mpfr_rnd_t rnd)  
int mpfr_dot (mpfr_t rop, const mpfr_ptr a[], const mpfr_ptr b[], unsigned long int n, mpfr_rnd_t rnd)  

The operators and mixed forms. Thirty-two of these rows are the four operations across their operand types, and the section intro’s recipe disposes of them; mpfr_add_q and its kin are direct Add<Rational>-style implementations rather than conversions. Two of MPFR’s own remarks transfer directly: mpfr_sqr exists because squaring is faster than mpfr_mul on equal operands, and x.square() earns its keep the same way; and mpfr_ui_div with op1 = 1 is the reciprocal, which Malachite spells reciprocal_prec_round. Division by zero gives a signed infinity on both sides, with no exception beyond MPFR’s divide-by-zero flag.

The roots. sqrt follows IEEE 754, taking \(\sqrt{-0}\) to \(-0\) and negative values to NaN, in both libraries; sqrt_unsigned_prec_round is the ported mpfr_sqrt_ui, the square root of a u64. mpfr_rec_sqrt is ReciprocalSqrt, and MPFR’s warning carries over exactly: both libraries take \(\pm 0\) to \(+\infty\), which “is different from the one of the rSqrt function recommended by the IEEE 754 standard”. mpfr_rootn_ui and mpfr_rootn_si are root_u_prec_round and root_s_prec_round, with the plain trait spelling x.root(n), and the IEEE rootn sign rules, odd roots of negatives negative, even roots NaN, zeros by the limit rules, agree throughout. The deprecated mpfr_root, which differs from mpfr_rootn_ui only on \(-0\) with even n and “will be removed in a future release”, is left to its replacements.

mpfr_neg, mpfr_abs. Sign operations that, in MPFR, can also round, when rop has a smaller precision than op. Malachite’s -x and x.abs() keep the precision exactly; when the precision must change too, compose with from_float_prec_round. The remark that the sign rule “also applies to NaN in order to mimic the IEEE 754” behavior is vacuous here, the single NaN being signless.

mpfr_dim. The positive difference, \(op1 - op2\) if \(op1 > op2\), \(+0\) if \(op1 \le op2\), and NaN if either operand is NaN, is a gap. Until it exists, a comparison and a subtraction spell it out, with the NaN case handled first.

The 2exp family. x << k and x >> k are exact multiplications and divisions by \(2^k\), adjusting the exponent, and both directions accept signed and unsigned shift amounts as elsewhere in Malachite. The rounding mode in mpfr_mul_2ui’s signature matters only when the shifted value leaves the exponent range, and for that case the full forms shl_prec_round and shr_prec_round carry the mode and return the ternary value; the plain operators round to nearest at the boundary.

mpfr_fac_ui. The rounded factorial is a gap, though not for lack of a correct spelling: the factorial is exact in Natural, and Float::from_natural_prec_round(Natural::factorial(op), prec, rnd) produces exactly mpfr_fac_ui’s result. What it does not match is the cost. The composition computes every bit of the exact factorial before rounding once, while a dedicated implementation works at a precision near the target throughout, which is far cheaper when prec is small and op is large; the row is a gap until the dedicated version exists.

The fused operations. mpfr_fma, mpfr_fms, mpfr_fmma, and mpfr_fmms, the singly rounded \(op1 \cdot op2 \pm op3\) and \(op1 \cdot op2 \pm op3 \cdot op4\), are gaps, the same fused family promised on the FLINT integers page for exact integers. The separately rounded spelling &a * &b + &c computes a different, twice-rounded value, which is exactly what fusing exists to avoid; these rows are gaps rather than compositions.

mpfr_hypot. The Euclidean norm \(\sqrt{x^2 + y^2}\), with the C99 special-value rule that an infinite operand gives \(+\infty\) “even if the other number is NaN”, is a gap.

mpfr_sum, mpfr_dot. Correctly rounded sums and dot products of arrays, with a single rounding regardless of length. These are gaps, but exactness is available in the meantime by leaving the field: every finite Float converts exactly to a Rational, a Rational sum is exact, and from_rational_prec_round performs the one rounding, reproducing mpfr_sum on finite inputs, at exact-arithmetic cost. MPFR notes that mpfr_dot is experimental and “does not yet handle intermediate overflows and underflows”; the Rational route has neither.

Comparison Functions

As on every page of this family, comparison is where Malachite is at its most complete: the three-way comparisons and the IEEE predicates both exist for every operand type, so MPFR’s closing remark for this section, that the predicates compare only floats and “you may need to do a conversion first”, has nothing to attach to.

  MPFR Malachite
int mpfr_cmp (mpfr_t op1, mpfr_t op2) PartialOrd
int mpfr_cmp_ui (mpfr_t op1, unsigned long int op2) PartialOrd
int mpfr_cmp_si (mpfr_t op1, long int op2) PartialOrd
int mpfr_cmp_d (mpfr_t op1, double op2) PartialOrd
int mpfr_cmp_ld (mpfr_t op1, long double op2)  
int mpfr_cmp_z (mpfr_t op1, mpz_t op2) PartialOrd
int mpfr_cmp_q (mpfr_t op1, mpq_t op2) PartialOrd
int mpfr_cmp_f (mpfr_t op1, mpf_t op2)  
int mpfr_cmp_ui_2exp (mpfr_t op1, unsigned long int op2, mpfr_exp_t e) PartialOrd
int mpfr_cmp_si_2exp (mpfr_t op1, long int op2, mpfr_exp_t e) PartialOrd
int mpfr_cmpabs (mpfr_t op1, mpfr_t op2) PartialOrdAbs
int mpfr_cmpabs_ui (mpfr_t op1, unsigned long int op2) PartialOrdAbs
int mpfr_nan_p (mpfr_t op) is_nan
int mpfr_inf_p (mpfr_t op) is_infinite
int mpfr_number_p (mpfr_t op) is_finite
int mpfr_zero_p (mpfr_t op) is_zero
int mpfr_regular_p (mpfr_t op) is_normal
int mpfr_sgn (mpfr_t op) PartialOrd
int mpfr_greater_p (mpfr_t op1, mpfr_t op2) PartialOrd
int mpfr_greaterequal_p (mpfr_t op1, mpfr_t op2) PartialOrd
int mpfr_less_p (mpfr_t op1, mpfr_t op2) PartialOrd
int mpfr_lessequal_p (mpfr_t op1, mpfr_t op2) PartialOrd
int mpfr_equal_p (mpfr_t op1, mpfr_t op2) PartialEq
int mpfr_lessgreater_p (mpfr_t op1, mpfr_t op2) PartialOrd
int mpfr_unordered_p (mpfr_t op1, mpfr_t op2) PartialOrd
int mpfr_total_order_p (mpfr_t x, mpfr_t y) ComparableFloat

The mpfr_cmp family. x.partial_cmp(&y) compares the values exactly, each “considered to their full own precision”, and where mpfr_cmp handles NaN by “set the erange flag and return zero”, partial_cmp returns None, which has the small advantage of being distinguishable from Some(Equal) without consulting anything. The mixed comparisons are all direct implementations, against integers of every width, f64, an Integer, a Natural, or a Rational, always exact. For the _2exp pair, shift the operand into place first: Float::from(op2) << e is exact and costs only exponent arithmetic while e stays inside the exponent range, and outside it the comparison is settled by sign and magnitude before any shift is needed. mpfr_cmpabs and mpfr_cmpabs_ui are PartialOrdAbs, x.partial_cmp_abs(&y), comparing magnitudes without materializing either absolute value and answering NaN with None in the same way.

The classification predicates. Five names, one vocabulary shift: is_nan, is_infinite, is_finite for mpfr_number_p, is_zero, and is_normal for mpfr_regular_p. The last pair agree exactly because neither library has subnormals: normal means finite and nonzero on both sides.

mpfr_sgn. MPFR defines it as “equivalent to mpfr_cmp_ui (op, 0), but more efficient”, and the mapping takes the definition at its word: x.partial_cmp(&0u32), with either zero giving Some(Equal) and NaN giving None in place of the erange flag. A warning about a similar name: Float’s Sign implementation, x.sign(), is not mpfr_sgn but the sign bit: it never returns Equal, sends \(-0\) to Less and \(+0\) to Greater, and panics on NaN, which makes it the counterpart of mpfr_signbit, under Miscellaneous Functions.

The IEEE predicates. The five predicate functions are Rust’s comparison operators, exactly: >, >=, <, <=, and == on a partially ordered type “return zero whenever op1 and/or op2 is NaN”, which is precisely how Rust defines the operators through PartialOrd. The two combined predicates are one-liners over partial_cmp: mpfr_lessgreater_p is x < y || x > y, and mpfr_unordered_p is x.partial_cmp(&y).is_none().

mpfr_total_order_p. Both libraries offer a total order over all floats, and the two orders differ in instructive ways. ComparableFloat implements Ord, so ComparableFloat(x) <= ComparableFloat(y) plays the predicate’s role, with the full Ordering available where mpfr_total_order_p “returns a binary value”. The differences: IEEE 754’s totalOrder places the two signed NaNs at the ends, \(-\mathrm{NaN}\) below \(-\infty\) and \(+\mathrm{NaN}\) above \(+\infty\), and MPFR notes that “the sign bit of NaN also matters”, while Malachite’s single NaN sits between \(-0\) and \(+0\); and IEEE’s order ignores precision, while ComparableFloat refines equal values by it, ordering the greater precision further from zero, the same refinement its Eq and Hash use. On NaN-free data of uniform precision the two orders agree exactly.

Transcendental Functions

The largest section of the manual, and the one where the state of Malachite’s port is most visible: the logarithm, exponential, and power families are complete, while the trigonometric, hyperbolic, and special functions are the frontier, mapped below as gaps. Everything here returns the ternary value, and MPFR’s warning about cost applies to both libraries: “in some domains, computing transcendental functions (even more with correct rounding) is expensive, even in small precision”.

One note on names before the tables, since this section is where the two naming traditions diverge most. MPFR keeps C’s mathematical abbreviations, log, exp2, expm1, log1p; Malachite spells the operations out: the natural logarithm is ln, \(2^x\) is power_of_2, and the shifted variants append _x_minus_1 or insert _1_plus_x where C appends m1 or p1. The tables give the dictionary row by row.

Logarithms and exponentials

  MPFR Malachite
int mpfr_log (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd) ln_prec_round, Ln
int mpfr_log_ui (mpfr_t rop, unsigned long int op, mpfr_rnd_t rnd) ln_unsigned_prec_round
int mpfr_log2 (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd) log_base_2_prec_round, LogBase2
int mpfr_log10 (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd) log_base_10_prec_round, LogBase10
int mpfr_log1p (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd) ln_1_plus_x_prec_round, Ln1PlusX
int mpfr_log2p1 (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd) log_base_2_1_plus_x_prec_round, LogBase2Of1PlusX
int mpfr_log10p1 (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd) log_base_10_1_plus_x_prec_round, LogBase10Of1PlusX
int mpfr_exp (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd) exp_prec_round, Exp
int mpfr_exp2 (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd) power_of_2_of_float_prec_round, PowerOf2
int mpfr_exp10 (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd) power_of_10_of_float_prec_round, PowerOf10
int mpfr_expm1 (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd) exp_x_minus_1_prec_round, ExpXMinus1
int mpfr_exp2m1 (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd) power_of_2_x_minus_1_prec_round, PowerOf2XMinus1
int mpfr_exp10m1 (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd) power_of_10_x_minus_1_prec_round, PowerOf10XMinus1

The logarithms. All four are ports, ln_unsigned_prec_round being the binary-splitting mpfr_log_ui, the logarithm of a u64. The special-value rules carry over exactly: the logarithm of 1 is \(+0\) “in all rounding modes”, the logarithm of \(\pm 0\) is \(-\infty\) where “the sign of the zero has no influence on the result”, and negative arguments give NaN.

The shifted logarithms. ln_1_plus_x, log_base_2_1_plus_x, and log_base_10_1_plus_x compute \(\log_b(1+x)\) without forming \(1+x\), the standard device for keeping accuracy when \(x\) is near zero, and take \(-1\) to \(-\infty\) as their MPFR counterparts do.

The exponentials. exp is Exp; \(2^x\) and \(10^x\) are PowerOf2 and PowerOf10 applied to a Float exponent, the _of_float in the full method names distinguishing them from the exact power_of_2(u64) constructor. The m1 trio, \(b^x - 1\) accurately near zero, follows the same dictionary with _x_minus_1.

Exact rational arguments. Every function in this table also has a _rational companion, ln_rational_prec_round, power_of_2_rational_prec_round, and so on, which evaluates the function of an exact Rational argument with a single rounding. MPFR has no counterpart; the nearest spelling there converts the rational to a float first and accepts the intermediate rounding.

Powers

  MPFR Malachite
int mpfr_pow (mpfr_t rop, mpfr_t op1, mpfr_t op2, mpfr_rnd_t rnd) pow_prec_round, Pow
int mpfr_powr (mpfr_t rop, mpfr_t op1, mpfr_t op2, mpfr_rnd_t rnd) powr_prec_round
int mpfr_pow_ui (mpfr_t rop, mpfr_t op1, unsigned long int op2, mpfr_rnd_t rnd) pow_u_prec_round, Pow
int mpfr_pow_si (mpfr_t rop, mpfr_t op1, long int op2, mpfr_rnd_t rnd) pow_s_prec_round, Pow
int mpfr_pow_uj (mpfr_t rop, mpfr_t op1, uintmax_t op2, mpfr_rnd_t rnd) pow_u_prec_round
int mpfr_pow_sj (mpfr_t rop, mpfr_t op1, intmax_t op2, mpfr_rnd_t rnd) pow_s_prec_round
int mpfr_pown (mpfr_t rop, mpfr_t op1, intmax_t op2, mpfr_rnd_t rnd) pow_s_prec_round
int mpfr_pow_z (mpfr_t rop, mpfr_t op1, mpz_t op2, mpfr_rnd_t rnd) pow_integer_prec_round, Pow
int mpfr_ui_pow_ui (mpfr_t rop, unsigned long int op1, unsigned long int op2, mpfr_rnd_t rnd) unsigned_pow_unsigned_prec_round
int mpfr_ui_pow (mpfr_t rop, unsigned long int op1, mpfr_t op2, mpfr_rnd_t rnd) unsigned_pow_prec_round
int mpfr_compound_si (mpfr_t rop, mpfr_t op, long int n, mpfr_rnd_t rnd)  

mpfr_pow. pow_prec_round and the Pow trait, a port. The fifteen ISO C99 special-value rules the manual enumerates hold verbatim, including the two that surprise, pow(+1, y) returning 1 “for any y, even a NaN”, and pow(x, ±0) likewise; and both libraries detect exactly representable powers up front, so exact cases return Equal rather than looping toward an unreachable rounding decision.

mpfr_powr. IEEE 754’s other power, “the exponential of op2 multiplied by the logarithm of op1”: restricted to nonnegative bases, with NaN where pow’s rules would conjure a value from a negative base, and agreeing with pow wherever both are defined. powr_prec_round heads a family of inherent methods; there is no trait spelling, the Pow name being taken by pow’s semantics.

The integer exponents. pow_u_prec_round and pow_s_prec_round take any unsigned or signed width, collapsing pow_ui/pow_uj and pow_si/pow_sj; mpfr_pown collapses with them, being MPFR’s own alias for mpfr_pow_sj “to follow the C2x function pown”. A full Integer exponent goes to pow_integer_prec_round. All are reachable through Pow as well, with u64, i64, and Integer exponents.

The u64 bases. mpfr_ui_pow_ui and mpfr_ui_pow map to unsigned_pow_unsigned_prec_round and unsigned_pow_prec_round directly, integer-based powers computed at the target precision rather than exactly.

mpfr_compound_si. \((1+op)^n\), IEEE 754’s compound-interest function, accurate without forming \(1+op\), is a gap. The exact interim leaves the field as usual, and pays for it: Rational::from(op) + 1 is exact, its nth power is exact, and from_rational_prec_round rounds once, but the exact power grows with n where a dedicated implementation works at the target precision throughout.

Beyond MPFR. The power lattice fills in combinations MPFR does not have: a Rational exponent on a Float base (pow_rational_prec_round, with exact algebraic cases like rational powers of perfect powers detected and returned exactly), a Rational base under a Float exponent (rational_pow_prec_round), both at once (rational_pow_rational_prec_round), and a u64 base under a Rational exponent (unsigned_pow_rational_prec_round).

Trigonometric functions

  MPFR Malachite
int mpfr_cos (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_sin (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_tan (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_cosu (mpfr_t rop, mpfr_t op, unsigned long int u, mpfr_rnd_t rnd)  
int mpfr_sinu (mpfr_t rop, mpfr_t op, unsigned long int u, mpfr_rnd_t rnd)  
int mpfr_tanu (mpfr_t rop, mpfr_t op, unsigned long int u, mpfr_rnd_t rnd)  
int mpfr_cospi (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_sinpi (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_tanpi (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_sin_cos (mpfr_t sop, mpfr_t cop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_sec (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_csc (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_cot (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_acos (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_asin (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_atan (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_acosu (mpfr_t rop, mpfr_t op, unsigned long int u, mpfr_rnd_t rnd)  
int mpfr_asinu (mpfr_t rop, mpfr_t op, unsigned long int u, mpfr_rnd_t rnd)  
int mpfr_atanu (mpfr_t rop, mpfr_t op, unsigned long int u, mpfr_rnd_t rnd)  
int mpfr_acospi (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_asinpi (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_atanpi (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_atan2 (mpfr_t rop, mpfr_t y, mpfr_t x, mpfr_rnd_t rnd)  
int mpfr_atan2u (mpfr_t rop, mpfr_t y, mpfr_t x, unsigned long int u, mpfr_rnd_t rnd)  
int mpfr_atan2pi (mpfr_t rop, mpfr_t y, mpfr_t x, mpfr_rnd_t rnd)  

The family. Twenty-five rows, one gap: trigonometry is the next port after the exponential and power families, and none of it exists in Malachite yet, with no interim spelling to offer, correct rounding not being something a detour through f64 can provide. This is also the family MPFR’s cost warning names first: for large arguments the work is dominated by argument reduction, dividing out a \(2\pi\) known to enough precision, and that cost is intrinsic to the specification.

The u and pi variants. MPFR measures angles three ways: in radians, in turns scaled by u (mpfr_sinu computes the sine of \(op \times 2\pi/u\), so u = 360 “gets the… sine… for op in degrees”), and in half-turns (mpfr_sinpi and kin; mpfr_atan2pi “is the same as mpfr_atan2u with u = 2”). The scaled variants carry IEEE 754 exactness contracts that any future implementation inherits: mpfr_cosu returns \(+0\) at half-integers of \(op \times 2/u\) “so that the function is even”, and mpfr_sinu returns a zero with the sign of op at integers “so that the function is odd”, which means the rational points with exact answers must be detected rather than approached through ever-higher precision.

mpfr_sin_cos. Both values in one argument reduction. The C signature forces two rounded results into one int, “s + 4c”, zero “iff both results are exact”, and forbids aliasing between the outputs; a Rust return of two values with two ternary Orderings makes both constraints structural when this is built. mpfr_sec, mpfr_csc, and mpfr_cot are the reciprocal trio, gaps with their primaries.

The inverse functions. acos, asin, atan, their u and pi scalings, and the two-argument atan2 family with its twenty ISO C99 special cases, signed zeros along the axes and quarter-\(\pi\) values at the infinite corners. One remark from the manual is worth keeping for its subtlety, and will hold in Malachite too: acos(-1) rounds \(\pi\), and the rounded number “might not be in the output range” of the mathematical function; “still, the result lies in the image of the output range by the rounding function”.

Hyperbolic functions

  MPFR Malachite
int mpfr_cosh (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_sinh (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_tanh (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_sinh_cosh (mpfr_t sop, mpfr_t cop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_sech (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_csch (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_coth (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_acosh (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_asinh (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_atanh (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  

The family. Ten rows, one gap, but a different kind of gap from the trigonometric block above. The hyperbolic functions are algebraic combinations of the exponential machinery this page has already marked ✓: \(\sinh x = (e^x - e^{-x})/2\) with exp_x_minus_1 carrying the accuracy near zero, and \(\operatorname{atanh} x\) living the same way on ln_1_plus_x. There is no argument-reduction wall here; when these are built they will be layers over the ported exponential and logarithm cores. What keeps the rows at ✗ in the meantime is the usual seam: composing two correctly rounded steps rounds twice, and twice rounded is not correctly rounded. mpfr_sinh_cosh shares mpfr_sin_cos’s packed return value, zero “iff both results are exact”, and the same observation about a two-Ordering Rust signature applies; sech, csch, and coth are the reciprocal trio, and acosh, asinh, and atanh the inverses.

Special functions

  MPFR Malachite
int mpfr_eint (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_li2 (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_gamma (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_gamma_inc (mpfr_t rop, mpfr_t op, mpfr_t op2, mpfr_rnd_t rnd)  
int mpfr_lngamma (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_lgamma (mpfr_t rop, int *signp, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_digamma (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_beta (mpfr_t rop, mpfr_t op1, mpfr_t op2, mpfr_rnd_t rnd)  
int mpfr_zeta (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_zeta_ui (mpfr_t rop, unsigned long int op, mpfr_rnd_t rnd)  
int mpfr_erf (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_erfc (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_j0 (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_j1 (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_jn (mpfr_t rop, long int n, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_y0 (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_y1 (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_yn (mpfr_t rop, long int n, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_agm (mpfr_t rop, mpfr_t op1, mpfr_t op2, mpfr_rnd_t rnd) agm_prec_round
int mpfr_ai (mpfr_t rop, mpfr_t x, mpfr_rnd_t rnd)  

The special-function block. Eighteen gaps in one sweep: the exponential integral and the dilogarithm; the Gamma family, gamma, the upper incomplete gamma_inc, lngamma, lgamma, and digamma, with beta alongside; the Riemann zeta function, on a Float and on a u64; the error-function pair; and the Bessel functions of the first and second kinds at orders 0, 1, and n. One signature deserves a forward-looking remark: mpfr_lgamma returns the sign of \(\Gamma(op)\) through an out-parameter signp, which a Rust signature would fold into the return value alongside the ternary.

mpfr_agm. The arithmetic-geometric mean is ported: agm_prec_round, agreeing with MPFR down to the special-value fine print, NaN when “any operand is negative and the other one is not zero”, \(+0\) for a zero paired with a finite value, and NaN for a zero paired with an infinity. It is the engine under the logarithm family above, and the one inhabitant of this subsection that is already built.

mpfr_ai. The Airy function comes with a documented restriction in MPFR: “The current implementation is not intended to be used with large arguments. It works with \(|x|\) typically smaller than 500. For larger arguments, other methods should be used and will be implemented in a future version.” The gap recorded here is the whole function, all argument ranges: the large-argument regimes are reachable with asymptotic expansions carrying rigorous tail bounds, the far positive range collapses to an early underflow test, and the oscillatory negative range shares its argument-reduction machinery with the trigonometric family above, which it will naturally follow.

Constants

  MPFR Malachite
int mpfr_const_log2 (mpfr_t rop, mpfr_rnd_t rnd) ln_2_prec_round
int mpfr_const_pi (mpfr_t rop, mpfr_rnd_t rnd) pi_prec_round
int mpfr_const_euler (mpfr_t rop, mpfr_rnd_t rnd)  
int mpfr_const_catalan (mpfr_t rop, mpfr_rnd_t rnd)  

The constants. Float::ln_2_prec_round(prec, rnd) and Float::pi_prec_round(prec, rnd) compute \(\log 2\) and \(\pi\) to any requested precision, statically, where MPFR fills a prepared variable and caches the computation internally, the cache being the state behind mpfr_free_cache. Euler’s constant \(\gamma\) and Catalan’s constant are gaps, a slightly surprising pair of ✗ rows given the company they would keep: Malachite currently computes around three dozen constants, from \(e\), \(\tau\), \(\varphi\), and the square-root and logarithm families to the lemniscate, Gauss, Gelfond, and Ramanujan constants and digit-defined numbers like the Prouhet-Thue-Morse and prime constants, and MPFR’s remaining two will join them.

Input and Output Functions

As on every I/O section in this family, the FILE * half of these functions has no Rust counterpart to need: strings are the interface, and write! reaches any stream.

  MPFR Malachite
size_t mpfr_out_str (FILE *stream, int base, size_t n, mpfr_t op, mpfr_rnd_t rnd) Display, get_str
size_t mpfr_inp_str (mpfr_t rop, FILE *stream, int base, mpfr_rnd_t rnd) set_str
int mpfr_fpif_export (FILE *stream, mpfr_t op) Serialize
int mpfr_fpif_import (mpfr_t op, FILE *stream) Deserialize
void mpfr_dump (mpfr_t op) Debug

mpfr_out_str, mpfr_inp_str. The output function is mpfr_get_str with presentation: the same bases, 2 to 62 and \(-2\) to \(-36\), the same n = 0 digit-count default, and a fixed layout, first digit, locale-defined decimal point, remaining digits, then an exponent whose prefix is e in small bases and @ in large ones. In base 10, Display prints the value in Malachite’s own layout, which does not always show an exponent and always uses a period; for other bases and for MPFR’s exact layout, get_str supplies the digits and exponent and the caller places the point, which is the ≈. The input function reads a whitespace-delimited word and “parses it using mpfr_set_str”; with the word in hand, Malachite’s set_str is the same parse, so only the tokenizing is left to the caller.

mpfr_fpif_export, mpfr_fpif_import. MPFR’s interchange format and Malachite’s serde support answer the same need, moving floats between machines with the precision preserved: “one can export on a 32-bit computer and import on a 64-bit computer, or export on a little-endian computer and import on a big-endian computer”, and a Float serialized on any platform deserializes on any other, Limb width included. The encodings differ, a custom binary format, which MPFR marks experimental, against a textual form through serde, which composes with any serde format and carries the value, the precision, and the specials; the sign of NaN, which mpfr_fpif_export stores, does not exist here. Both sides validate on the way in, mpfr_fpif_import rejecting invalid precisions as Malachite’s deserialization rejects invalid values.

mpfr_dump. A debugging print in “some unspecified format” that “may change without breaking the ABI”; Malachite’s Debug is the same idea with the same non-promise, currently printing what Display prints. When the debugging question is about the representation rather than the value, the precision-revealing form is ComparableFloat’s Display, whose hexadecimal output makes precision visible.

Formatted Output Functions

MPFR extends printf with the R type: a conversion specification % [flags] [width] [.precision] R [rounding] conv formats an mpfr_t argument, with conv drawn from C99’s float conversions plus b for binary. Malachite splits the job along a natural seam. The R-conversion engine is ported: format_float_str(&x, "%.10RYf") takes one Float and one conversion specification and returns the formatted piece. Everything around it, the literal text, the other arguments, and the choice of sink, is Rust’s own format! and write!, which also retire the buffer-management distinctions that give this section most of its rows.

  MPFR Malachite
int mpfr_fprintf (FILE *stream, const char *template, ...) format_float_str, write!
int mpfr_vfprintf (FILE *stream, const char *template, va_list ap)  
int mpfr_printf (const char *template, ...) format_float_str, print!
int mpfr_vprintf (const char *template, va_list ap)  
int mpfr_sprintf (char *buf, const char *template, ...) format_float_str, format!
int mpfr_vsprintf (char *buf, const char *template, va_list ap)  
int mpfr_snprintf (char *buf, size_t n, const char *template, ...) format_float_str, format!
int mpfr_vsnprintf (char *buf, size_t n, const char *template, va_list ap)  
int mpfr_asprintf (char **str, const char *template, ...) format_float_str, format!
int mpfr_vasprintf (char **str, const char *template, va_list ap)  

The family. Ten functions, one engine. The five direct functions differ only in where the characters go, a stream, stdout, a caller’s buffer with or without a size limit, or an allocated string; in Rust the destination is write!’s first argument or format!’s returned String, and the truncating and allocating variants collapse. The va_list five are C’s variadic plumbing, and the Requirements subsection’s concerns, variadic support and header order, come with them. A row is ≈ rather than ✓ because the template string as a whole is not interpreted: each R conversion is formatted by format_float_str and spliced where {} puts it.

The conversion specification. format_float_str accepts MPFR’s grammar for a single conversion: the printf flags, width, and precision; the rounding characters, U for Ceiling, D for Floor, Y for Up (away from zero, “because ISO C reserves the A specifier for hexadecimal output”), Z for Down, and N for the default Nearest, with Exact additionally supported by the engine and panicking unless the digits represent the value exactly; and the conversions a/A, b, e/E, f/F, and g/G. The * rounding character, which in C fetches the mode from the argument list, has no argument list to fetch from in a single-value call. The missing-precision defaults carry over exactly: a, A, and b print “an exact representation with no trailing zeros”, e and E print the \(\lceil p \log 2/\log 10\rceil\) round-trip digit count “matching the choice done for mpfr_get_str”, and f, F, g, and G default to 6. A failed conversion returns None where MPFR returns \(-1\) with an errno.

Documented divergences. Two design-level differences, both downstream of decisions already on this page. A zero formatted with an empty precision under e-style conversions uses precision 1, since Malachite zeros carry no precision for the default to read. And the ' grouping flag always groups with a comma, where MPFR takes the separator from the locale, which in the default C locale is empty, so that MPFR prints no separators there at all.

The thinnest section of the mapping: rounding a Float to an integral Float, and the floating-point remainders, are eighteen gaps, with only the closing predicate already in place. The rows are expected to fill as a family.

  MPFR Malachite
int mpfr_rint (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_ceil (mpfr_t rop, mpfr_t op)  
int mpfr_floor (mpfr_t rop, mpfr_t op)  
int mpfr_round (mpfr_t rop, mpfr_t op)  
int mpfr_roundeven (mpfr_t rop, mpfr_t op)  
int mpfr_trunc (mpfr_t rop, mpfr_t op)  
int mpfr_rint_ceil (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_rint_floor (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_rint_round (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_rint_roundeven (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_rint_trunc (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_frac (mpfr_t rop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_modf (mpfr_t iop, mpfr_t fop, mpfr_t op, mpfr_rnd_t rnd)  
int mpfr_fmod (mpfr_t r, mpfr_t x, mpfr_t y, mpfr_rnd_t rnd)  
int mpfr_fmod_ui (mpfr_t r, mpfr_t x, unsigned long int y, mpfr_rnd_t rnd)  
int mpfr_fmodquo (mpfr_t r, long int* q, mpfr_t x, mpfr_t y, mpfr_rnd_t rnd)  
int mpfr_remainder (mpfr_t r, mpfr_t x, mpfr_t y, mpfr_rnd_t rnd)  
int mpfr_remquo (mpfr_t r, long int* q, mpfr_t x, mpfr_t y, mpfr_rnd_t rnd)  
int mpfr_integer_p (mpfr_t op) is_integer

Rounding to an integer. Eleven rows, two carefully distinguished semantics, both part of the gap. mpfr_rint and the five fixed-mode functions round op to a representable integer in a single rounding: “no double rounding is performed”, so 10.5 at 2-bit precision goes directly to 12, and the ternary value is refined beyond the usual convention, 0 for an integer representable as-is, \(\pm 1\) for an integer that had to be re-rounded, \(\pm 2\) for a non-integer. The mpfr_rint_* five are the same operations “regarded in the same way as any other mathematical function”: round to the integer first, then correctly round that integer to the target precision, so 6.5 under mpfr_rint_round at 2 bits becomes 7 and then 8. mpfr_round’s ties-away rule (roundTiesToAway) is also the one integer-rounding mode with no RoundingMode counterpart. Until the family exists, a guarded composition reproduces the rint_* semantics at fair cost: when op.get_exponent() is at least op.get_prec(), the value is already an integer and is its own answer; otherwise the integer part has fewer bits than the precision, and Integer::rounding_from(&op, rm) followed by from_integer_prec_round performs the two roundings explicitly. The single-rounding mpfr_rint contract is not reproduced by that composition; it is part of what the gap owes.

mpfr_frac, mpfr_modf. The fractional part, “having the same sign as op”, with rnd rounding the exact fraction rather than shaping it, and zero with op’s sign at integers and infinities; mpfr_modf packages the truncation and the fraction in one call with a mpfr_sin_cos-style packed return. Both fall with the family above, and compose the same way in the meantime, the exact fraction being a subtraction that the guard keeps cheap.

The remainders. \(r = x - ny\) with the quotient n “rounded toward zero” for the fmod three and “to the nearest integer (ties rounded to even)” for remainder and remquo, following ISO C99 F.9.7.1 for specials: NaN for infinite x or zero y, x rounded to r’s precision for infinite y, and a zero r taking x’s sign. The quo variants also report the quotient’s low bits with the sign of \(x/y\). The manual notes what makes these functions more than one-liners: “x may be so large in magnitude relative to y that an exact representation of the quotient is not practical”, so a dedicated implementation reduces the exponent gap modularly instead of materializing it, which is exactly what an exact Rational interim does not do; the exact route is correct and affordable only while the exponents of x and y stay close. MPFR points out that remainder and remquo “are useful for additive argument reduction”, which places this gap on the same road as the trigonometric family above.

mpfr_integer_p. The one row already filled: is_integer, via the IsInteger trait, true exactly when the value is an integer, NaN and infinities included on the false side.

  MPFR Malachite
void mpfr_set_default_rounding_mode (mpfr_rnd_t rnd)  
mpfr_rnd_t mpfr_get_default_rounding_mode (void)  
int mpfr_prec_round (mpfr_t x, mpfr_prec_t prec, mpfr_rnd_t rnd) set_prec_round, set_prec
int mpfr_can_round (mpfr_t b, mpfr_exp_t err, mpfr_rnd_t rnd1, mpfr_rnd_t rnd2, mpfr_prec_t prec)  
mpfr_prec_t mpfr_min_prec (mpfr_t x) get_min_prec
const char * mpfr_print_rnd_mode (mpfr_rnd_t rnd) Display
mpfr_round_nearest_away (foo, rop, op, ...)  

The default rounding mode. “To nearest initially”, and a global, so the pair of rows is — for the reason set out under Conventions: the rounding mode is an argument everywhere, or Nearest by the _prec families’ definition, and there is nothing to set or get.

mpfr_prec_round. The function that Malachite’s set_prec_round and set_prec actually correspond to, resolving the naming warning under Initialization Functions: round the value in place to a new precision, returning the ternary value. The manual demonstrates its role in a Newton iteration, sharpening and widening precision between steps, and the idiom transfers verbatim. Its remarks about significand storage, fresh limbs zero-filled on widening and no reallocation on narrowing, are C-side bookkeeping with no counterpart to need.

mpfr_can_round. The Ziv gate, exported: given an approximation b “of an unknown number x in the direction rnd1 with error at most two to the power EXP(b) − err”, decide whether x can be correctly rounded to prec in rnd2, treating the error as two-sided when rnd1 is nearest and promising that the check “does not modify its arguments”. Malachite runs the same test inside every Ziv loop on this page, through an internal port of MPFR’s own internal form of the check, but no public interface exists, so the row is a gap: the exported version, with the error-direction generality of rnd1, is what remains to build.

mpfr_min_prec. get_min_prec returns “the minimal number of bits required to store the significand” as an Option, None standing in for MPFR’s 0 “for special values, including 0”, the same shape as the mpfr_get_prec row.

mpfr_print_rnd_mode. RoundingMode implements Display and prints its own vocabulary, Nearest where MPFR prints "MPFR_RNDN"; the null pointer for an invalid mode has no counterpart, an enum having no invalid values.

mpfr_round_nearest_away. A macro that manufactures a rounding mode neither library offers: ties-away is not a supported member of mpfr_rnd_t any more than of RoundingMode, and MPFR expresses it only through dedicated devices, the mpfr_round function noted above and this macro, which computes foo twice to synthesize the rule for any function. The two libraries are at parity here, and the macro’s double-evaluation mechanics are C plumbing with nothing to abbreviate.

Miscellaneous Functions

  MPFR Malachite
void mpfr_nexttoward (mpfr_t x, mpfr_t y) increment, decrement
void mpfr_nextabove (mpfr_t x) increment
void mpfr_nextbelow (mpfr_t x) decrement
int mpfr_min (mpfr_t rop, mpfr_t op1, mpfr_t op2, mpfr_rnd_t rnd)  
int mpfr_max (mpfr_t rop, mpfr_t op1, mpfr_t op2, mpfr_rnd_t rnd)  
int mpfr_urandomb (mpfr_t rop, gmp_randstate_t state)  
int mpfr_urandom (mpfr_t rop, gmp_randstate_t state, mpfr_rnd_t rnd)  
int mpfr_nrandom (mpfr_t rop1, gmp_randstate_t state, mpfr_rnd_t rnd)  
int mpfr_grandom (mpfr_t rop1, mpfr_t rop2, gmp_randstate_t state, mpfr_rnd_t rnd)  
int mpfr_erandom (mpfr_t rop1, gmp_randstate_t state, mpfr_rnd_t rnd)  
mpfr_exp_t mpfr_get_exp (mpfr_t x) get_exponent
int mpfr_set_exp (mpfr_t x, mpfr_exp_t e) Shl
int mpfr_signbit (mpfr_t op) is_sign_negative
int mpfr_setsign (mpfr_t rop, mpfr_t op, int s, mpfr_rnd_t rnd) Abs, Neg
int mpfr_copysign (mpfr_t rop, mpfr_t op1, mpfr_t op2, mpfr_rnd_t rnd) Abs, Neg
const char * mpfr_get_version (void)  
MPFR_VERSION, MPFR_VERSION_NUM (major, minor, patchlevel)  
const char * mpfr_get_patches (void)  
int mpfr_buildopt_tls_p (void)  
int mpfr_buildopt_float128_p (void)  
int mpfr_buildopt_decimal_p (void)  
int mpfr_buildopt_gmpinternals_p (void)  
int mpfr_buildopt_sharedcache_p (void)  
const char * mpfr_buildopt_tune_case (void)  

The neighbor functions. MPFR’s stepping functions are “similar to the nextUp and nextDown operations from IEEE 754”, and Malachite’s increment and decrement do the same walk along the representable numbers at the value’s own precision, with mpfr_nexttoward recovered by comparing first and stepping second. Two differences make the rows ≈. MPFR’s functions are total: NaN passes through, zero steps to the smallest float of the appropriate sign, and the infinities act as endpoints, while increment and decrement panic on NaN, infinities, and zeros. And at a binade boundary the conventions part: stepping down from a power of two, decrement subtracts the ulp of the binade being left, taking a larger step than mpfr_nextbelow’s move to the nearest representable below.

mpfr_min, mpfr_max. Gaps with real content: these follow IEEE 754-2019’s minimumNumber and maximumNumber, where a single NaN operand is ignored, “the numeric value” is returned, only two NaNs produce NaN, and zeros of different signs order as \(-0 < +0\); the result is then rounded to rop’s precision. A spelled-out composition over partial_cmp must reproduce each of those rules, which is exactly why a dedicated pair belongs in the library.

The random generators. MPFR’s four are distribution samplers: mpfr_urandomb draws uniformly from \([0, 1)\) with exactly rop’s precision, mpfr_urandom behaves “as if a random real number is generated according to the continuous uniform distribution on the interval [0, 1] and then rounded”, and mpfr_nrandom and mpfr_erandom sample the standard normal and mean-one exponential distributions, correctly rounded. Malachite’s random module generates values for testing, streams with mean-parameterized precisions and exponents and striped bit patterns, the same philosophy noted on the FLINT rationals page; the distribution samplers are a genuine gap. mpfr_grandom is deprecated in favor of mpfr_nrandom, which MPFR notes is “much more efficient”, and rests with its replacement.

mpfr_get_exp, mpfr_set_exp. get_exponent returns the exponent under the same \([1/2, 1)\) significand convention set out under Conventions, answering None where MPFR declares the behavior “undefined” for NaN, infinities, and zero. Its inverse is a shift: x << (e - x.get_exponent().unwrap()) moves the exponent exactly, the signed shift amount reversing direction as needed. The ≈ is the failure mode at the edge of the exponent range, where mpfr_set_exp refuses and leaves x unchanged while a shift saturates by the rounding rules.

The sign functions. mpfr_signbit is is_sign_negative, with one NaN-shaped difference that costs nothing: MPFR reports the NaN’s stored sign bit, while the single signless NaN answers false. This is also where the Sign trait warning from Comparison Functions lands: x.sign() is the Ordering-valued reader of the same bit for non-NaN values. mpfr_setsign and mpfr_copysign are the absolute value with an optional negation, -op.abs() or op.abs() as the requested sign directs, with from_float_prec_round supplying the rounding when the precision changes too; their careful clauses about NaN signs have nothing to govern here.

Versions and build options. Nine rows of build metadata with no counterpart to need: Cargo pins and reports crate versions, so the runtime-versus-header comparison that mpfr_get_version exists to support cannot arise; patch tracking belongs to the package manager; and the build options either do not exist in Malachite, like the float128 and decimal types, or are visible in the types themselves, like the 32_bit_limbs limb choice. mpfr_buildopt_tune_case’s thresholds file has its analogue in Malachite’s tuning machinery, but as a development concern rather than a runtime query.

The section where the global-state design difference is settled row by row. MPFR keeps a movable exponent range and six sticky exception flags; Malachite fixes the range and returns each operation’s story with the operation. The result is a table of mostly — rows, each backed by a specific answer to “where did that information go”.

  MPFR Malachite
mpfr_exp_t mpfr_get_emin (void) Float::MIN_EXPONENT
mpfr_exp_t mpfr_get_emax (void) Float::MAX_EXPONENT
int mpfr_set_emin (mpfr_exp_t exp)  
int mpfr_set_emax (mpfr_exp_t exp)  
mpfr_exp_t mpfr_get_emin_min (void)  
mpfr_exp_t mpfr_get_emin_max (void)  
mpfr_exp_t mpfr_get_emax_min (void)  
mpfr_exp_t mpfr_get_emax_max (void)  
int mpfr_check_range (mpfr_t x, int t, mpfr_rnd_t rnd)  
int mpfr_subnormalize (mpfr_t x, int t, mpfr_rnd_t rnd)  
void mpfr_clear_underflow (void)  
void mpfr_clear_overflow (void)  
void mpfr_clear_divby0 (void)  
void mpfr_clear_nanflag (void)  
void mpfr_clear_inexflag (void)  
void mpfr_clear_erangeflag (void)  
void mpfr_clear_flags (void)  
void mpfr_set_underflow (void)  
void mpfr_set_overflow (void)  
void mpfr_set_divby0 (void)  
void mpfr_set_nanflag (void)  
void mpfr_set_inexflag (void)  
void mpfr_set_erangeflag (void)  
int mpfr_underflow_p (void) test_underflow
int mpfr_overflow_p (void) test_overflow
int mpfr_divby0_p (void)  
int mpfr_nanflag_p (void)  
int mpfr_inexflag_p (void)  
int mpfr_erangeflag_p (void)  
void mpfr_flags_clear (mpfr_flags_t mask)  
void mpfr_flags_set (mpfr_flags_t mask)  
mpfr_flags_t mpfr_flags_test (mpfr_flags_t mask)  
mpfr_flags_t mpfr_flags_save (void)  
void mpfr_flags_restore (mpfr_flags_t flags, mpfr_flags_t mask)  

The exponent range. mpfr_get_emin and mpfr_get_emax answer with Float::MIN_EXPONENT and Float::MAX_EXPONENT, the very values a default-configured MPFR reports, with the smallest positive value \(\tfrac{1}{2} \times 2^{emin}\) and the largest \((1 - \varepsilon) \times 2^{emax}\) in both libraries. The setters and the four mpfr_get_e*_min/_max bounds are — because the range does not move; and with them goes a class of hazard the manual spends paragraphs on, that after a range change “it is the user’s responsibility to check that any floating-point value used as an input is in the new exponent range”, on pain of undefined behavior. mpfr_check_range, which re-rounds a result computed under one range into another while propagating the ternary value, manages a seam that does not exist here.

mpfr_subnormalize. The tool for emulating gradual underflow, and through it whole IEEE formats; the manual’s example reproduces binary64 arithmetic by setting the range and subnormalizing every result. Malachite has no subnormals and no movable range, so the row is —; its own emulation needs are met the other way around, by crate-level helpers like emulate_float_to_float_fn that reproduce f32 and f64 results from Float computations.

The flags, translated. MPFR’s six sticky flags accumulate across a computation, thread locally, and are queried at the end; Malachite hands each operation’s report back with the operation, so the query functions map to information already in the caller’s hands, and the thirteen clear/set rows and five mpfr_flags_* group rows, machinery for managing and restoring the accumulator, have nothing to manage. The dictionary, flag by flag:

What stickiness itself buys, one query after a long computation, is folded by hand here: a sequence of operations tests each step, or carries the disjunction along. That is the honest cost of statelessness, paid for the usual gains, no thread-local state to save and restore, which is what mpfr_flags_save and mpfr_flags_restore exist to do.

Memory Handling Functions

  MPFR Malachite
void mpfr_free_cache (void)  
void mpfr_free_cache2 (mpfr_free_cache_t way)  
void mpfr_free_pool (void)  
int mpfr_mp_memory_cleanup (void)  

The caches and pools. Four rows of maintenance for state Malachite does not keep. MPFR caches computed constants and pools working memory, thread-locally and globally, and asks that mpfr_free_cache be called “before terminating a thread, even if you did not call mpfr_const_* functions directly (they could have been called internally)”. Malachite computes constants on demand at the requested precision and frees every allocation when its owner drops, so there is nothing to remember to free; mpfr_mp_memory_cleanup’s handshake with GMP’s mp_set_memory_functions belongs to the C allocator world.

Compatibility With MPF

This section is where the mapping index’s promise about GMP’s float type is kept: GMP’s manual steers new projects toward MPFR, and the road from mpf_t runs through this page. MPFR ships a header, mpf2mpfr.h, that recompiles many MPF programs unchanged, and its list of caveats is a fair summary of what an mpf_t user gains by moving to either library: exact-bit precision where MPF’s is a lower bound, a defined exponent range, and different output formatting. The section’s five functions exist for that compatibility layer.

  MPFR Malachite
void mpfr_set_prec_raw (mpfr_t x, mpfr_prec_t prec)  
int mpfr_eq (mpfr_t op1, mpfr_t op2, unsigned long int op3)  
void mpfr_reldiff (mpfr_t rop, mpfr_t op1, mpfr_t op2, mpfr_rnd_t rnd)  
int mpfr_mul_2exp (mpfr_t rop, mpfr_t op1, unsigned long int op2, mpfr_rnd_t rnd) Shl
int mpfr_div_2exp (mpfr_t rop, mpfr_t op1, unsigned long int op2, mpfr_rnd_t rnd) Shr

The five functions. mpfr_set_prec_raw is mpfr_set_prec’s undefined-behavior sibling, managing storage that manages itself here. mpfr_eq, an MPF-style first-n-bits comparison, comes with MPFR’s own advice not to use it, and its warning that “1.011111 and 1.100000 are regarded as different for any value of op3 larger than 1” explains why no counterpart is wanted; numeric closeness is a subtraction and a comparison. mpfr_reldiff computes \(|op1 - op2|/op1\) with no correct-rounding guarantee, which is exactly what writing the formula out achieves. The 2exp pair are, in the manual’s words, “identical to mpfr_mul_2ui and mpfr_div_2ui”, and map as those rows do.

Custom Interface

  MPFR Malachite
size_t mpfr_custom_get_size (mpfr_prec_t prec)  
void mpfr_custom_init (void *significand, mpfr_prec_t prec)  
void mpfr_custom_init_set (mpfr_t x, int kind, mpfr_exp_t exp, mpfr_prec_t prec, void *significand)  
int mpfr_custom_get_kind (mpfr_t x)  
void * mpfr_custom_get_significand (mpfr_t x)  
mpfr_exp_t mpfr_custom_get_exp (mpfr_t x)  
void mpfr_custom_move (mpfr_t x, void *new_position)  

The interface. An escape hatch for applications that “use a stack to handle the memory and their objects”, building mpfr_t values over caller-owned storage with the caller responsible for every allocation and its lifetime. Rust draws the ownership lines differently: a Float owns its significand, values below 65 bits of precision live inline without allocating, and reclamation is Drop rather than “garbaging the used memory”. The interface’s components, sizing, placement, kind and significand access, and relocation, are C memory management with no seam to attach to; the readable parts of a Float, the significand, exponent, and classification, are reached through the ordinary accessors this page has already mapped.