How Malachite Is Tested: Naturals
This page lists every public function of
Natural, the
unsigned integer type of the malachite-nz crate, and records which independent implementations it
is checked against. The introduction describes the oracles and the testing they
sit in; this page is the ledger. It follows the organization of the crate’s documentation, one
section per module, so that a function is where its documentation is.
Reading the tables
Each row is one operation, named after the module that implements it and linked to that module’s
documentation. The Functions column lists the traits and methods the module implements; a
trait’s by-value and by-reference implementations, and its *Assign form, count as one function,
since they compute the same thing, while functions with genuinely different results (div_mod
against div_rem, Add against Sum) are listed separately. The remaining columns are the
oracles of the introduction:
| meaning | |
|---|---|
| ✓ | The oracle computes this function and agrees with Malachite on every input tried. |
| ≈ | The oracle agrees, after an adaptation on the oracle side that is more than a change of spelling: a convention of Malachite’s that the oracle does not share is applied to the oracle’s output before the comparison. The mapping pages say what the adaptation is. |
| The oracle does not check this function. |
A function with no mark in any column is checked only by Malachite’s own unit and property tests. Those rows are collected at the end of the page, in What is not yet cross-checked, which is the list of what the oracles, Azurite first, should gain next.
Functions that are not part of the public interface are not listed: the limbs_* functions that
operate on limb slices and the other #[doc(hidden)] helpers are exercised by the same runs as
the functions built on them, but they are implementation details.
Basic
The constants and the standard traits of the type itself, from
malachite_nz::natural.
| Operation | Functions | Azurite | FLINT | GMP | num | Reference |
|---|---|---|---|---|---|---|
| constants | Zero, One, Two, Min |
|||||
| default | Default |
|||||
| named | Named |
The constants are the values 0, 1, and 2, and MIN is 0; every oracle run uses them on
the way to checking something else, but no run checks them as such. Named gives the type’s name
as a string and has nothing to compare against.
Comparison
From
malachite_nz::natural::comparison.
| Operation | Functions | Azurite | FLINT | GMP | num | Reference |
|---|---|---|---|---|---|---|
| cmp | Ord, PartialOrd |
✓ | ✓ | ✓ | ||
| cmp | cmp_normalized |
✓ | ✓ | |||
| cmp | cmp_normalized_no_shift |
|||||
| cmp_double | OrdDouble, PartialOrdDouble |
|||||
| eq | PartialEq, Eq |
✓ | ✓ | ✓ | ||
| hash | Hash |
|||||
| partial_cmp_primitive_int | PartialOrd<u8>, …, PartialOrd<isize>, and the reverse directions |
✓ | ✓ | ✓ | ||
| partial_eq_primitive_int | PartialEq<u8>, …, PartialEq<isize>, and the reverse directions |
✓ | ✓ | ✓ | ||
| partial_cmp_primitive_float | PartialOrd<f32>, PartialOrd<f64>, and the reverse directions |
✓ | ||||
| partial_eq_primitive_float | PartialEq<f32>, PartialEq<f64>, and the reverse directions |
✓ | ||||
| partial_cmp_abs_primitive_int | PartialOrdAbs<u8>, …, PartialOrdAbs<isize>, and the reverse directions |
✓ | ||||
| eq_abs_primitive_int | EqAbs<u8>, …, EqAbs<isize>, and the reverse directions |
|||||
| partial_cmp_abs_primitive_float | PartialOrdAbs<f32>, PartialOrdAbs<f64>, and the reverse directions |
|||||
| eq_abs_primitive_float | EqAbs<f32>, EqAbs<f64>, and the reverse directions |
cmp is checked by Azurite’s AzNat.compare and by GMP and num on the same inputs, and eq by
Azurite’s structural equality and by GMP and num. cmp_normalized, the comparison of two values
after aligning their leading bits, is checked by Azurite’s normalizedCompare and a reference
implementation that shifts and compares; its _no_shift variant, which assumes the alignment has
been done, is not. The comparisons and equalities with primitive integers, in both directions, are
checked by Azurite’s compareUInt64 and beqUInt64 (every natural being greater than a negative
primitive) and against GMP, and the integer ones against num as well; the comparisons with floats
are checked against GMP, which converts the float exactly. The magnitude comparisons (EqAbs,
PartialOrdAbs) are the plain comparisons on a type with no sign, and only the integer
PartialOrdAbs is cross-checked, against GMP; the others are currently covered by property tests
alone.
Arithmetic
From
malachite_nz::natural::arithmetic.
The module is large, so its rows are grouped by theme.
Addition, subtraction, and multiplication
| Operation | Functions | Azurite | FLINT | GMP | num | Reference |
|---|---|---|---|---|---|---|
| add | Add |
✓ | ✓ | ✓ | ||
| add | Sum |
✓ | ||||
| sub | Sub |
✓ | ✓ | ✓ | ||
| checked_sub | CheckedSub |
✓ | ✓ | |||
| saturating_sub | SaturatingSub |
✓ | ||||
| abs_diff | AbsDiff |
|||||
| neg | Neg |
✓ | ✓ | ✓ | ||
| mul | Mul |
✓ | ✓ | ✓ | ||
| mul | Product |
✓ | ||||
| square | Square |
✓ | ||||
| abs_squared | AbsSquared |
|||||
| add_mul | AddMul |
|||||
| sub_mul | SubMul |
|||||
| checked_sub_mul | CheckedSubMul |
|||||
| saturating_sub_mul | SaturatingSubMul |
|||||
| mul_add_mul | MulAddMul |
|||||
| mul_sub_mul | MulSubMul |
|||||
| checked_mul_sub_mul | CheckedMulSubMul |
|||||
| saturating_mul_sub_mul | SaturatingMulSubMul |
|||||
| average | Average |
|||||
| average | AverageRound |
The four basic operations are checked by Azurite (AzNat.add, sub, mul, square) and by GMP
and num, and saturating_sub by Azurite, whose subtraction truncates at zero exactly as
saturating_sub does; Malachite’s - panics where the difference would be negative, so the lines
it prints are differences that AzNat.sub computes exactly. Sum and Product are checked against
a reference implementation that folds + and * one term at a time, and Neg, which turns a
Natural into an Integer, by Azurite’s AzInt.neg and against GMP and num. The fused operations
(add_mul, sub_mul, mul_add_mul, and their checked and saturating forms), abs_diff,
abs_squared, and average are not yet cross-checked: their property tests compare them with the
unfused combinations of operations that are, which is a strong check but not an independent one.
Shifts
| Operation | Functions | Azurite | FLINT | GMP | num | Reference |
|---|---|---|---|---|---|---|
| shl | Shl<u8>, …, Shl<isize> |
✓ | ✓ | ✓ | ||
| shr | Shr<u8>, …, Shr<isize> |
✓ | ✓ | ✓ | ||
| shl_round | ShlRound<i8>, …, ShlRound<isize> |
|||||
| shr_round | ShrRound<u8>, …, ShrRound<isize> |
✓ | ||||
| mul_shr_round | MulShrRound |
|||||
| round_to_multiple_of_power_of_2 | RoundToMultipleOfPowerOf2 |
Shifting by a primitive integer is checked by Azurite’s shiftLeft and shiftRight for every shift
type, a negative count reversing the direction, and against GMP; the unsigned shifts also against
num. shr_round, which shifts right and rounds the result in a given mode, is checked by Azurite’s
shiftRightRound for every primitive shift type, a negative shift count being a left shift; the
Exact mode, which Azurite does not have, is checked as “the shift is exact and the Ordering is
Equal”.
Division
| Operation | Functions | Azurite | FLINT | GMP | num | Reference |
|---|---|---|---|---|---|---|
| div | Div |
✓ | ✓ | ✓ | ||
| div | CheckedDiv |
✓ | ||||
| div_mod | DivMod, DivRem |
✓ | ✓ | ✓ | ||
| div_mod | CeilingDivNegMod |
✓ | ||||
| div_mod | DivModPrecomputed |
|||||
| mod_op | Mod, Rem |
✓ | ✓ | ✓ | ||
| mod_op | NegMod |
✓ | ||||
| div_euclidean | DivEuclidean |
✓ | ||||
| mod_euclidean | ModEuclidean |
✓ | ||||
| div_mod_euclidean | DivModEuclidean |
✓ | ||||
| div_exact | DivExact |
✓ | ||||
| div_round | DivRound |
✓ | ✓ | ✓ | ||
| divisible_by | DivisibleBy |
✓ | ✓ | ✓ | ||
| round_to_multiple | RoundToMultiple |
|||||
| balanced_mod | BalancedMod |
Truncating division is checked three ways: /, div_mod, div_rem, %, and mod_op (which
coincide on naturals) against Azurite’s div, mod, and divMod, and against GMP and num. The
Euclidean forms, which also coincide with the truncating ones on naturals, and divisible_by are
checked by Azurite’s divMod and mod as well. div_round is checked by Azurite’s divRound in
every rounding mode, Exact being checked as an exact division, and against GMP. The forms that
round the quotient up (ceiling_div_neg_mod, neg_mod), div_exact, and divisible_by are
checked against GMP. DivModPrecomputed, which reuses a precomputed inverse of the divisor, is
compared with div_mod, and balanced_mod, the remainder in \((-m/2, m/2]\), is tested with the
integer version.
Signs, units, and parity
| Operation | Functions | Azurite | FLINT | GMP | num | Reference |
|---|---|---|---|---|---|---|
| sign | Sign |
✓ | ||||
| parity | Parity |
✓ | ||||
| is_unit | IsUnit |
|||||
| conjugate | Conjugate |
|||||
| canonicalize_unit | CanonicalizeUnit |
|||||
| canonical_unit_i_pow | CanonicalUnitIPow |
sign is checked against GMP and even/odd against Azurite’s isEven/isOdd. The unit
functions (is_unit, conjugate, canonicalize_unit, canonical_unit_i_pow) are the trivial
cases of functions that matter for Gaussian integers and polynomials, where they are cross-checked.
Modular arithmetic
The functions that take a modulus \(m\) and require their inputs to be reduced modulo it.
| Operation | Functions | Azurite | FLINT | GMP | num | Reference |
|---|---|---|---|---|---|---|
| mod_is_reduced | ModIsReduced |
✓ | ||||
| mod_add | ModAdd |
✓ | ||||
| mod_sub | ModSub |
✓ | ||||
| mod_neg | ModNeg |
✓ | ||||
| mod_mul | ModMul |
✓ | ||||
| mod_mul | ModMulPrecomputed |
✓ | ||||
| mod_square | ModSquare |
✓ | ||||
| mod_square | ModSquarePrecomputed |
✓ | ||||
| mod_pow | ModPow |
✓ | ✓ | ✓ | ✓ | |
| mod_pow | ModPowPrecomputed |
✓ | ||||
| mod_shl | ModShl<u8>, …, ModShl<isize> |
✓ | ||||
| mod_shr | ModShr<i8>, …, ModShr<isize> |
✓ | ||||
| mod_inverse | ModInverse |
✓ | ✓ | |||
| mod_div | ModDiv |
≈ | ✓ | ✓ | ||
| mod_div_list | ModDivList |
✓ | ✓ | |||
| mod_sqrt | ModSqrt |
≈ | ||||
| eq_mod | EqMod |
✓ | ✓ |
Azurite checks the whole family through its residue type AzZMod m, whose invariant (a value in
\([0, m)\)) is the precondition these functions assert, so every input is first checked to be
reduced: addition, subtraction, negation, multiplication, squaring, powers, shifts, inverses, and
the three _precomputed variants, which are compared with Azurite’s plain operations since the
precomputed data affects only speed. mod_pow is also checked against GMP’s and num’s modular
exponentiation and a square-and-multiply reference, and mod_inverse against a reference
extended-Euclid inverse.
mod_div is ≈ for Azurite because the quotient is not unique when the divisor is not a unit:
Malachite documents that it returns one of the quotients, so the oracle checks the documented
existence condition (\(\gcd(y, m) \mid x\)) and that the printed quotient \(q\) satisfies
\(qy \equiv x \pmod m\), rather than comparing values. FLINT’s fmpz_mod_divides makes the same
choice of quotient as Malachite and is compared exactly. mod_sqrt is ≈ for FLINT because for
even moduli between 50 and 600 FLINT’s fmpz_sqrtmod calls a Jacobi symbol routine with an even
modulus, whose behavior is undefined; that documented window is skipped, and every other input,
every odd modulus included, is compared exactly.
Arithmetic modulo a power of 2
| Operation | Functions | Azurite | FLINT | GMP | num | Reference |
|---|---|---|---|---|---|---|
| mod_power_of_2 | ModPowerOf2 |
✓ | ||||
| mod_power_of_2 | RemPowerOf2 |
✓ | ||||
| mod_power_of_2 | NegModPowerOf2 |
✓ | ||||
| mod_power_of_2_is_reduced | ModPowerOf2IsReduced |
✓ | ||||
| mod_power_of_2_add | ModPowerOf2Add |
✓ | ||||
| mod_power_of_2_sub | ModPowerOf2Sub |
✓ | ||||
| mod_power_of_2_neg | ModPowerOf2Neg |
✓ | ||||
| mod_power_of_2_mul | ModPowerOf2Mul |
✓ | ||||
| mod_power_of_2_square | ModPowerOf2Square |
✓ | ||||
| mod_power_of_2_pow | ModPowerOf2Pow |
✓ | ✓ | |||
| mod_power_of_2_inverse | ModPowerOf2Inverse |
✓ | ||||
| mod_power_of_2_shl | ModPowerOf2Shl<u8>, …, ModPowerOf2Shl<isize> |
✓ | ||||
| mod_power_of_2_shr | ModPowerOf2Shr<i8>, …, ModPowerOf2Shr<isize> |
✓ | ||||
| eq_mod_power_of_2 | EqModPowerOf2 |
✓ | ✓ |
Azurite checks these through its type AzZModPow2 k, the residues modulo \(2^k\), in the same way
as the general family, and ModPowerOf2 and rem_power_of_2 (which coincide on naturals) through
AzNat.modPow2; neg_mod_power_of_2, which takes any natural, is checked as the negation in
AzZModPow2 k of its residue. mod_power_of_2_pow is also checked against a square-and-multiply
reference, and eq_mod_power_of_2 against GMP’s is_congruent_2pow.
Chinese remaindering
| Operation | Functions | Azurite | FLINT | GMP | num | Reference |
|---|---|---|---|---|---|---|
| crt | Crt |
✓ | ✓ | ✓ | ||
| multi_crt | Natural::multi_crt, MultiCrt::new, MultiCrt::apply |
✓ | ✓ | ✓ | ||
| multi_crt | MultiCrt::apply_balanced |
|||||
| crt_comb | CrtComb::new, CrtComb::reduce |
✓ | ||||
| crt_comb | CrtComb::combine |
✓ | ||||
| crt_comb | CrtComb::combine_balanced |
✓ |
crt is checked by Azurite’s Garner algorithm on the two moduli (its None being checked as moduli
that are not coprime), FLINT’s fmpz_CRT, and a reference that combines the two congruences with an
extended GCD; multi_crt by Azurite’s Garner algorithm (its None result being checked as a
violated precondition: moduli that are not pairwise coprime, or a residue that is not reduced),
FLINT’s fmpz_multi_CRT, and a reference that folds crt. multi_crt is built on MultiCrt::new
and MultiCrt::apply, so those are checked through it; apply_balanced, which returns the residue
in \((-M/2, M/2]\), is not yet. The CrtComb precomputation is checked against FLINT’s
fmpz_multi_mod_ui and fmpz_multi_CRT_ui family.
Powers, roots, and logarithms
| Operation | Functions | Azurite | FLINT | GMP | num | Reference |
|---|---|---|---|---|---|---|
| pow | Pow<u64> |
✓ | ✓ | ✓ | ✓ | |
| sqrt | FloorSqrt |
✓ | ✓ | ✓ | ✓ | |
| sqrt | CeilingSqrt |
✓ | ✓ | |||
| sqrt | CheckedSqrt |
✓ | ✓ | |||
| sqrt | SqrtRem |
✓ | ✓ | ✓ | ||
| root | FloorRoot<u64> |
✓ | ✓ | ✓ | ✓ | |
| root | CeilingRoot<u64> |
✓ | ||||
| root | CheckedRoot<u64> |
✓ | ✓ | |||
| root | RootRem<u64> |
✓ | ✓ | |||
| log_base | FloorLogBase, CeilingLogBase, CheckedLogBase |
✓ | ✓ | |||
| log_base | approx_ln |
|||||
| log_base_2 | FloorLogBase2, CeilingLogBase2, CheckedLogBase2 |
✓ | ||||
| log_base_power_of_2 | FloorLogBasePowerOf2, CheckedLogBasePowerOf2 |
✓ | ||||
| log_base_power_of_2 | CeilingLogBasePowerOf2 |
✓ | ✓ |
pow, floor_sqrt, sqrt_rem, ceiling_sqrt, checked_sqrt, floor_root (cube roots included),
and checked_root are checked by Azurite (the ceiling and checked square roots read off sqrtRem),
and the floor and remainder forms by GMP (and the floors by num). Every root function is also
checked against a reference that finds the root by binary search, and pow against both repeated
multiplication and square-and-multiply; ceiling_root is cross-checked only through that reference.
The logarithms are checked by Azurite: the base-2 and base-\(2^k\) logarithms from AzNat.size and
isPowerOfTwo, and floor_log_base and its siblings by AzRat.floorLogBaseAbs and cmpPowAbs for
a base that fits in a limb (and by repeated multiplication in AzNat arithmetic for a larger one);
the general logarithms are also compared with two references (a naive loop of multiplications and a
search by repeated squaring). approx_ln, a floating-point estimate, is covered by property tests
alone.
Powers of 2
| Operation | Functions | Azurite | FLINT | GMP | num | Reference |
|---|---|---|---|---|---|---|
| power_of_2 | PowerOf2<u64> |
✓ | ||||
| is_power_of_2 | IsPowerOf2 |
✓ | ✓ | |||
| next_power_of_2 | NextPowerOf2 |
✓ | ||||
| divisible_by_power_of_2 | DivisibleByPowerOf2 |
✓ | ✓ |
power_of_2, is_power_of_2, and divisible_by_power_of_2 are checked by Azurite, and the last
three functions by GMP.
GCD and number theory
| Operation | Functions | Azurite | FLINT | GMP | num | Reference |
|---|---|---|---|---|---|---|
| gcd | Gcd |
✓ | ✓ | ✓ | ✓ | |
| gcd | ExtendedGcd |
≈ | ✓ | ✓ | ||
| gcd | extended_gcd_partial |
✓ | ||||
| lcm | Lcm |
✓ | ✓ | |||
| coprime_with | CoprimeWith |
✓ | ||||
| kronecker_symbol | JacobiSymbol |
✓ | ✓ | ✓ | ||
| kronecker_symbol | LegendreSymbol |
✓ | ✓ | |||
| kronecker_symbol | KroneckerSymbol |
✓ |
gcd is checked by Azurite’s binary GCD, GMP, num, and two references (Euclid’s algorithm and the
binary algorithm), and coprime_with by Azurite. extended_gcd is ≈ for Azurite because a Bézout
pair is not unique and Azurite normalizes its pair differently: the oracle checks that the GCDs
agree, that Malachite’s pair satisfies \(sa + tb = g\), and that it is the pair Malachite
documents (bounded by \(|s| \le b/g\), \(|t| \le a/g\), with the fixed values for zeros and
divisors); GMP and the two references compare the pair exactly. extended_gcd_partial, the
partial extended GCD used in continued-fraction and lattice code, is checked against FLINT’s
fmpz_xgcd_partial. jacobi_symbol is checked by Azurite, GMP, and a reference, and the
Legendre and Kronecker symbols by GMP.
Combinatorial functions
| Operation | Functions | Azurite | FLINT | GMP | num | Reference |
|---|---|---|---|---|---|---|
| factorial | Factorial |
✓ | ✓ | |||
| factorial | DoubleFactorial |
✓ | ✓ | |||
| factorial | Multifactorial |
✓ | ✓ | |||
| factorial | Subfactorial |
✓ | ||||
| falling_factorial | FallingFactorial |
✓ | ||||
| rising_factorial | RisingFactorial |
✓ | ||||
| binomial_coefficient | BinomialCoefficient |
✓ | ✓ | |||
| fibonacci | Fibonacci (fibonacci, fibonacci_pair) |
✓ | ✓ | |||
| fibonacci | LucasNumber (lucas_number, lucas_number_pair) |
✓ | ✓ | |||
| primorial | Primorial::primorial |
✓ | ✓ | |||
| primorial | Primorial::product_of_first_n_primes |
✓ | ||||
| bell_number | BellNumber |
✓ | ||||
| bell_number | bell_numbers_prefix |
✓ | ||||
| landau_function | landau_function_prefix |
✓ |
Almost every combinatorial function is compared with a naive reference (the defining product, sum,
or recurrence), and most with GMP. rising_factorial, bell_number (with its prefix table), and
landau_function_prefix are checked against FLINT. None has an Azurite counterpart yet, so this
whole section is open ground for it.
Conversion
From
malachite_nz::natural::conversion.
Primitive types
| Operation | Functions | Azurite | FLINT | GMP | num | Reference |
|---|---|---|---|---|---|---|
| from_primitive_int | From<u8>, …, From<usize> |
✓ | ✓ | ✓ | ||
| from_primitive_int | SaturatingFrom<i8>, …, SaturatingFrom<isize> |
✓ | ||||
| from_primitive_int | TryFrom<i8>, …, TryFrom<isize>, ConvertibleFrom |
|||||
| from_primitive_int | const_from |
|||||
| primitive_int_from_natural | WrappingFrom<Natural> for every primitive integer |
✓ | ✓ | |||
| primitive_int_from_natural | TryFrom<Natural> for every primitive integer |
✓ | ||||
| primitive_int_from_natural | SaturatingFrom, OverflowingFrom, ConvertibleFrom for every primitive integer |
|||||
| from_bool | From<bool> |
|||||
| from_primitive_float | RoundingFrom<f32>, RoundingFrom<f64> |
✓ | ||||
| from_primitive_float | TryFrom<f32>, TryFrom<f64>, ConvertibleFrom |
✓ | ||||
| primitive_float_from_natural | RoundingFrom<Natural> for f32, f64 |
✓ | ||||
| primitive_float_from_natural | TryFrom<Natural>, ConvertibleFrom<Natural> for f32, f64 |
✓ | ||||
| mantissa_and_exponent | IntegerMantissaAndExponent |
|||||
| mantissa_and_exponent | SciMantissaAndExponent, sci_mantissa_and_exponent_round, from_sci_mantissa_and_exponent_round |
✓ | ||||
| is_integer | IsInteger |
|||||
| is_real | IsReal |
|||||
| is_gaussian_integer | IsGaussianInteger |
|||||
| clone | Clone |
✓ | ✓ |
Conversion from the unsigned primitives is checked by Azurite (UInt64.toAzNat), GMP, and num, and
the clamping conversion from the signed ones by Azurite. Toward the primitives, wrapping_from
(the value modulo \(2^w\), reinterpreted for signed types) is checked by Azurite’s toUInt64 and
toInt64 families and by GMP, and try_from by GMP.
The conversions to and from f32 and f64, and the scientific mantissa-and-exponent
decompositions, are checked by Azurite. A Natural becomes an exact AzFloat and is rounded to
f64 by AzFloat.toFloat64, whose IEEE 754 rounding is proven, or to the 24 bits of an f32 by
setPrecRound; a rounded value above the largest finite float overflows as IEEE 754 specifies. In
the other direction a float’s exact rational value is rounded by AzRat.round. Malachite prints
floats as the shortest decimals that read back to them, and the oracle reads each decimal back as
an exact rational and rounds it to the float format, subnormals included, before comparing values.
Limbs and digits
| Operation | Functions | Azurite | FLINT | GMP | num | Reference |
|---|---|---|---|---|---|---|
| from_limbs | from_limbs_asc, from_owned_limbs_asc |
✓ | ||||
| from_limbs | from_limbs_desc, from_owned_limbs_desc |
✓ | ||||
| to_limbs | limbs |
✓ | ||||
| to_limbs | to_limbs_asc, into_limbs_asc, as_limbs_asc, to_limbs_desc, into_limbs_desc |
✓ | ||||
| limb_count | limb_count |
✓ | ||||
| general_digits | Digits::to_digits_asc, Digits::to_digits_desc |
✓ | ✓ | |||
| general_digits | Digits::from_digits_asc, Digits::from_digits_desc |
✓ | ✓ | |||
| power_of_2_digits | PowerOf2Digits |
✓ | ✓ | |||
| power_of_2_digit_iterable | PowerOf2DigitIterable |
The limb-level interface is checked by Azurite’s ofLimbs and limbs in both orders and every form
(to_limbs, into_limbs, as_limbs_asc, the reversed iterator, the from_owned_limbs
constructors) and limb_count by the number of AzNat limbs. Base-\(b\) digits, in both directions
and both orders, are checked by Azurite (limbDigits and ofLimbDigits for primitive digits, and
division and Horner’s rule in AzNat arithmetic for Natural digits) and by references that
convert one digit at a time; the power-of-2 digits by Azurite’s limbDigitsPow2 and
ofLimbDigitsPow2 and by references that extract and assemble bit fields.
Strings
| Operation | Functions | Azurite | FLINT | GMP | num | Reference |
|---|---|---|---|---|---|---|
| to_string | Display, Debug |
✓ | ✓ | ✓ | ✓ | |
| to_string | Binary, Octal, LowerHex, UpperHex |
✓ | ✓ | ✓ | ✓ | |
| to_string | ToStringBase |
✓ | ✓ | ✓ | ||
| from_string | FromStr |
✓ | ✓ | ✓ | ||
| from_string | FromStringBase |
✓ | ✓ | ✓ | ||
| from_sci_string | FromSciString |
✓ | ||||
| to_sci | ToSci |
✓ | ||||
| format_natural | format_natural_str, format_gmp_str, GmpFormatArg |
✓ | ||||
| latex | ToLatex |
|||||
| typst | ToTypst |
|||||
| serde | Serialize, Deserialize |
|||||
| pyo3 | FromPyObject, IntoPyObject |
Decimal and hexadecimal output and input are checked against GMP and num, and to_string_base
(lower and upper case), from_str, and from_string_base by Azurite, whose digits for bases above
36 follow Malachite’s documented rule. The formatting traits are checked by Azurite’s
toStringBaseWith through the demos that format with a width (format!("{:#032x}", n) and so on),
where the oracle applies Rust’s zero padding after the base prefix; the unpadded demos print only
the output, which has nothing to be checked against. Scientific notation is checked by Azurite’s
AzRat.fromSci and AzRat.toSci on integers: from_sci_string as the exact rational rounded to an
integer in the requested mode (None under Exact when that is not possible, and for a negative
result), to_sci and to_sci_with_options digit for digit, and fmt_sci_valid as toSciExact.
The GMP-style format_natural_str is compared with GMP’s own gmp_snprintf, called directly.
LaTeX, Typst, serde, and the Python bindings are not cross-checked.
Logic
From
malachite_nz::natural::logic.
| Operation | Functions | Azurite | FLINT | GMP | num | Reference |
|---|---|---|---|---|---|---|
| and | BitAnd |
✓ | ✓ | ✓ | ||
| or | BitOr |
✓ | ✓ | ✓ | ||
| xor | BitXor |
✓ | ✓ | ✓ | ||
| not | Not |
✓ | ||||
| bit_access | BitAccess::get_bit |
✓ | ✓ | ✓ | ||
| bit_access | BitAccess::set_bit |
✓ | ✓ | ✓ | ||
| bit_access | BitAccess::clear_bit |
✓ | ✓ | |||
| bit_access | BitAccess::assign_bit, flip_bit |
✓ | ||||
| bit_block_access | BitBlockAccess::get_bits |
✓ | ✓ | |||
| bit_block_access | BitBlockAccess::assign_bits |
✓ | ||||
| bit_convertible | BitConvertible |
✓ | ||||
| bit_iterable | BitIterable |
|||||
| bit_scan | BitScan |
✓ | ✓ | |||
| count_ones | CountOnes |
✓ | ||||
| hamming_distance | HammingDistance |
✓ | ✓ | |||
| significant_bits | SignificantBits |
✓ | ✓ | ✓ | ||
| trailing_zeros | trailing_zeros |
✓ | ✓ | |||
| low_mask | LowMask |
✓ |
The bitwise operations and the single-bit accessors are checked against GMP, and most against num
and references that work limb by limb or bit by bit. Azurite checks get_bit, set_bit,
clear_bit, and get_bits (testBit, setBit, clearBit, getBits), and significant_bits,
trailing_zeros, and low_mask (size, trailingZeros, lowMask). AzNat has no and, or,
xor, or not yet, so those rows, and the bit scans and population counts built on them, are
where Azurite would add the most here.
Factorization
From malachite_nz::natural::factorization.
| Operation | Functions | Azurite | FLINT | GMP | num | Reference |
|---|---|---|---|---|---|---|
| is_square | IsSquare |
✓ | ✓ | |||
| is_power | IsPower |
✓ | ||||
| is_power | ExpressAsPower |
|||||
| remove_power | RemovePower |
✓ | ||||
| primes | primes_less_than, primes_less_than_or_equal_to |
✓ | ||||
| primes | primes |
is_square is checked by Azurite’s isSquare and GMP’s is_perfect_square, and is_power and
remove_power by GMP. primes_less_than and primes_less_than_or_equal_to are checked by Azurite
in a strong form: the oracle decides every number in the range with isPrime, whose result is
backed by a Miller–Rabin filter and a machine-checked APR-CL certificate, and requires the printed
list to be exactly the primes it finds. The unbounded primes iterator is tested by comparing its
prefixes with primes_less_than, so it inherits that check indirectly. express_as_power, which
returns a base and exponent rather than a yes or no, is covered by property tests alone.
Natural has no primality test of its own yet; Azurite’s proven isPrime will be its first
oracle when it does.
Exhaustive generation
From malachite_nz::natural::exhaustive.
| Operation | Functions | Azurite | FLINT | GMP | num | Reference |
|---|---|---|---|---|---|---|
| exhaustive | exhaustive_naturals |
✓ | ||||
| exhaustive | exhaustive_positive_naturals |
✓ | ||||
| exhaustive | exhaustive_natural_range |
✓ | ||||
| exhaustive | exhaustive_natural_inclusive_range |
✓ | ||||
| exhaustive | exhaustive_natural_range_to_infinity |
✓ |
The exhaustive generators are checked against Azurite’s ExhaustiveGenerator instances
(naturalsGen, positiveNaturalsGen, azNatRangeGen, azNatRangeInclusiveGen,
azNatRangeToInfinityGen), each of which carries a proof that every value occurs exactly once: the
demos print the whole-type sequences element by element and the first twenty values of each range,
and the oracle requires Azurite’s generator to produce the same values in the same positions, and a
range with fewer than twenty values to end where Malachite’s does. Malachite’s own tests compare
prefixes with fixed expected values and check that ranges contain exactly what they should.
Random generation
From malachite_nz::natural::random.
| Operation | Functions | Azurite | FLINT | GMP | num | Reference |
|---|---|---|---|---|---|---|
| random | random_naturals, random_positive_naturals, random_naturals_less_than, random_naturals_less_than_power_of_2 |
|||||
| random | striped_random_naturals, striped_random_positive_naturals, striped_random_naturals_less_than_power_of_2 |
|||||
| random | uniform_random_natural_range, uniform_random_natural_inclusive_range, random_natural_range, random_natural_inclusive_range, random_natural_range_to_infinity |
|||||
| random | striped_random_natural_range, striped_random_natural_inclusive_range, striped_random_natural_range_to_infinity |
|||||
| random | get_random_natural_with_bits, get_random_natural_with_up_to_bits, get_random_natural_less_than, and their striped forms |
Random generators have no independent oracle in the sense of this page: what they produce depends on Malachite’s own seeded generator, so another library cannot reproduce it. They are tested instead by pinning the first values for fixed seeds and by comparing the distribution of a large sample (its most common values, mean, standard deviation, skewness, and excess kurtosis) with the values the distribution should have, which catches a biased or truncated generator.
What is not yet cross-checked
The rows above with no mark, and the rows with no Azurite mark, sort into two groups by what it would take to give them a verified oracle. Within each group the most widely used functions come first.
A few lines of oracle code around Azurite functions. These need no new Azurite function, but
the oracle would compose existing ones, so the composition itself is unverified code: checked_sub
and saturating_sub_mul (a comparison and a subtraction), abs_diff, average and
average_round, the fused operations (add_mul, sub_mul, mul_add_mul, mul_sub_mul, and
their checked and saturating forms), shl_round, mul_shr_round, round_to_multiple and
round_to_multiple_of_power_of_2 (a rounded division or shift and a multiplication),
ceiling_root and root_rem (rootInt and a power), next_power_of_2, lcm (a GCD and a
division), div_exact and checked_div, ceiling_div_neg_mod and neg_mod, assign_bit and
flip_bit (from testBit, setBit, and clearBit), the primitive conversions that clamp, check,
or flag (TryFrom, SaturatingFrom, OverflowingFrom, ConvertibleFrom), IntegerMantissaAndExponent
(a count of trailing zeros and a shift), and Clone.
Azurite would need new functions. These are the operations whose absence from Azurite is the real gap, in rough order of how much of Malachite they would cover:
- The bitwise operations
and,or,xor, andnot, and with them the population and Hamming counts, the bit scans, bit iteration, conversion to and from bit vectors, and writing a block of bits (assign_bits). - The combinatorial functions: factorials (single, double, multi-, and sub-), the falling and rising factorials, binomial coefficients, Fibonacci and Lucas numbers, the primorial and the product of the first \(n\) primes, Bell numbers, and the Landau function. Every one of them is currently checked against a reference implementation and most against GMP, but none against a proven implementation.
- The Kronecker symbol (Azurite has the Jacobi symbol) and with it the Legendre symbol, the
modular square root,
mod_div_list, andMultiCrt::apply_balanced. - Perfect-power detection and decomposition (
is_power,express_as_power) andremove_power. - A primality test on
Natural, the one place where Azurite is ahead of Malachite: itsisPrimeis already proven, and is the oracle forprimes_less_than.
Outside the scope of an oracle. The constants, Default, Named, Hash, the unit functions
(is_unit, conjugate, canonicalize_unit, canonical_unit_i_pow), IsInteger, IsReal,
IsGaussianInteger, From<bool>, const_from, LaTeX and Typst output, serde, the Python bindings,
and the random generators. Most are trivial on a type with no sign and no fractional part; the
rest have no independent implementation to compare with, and are tested by their own unit and
property tests, the random generators by the distribution of large samples.