View on GitHub

malachite

An arbitrary-precision arithmetic library for Rust.

Malachite for num Users: Traits

This page maps num’s generic vocabulary, the num-traits and num-integer crates, with num-iter’s range functions alongside, onto Malachite’s generic vocabulary, which lives in malachite-base. It covers num-traits 0.2.19, num-integer 0.1.46, and num-iter 0.1.46, and completes the num family begun by the integers and rationals pages, which map the concrete types; this page is for code written against T: Num rather than against a BigUint. The mapping index lists all the pages.

The two crates being mapped here are trait collections, so the rows of this page pair traits with traits, and the mapping is between two generic systems: both num and Malachite implement their vocabularies for the primitive integer and floating-point types as well as for their bignum types, so in both worlds one generic function can span u32 and a bignum. What a porting reader translates is bounds and imports, and occasionally a method shape.

Conventions

Granularity

The deepest difference between the two systems is how much one trait means. num’s vocabulary is anchored by umbrella traits: Num bundles equality, the identities, the operators, and string parsing; PrimInt and Float each carry dozens of methods. Malachite’s vocabulary is fine-grained: nearly every operation is its own trait, Gcd, CheckedSub, FloorSqrt, and a bound is assembled from exactly the operations used. Porting a T: Num bound therefore usually means writing several Malachite bounds, and porting a Malachite bound into num terms usually means asking for more than is needed. The tables below map each num trait to the Malachite traits that cover its members.

Names collide, in both directions

Many correspondences are name-for-name: num’s CheckedAdd and Malachite’s CheckedAdd are different traits from different crates with the same job, and a use line decides which is in scope. Two collisions deserve care rather than comfort. num_traits::Float is a trait describing primitive floating-point types, while Malachite’s Float is an arbitrary-precision type; the two have nothing to do with each other, and the float section below sorts out what maps where. And num’s Integer is a trait, from num-integer, while Malachite’s Integer is its signed bignum type; this page writes num_integer::Integer when it means the trait.

Method shapes

num’s operation traits generally take their arguments by reference and return owned results, fn checked_add(&self, v: &Self) -> Option<Self>; Malachite’s generally take self by value, with Output associated types, reference implementations on &T where cloning matters, and separate *Assign traits for in-place forms. The information carried is the same, and the compiler polices the difference; where a shape difference changes what code can express, the notes say so.

What implements what

Each system implements its own vocabulary: num-traits for the primitives and, via num-bigint and num-rational, for the bignum types; malachite-base for the primitives and, via malachite-nz and malachite-q, for Natural, Integer, Rational, and Float. Neither library implements the other’s traits, so generic code chooses a vocabulary; the concrete-type pages of this family are the dictionary for everything a bound reaches through these traits.

Categories

Each item falls into one of four categories:

  meaning
A Malachite trait or function does the same thing.
A Malachite trait or function serves the same purpose, but its specification differs. The notes say how.
No counterpart is needed; the notes say why.
Malachite does not fully support this yet, but will in a future version.

Identities and umbrella traits

  num Malachite
Zero, ConstZero (zero(), is_zero, set_zero, ZERO) Zero
One, ConstOne (one(), is_one, set_one, ONE) One
free functions zero(), one()  
Num (PartialEq + Zero + One + NumOps, from_str_radix) Zero, One, FromStringBase
NumOps, NumRef, RefNum  
NumAssignOps, NumAssign, NumAssignRef  

The identities. The two systems agree on what and differ on how. num’s Zero is a trait with methods, zero() constructing the identity, is_zero testing it, set_zero assigning it, refined since 0.2.19 by ConstZero’s constant; Malachite’s Zero has been a single associated constant from the start. The translations are one-liners: T::zero() becomes T::ZERO, x.is_zero() becomes x == T::ZERO under a PartialEq bound, x.set_zero() becomes x = T::ZERO, and the free functions zero() and one() are the constants themselves. The constant family keeps going on the Malachite side: Two, NegativeOne, and, for the types that have them, OneHalf, Infinity, and NaN, all usable as generic bounds in the same way.

Num. The central umbrella, and a ≈ that unpacks rather than renames: a T: Num bound says PartialEq + Zero + One + NumOps plus from_str_radix, so its Malachite translation spells those out, T: PartialEq + Zero + One + Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T> + Rem<Output = T>, with FromStringBase covering the parsing member for the primitives and the bignum integers; the rational instantiation of that member is the base-string gap noted on the rationals page. The bound is longer, which is the granularity trade described under Conventions: nothing is bundled, and nothing unused comes along.

The operator bundles. NumOps is shorthand for the five standard operator bounds, NumAssignOps for their assign forms, and NumRef, RefNum, and NumAssignRef extend them to borrowed operands. The standard library’s operator traits are the shared vocabulary here, and Malachite’s types implement them in the same owned, borrowed, and assigning combinations, so every pattern these shorthands describe holds; only the shorthand names themselves have no counterparts, and a port writes the constituent bounds directly.

Signs and bounds

  num Malachite
Signed (abs, abs_sub, signum, is_positive, is_negative) Abs, Sign, PrimitiveSigned
Unsigned PrimitiveUnsigned
free functions abs, abs_sub, signum  
Bounded, LowerBounded, UpperBounded (min_value, max_value) PrimitiveInt, PrimitiveFloat
free functions clamp, clamp_min, clamp_max  

Signed and Unsigned. Each plays two roles. As method carriers, the Signed methods were mapped with the concrete types, abs to Abs, signum to Sign, the predicates to comparisons against zero, and abs_sub to a spelled-out positive difference, on the integers and rationals pages; the free functions are call-syntax sugar over the same methods. Two relatives of abs_sub are worth knowing. Its formula, a subtraction stopped at zero, is exactly SaturatingSub on the unsigned types, where zero is the saturation point: x.saturating_sub(y) on a Natural is the positive difference with no comparison written. And AbsDiff, x.abs_diff(y) computing \(|x - y|\), is the different operation abs_sub is sometimes mistaken for, and tells the two apart. As markers, the two systems draw the line differently: num’s Signed spans the signed primitives, BigInt, and BigRational in one bound, while Malachite’s PrimitiveSigned and PrimitiveUnsigned are primitive-only umbrellas, richer in members but not spanning the bignums. Code generic over signed types of both kinds assembles its bound from the operations it uses, which is the granularity trade again.

The bounded traits. Both systems attach bounds only where bounds exist: num implements Bounded for the primitives and leaves the unbounded bignums out, and Malachite’s bignums likewise have no extremes to name. For generic code over primitives, min_value() and max_value() become the MIN and MAX associated constants that PrimitiveInt and PrimitiveFloat carry. The LowerBounded/UpperBounded split, which exists for one-sidedly bounded types, reaches the same constants and has no separate counterpart.

The clamp functions. clamp, clamp_min, and clamp_max predate and parallel the standard library’s Ord::clamp, which covers every totally ordered type, Malachite’s exact types included: x.clamp(lo, hi). For partially ordered types, num’s versions accept floats; the same effect is two comparisons wherever Ord is unavailable.

Casts and bytes

This is where the two systems differ most in philosophy. num has one conversion vocabulary, Option-valued: a cast either produces the exact value or None, with the float cases rounding. Malachite has seven, and the trait names the semantics: TryFrom is exact with an Err, ExactFrom is exact with a panic, WrappingFrom reduces modulo \(2^w\), SaturatingFrom clamps to the target’s range, OverflowingFrom wraps and reports whether it did, ConvertibleFrom answers whether an exact conversion exists, and RoundingFrom rounds in an explicit mode and reports the direction. A num call site maps to whichever names what it meant.

  num Malachite
ToPrimitive (to_u8..to_u128, to_i*, to_f32, to_f64) TryFrom, RoundingFrom
FromPrimitive (from_u8.., from_f32, from_f64) TryFrom, RoundingFrom
NumCast; free function cast ExactFrom, TryFrom
AsPrimitive (as_) WrappingFrom
ToBytes, FromBytes, NumBytes  

ToPrimitive and FromPrimitive. The integer members are exact-or-None, num’s docs promising None “if the value cannot be represented”, which is TryFrom with an Err, or ConvertibleFrom when only the answer is wanted; the float members round, which is RoundingFrom with the mode written down. The concrete behaviors on bignums, truncation toward zero from floats and the one-ulp subtleties toward them, were mapped on the integers page; here the point is the bound itself, and a T: ToPrimitive generic becomes a bound on the specific conversions used.

NumCast and cast. An any-to-any conversion that routes through ToPrimitive, so cast::<T, U>(n) is the same exact-or-None contract with type inference picking the route. Malachite implements its conversion traits pairwise, so the translation is direct: U::try_from(n) fallibly, or U::exact_from(n) when the caller would have unwrapped anyway, panicking with intent rather than unwrapping an Option.

AsPrimitive. The generic spelling of Rust’s as operator, with as’s own semantics: wrapping between integers, saturating from floats since Rust 1.45, and its documentation retains an example marked “UB” from the era before that. The integer-to-integer case is exactly WrappingFrom; the float-involved cases are RoundingFrom and SaturatingFrom with the semantics named instead of inherited from the operator.

The byte traits. ToBytes and FromBytes generalize the primitives’ to_le_bytes family behind a Bytes associated type, with NumBytes bounding it; num implements them for the primitives. Malachite has no byte traits: concrete code reaches the standard inherent methods on primitives, and the bignum byte conversions live with the digit functions of the integers page. Code generic over byte representations keeps num’s vocabulary or passes byte slices explicitly.

Operator refinements

The checked, overflowing, saturating, and wrapping families are where the two vocabularies come closest to being one: most rows are the same trait name in two crates.

  num Malachite
CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, CheckedRem, CheckedNeg CheckedAdd and kin
CheckedShl, CheckedShr ArithmeticCheckedShl, ArithmeticCheckedShr
OverflowingAdd, OverflowingSub, OverflowingMul OverflowingAdd and kin
SaturatingAdd, SaturatingSub, SaturatingMul SaturatingAdd and kin
Saturating (legacy two-method umbrella)  
WrappingAdd, WrappingSub, WrappingMul, WrappingNeg WrappingAdd and kin
WrappingShl, WrappingShr Shl, Shr
Euclid, CheckedEuclid DivEuclidean, ModEuclidean
Inv Reciprocal
MulAdd AddMul
MulAddAssign AddMulAssign
Pow Pow
free functions pow, checked_pow  

The name-for-name families. Checked, overflowing, saturating, and wrapping arithmetic translate by changing the use line, with the method-shape difference from Conventions the only adjustment: num’s forms take references, Malachite’s take values with *Assign companions. Malachite’s families also include CheckedAbs, OverflowingNeg, SaturatingNeg, and their relatives, extending the grid beyond the common cases. The old Saturating umbrella, two methods from before the granular traits existed, maps as its members do.

The shifts. A real semantic split hides under similar names, worth slowing down for. num’s shift refinements govern the count: checked_shl answers None exactly when the count reaches the type’s width, its doctest sending checked_shl(&x, 16) on a u16 to None, and wrapping_shl reduces the count modulo the width, sending 16 to a shift by zero. Malachite’s ArithmeticCheckedShl governs the value: None when the shifted value cannot be represented, whatever the count. The count-based behaviors are one-liners when ported exactly, (n < W).then(|| x << n) and x << (n % W), but a caller reaching for checked_shl often wants the value-based question, and should choose deliberately.

Euclid and Inv. div_euclid is DivEuclidean and rem_euclid is ModEuclidean, on the primitives as on Integer, and the provided div_rem_euclid pair is DivModEuclidean; CheckedEuclid adds the zero-divisor guard. Inv is Reciprocal, on the primitive floats here and on Rational on the rationals page.

MulAdd and the argument order. Both libraries have the ternary multiply-and-add; the receivers differ, and the dictionary matters more here than anywhere on this page: x.mul_add(y, z) computes \(xy + z\), while x.add_mul(y, z) computes \(x + yz\), so the translation reorders, x.mul_add(y, z) becoming z.add_mul(x, y), an exact match. The assign forms do not reorder into each other: mul_add_assign mutates a multiplicand, \(r \gets rx + c\), the Horner step, while add_mul_assign mutates an accumulator, \(a \gets a + yz\), the accumulation step; the Horner shape spells r = c.add_mul(r, &x) by value, and SubMul completes the family with \(x - yz\). On the primitive floats, num’s mul_add is the fused, singly rounded operation; Malachite’s fused Float arithmetic is a gap recorded on the MPFR page.

Pow and the free functions. Pow keeps its name and its role, with the concrete exponent types mapped on the type pages. The free pow(base, exp) and checked_pow are call-syntax over the trait, whose Malachite spellings are the Pow and CheckedPow methods themselves.

Floats

The name collision flagged under Conventions resolves here. num’s float traits describe the primitive floating-point types, f32 and f64; Malachite’s Float is an arbitrary-precision type with its own page-sized dictionary, the MPFR page. A port of T: Float code therefore chooses a destination first: staying with primitive floats, the subject of these rows, or moving to arbitrary precision, at which point the MPFR page is the map.

  num Malachite
FloatCore PrimitiveFloat
Float PrimitiveFloat
FloatConst  
TotalOrder  
Real  

FloatCore and Float. num splits the primitive-float surface into a no_std core, classification, rounding, and sign manipulation, and a std-dependent full trait that adds the mathematical library, sqrt through atan2. PrimitiveFloat covers the first role and goes deeper into the representation: classification and to_bits alongside constants like MANTISSA_WIDTH, MIN_POSITIVE_SUBNORMAL, and LARGEST_ORDERED_REPRESENTATION that num does not name, plus the integer-logarithm and rounding supertraits. It does not carry the transcendental functions: generic code needing T: Float for sin and exp keeps num’s trait or calls the standard inherent methods concretely, and code that wants those functions correctly rounded has outgrown f64, which is what the Float type is for.

The rest. FloatConst exists to make the standard consts modules generic; Malachite has no counterpart trait, and its constant story at arbitrary precision, three dozen constants to any precision, is on the MPFR page. TotalOrder predates the standard library’s total_cmp, which now covers it; the arbitrary-precision total order is ComparableFloat’s. Real abstracts Float for real-valued types generally; nothing binds to it here.

Primitive integers

  num Malachite
PrimInt PrimitiveInt, PrimitiveUnsigned, PrimitiveSigned

The umbrella meets the umbrella. This is the one place both systems agree that a large bound is the right shape for primitive integers, and the two match in kind. num’s PrimInt gathers the operators, shifts, casts, and the bit-counting and byte-order methods; Malachite’s PrimitiveInt gathers over a hundred supertraits, from the operator refinements of this page through ExtendedGcd, BinomialCoefficient, and the Kronecker symbols, with PrimitiveUnsigned and PrimitiveSigned refining by signedness. Shared members map name-for-name through the fine-grained traits, count_ones to CountOnes, leading_zeros and trailing_zeros to LeadingZeros and TrailingZeros, rotate_left to RotateLeft, pow to Pow, from_str_radix to FromStringBase; the byte-order members, swap_bytes and the to_be/to_le family, have no trait spellings and stay with the standard inherent methods.

num-integer

  num Malachite
num_integer::Integer (as a bound) DivMod, Gcd, Parity, and kin
Roots (as a bound) FloorSqrt, FloorRoot
Average (average_floor, average_ceil; free functions)  
ExtendedGcd (the struct)  
free functions div_rem through gcd_lcm, sqrt, cbrt, nth_root  
binomial (n, k) BinomialCoefficient
multinomial (k: &[T]) BinomialCoefficient
IterBinomial  

The traits as bounds. num_integer::Integer’s methods were mapped in detail on the integers page, and Roots’s with the powers, truncation subtlety included. As bounds, both follow the granularity rule of this page: a function generic over T: num_integer::Integer asks Malachite for the operations it actually uses, DivMod here, Gcd and Parity there, and nothing more. The ExtendedGcd struct is num’s packaging for the Bézout triple that Malachite returns as a tuple, with the normalization advice of the integers page attached; the free functions are call syntax over the trait methods.

Average. The committed gap of this page: averaging functions, \(\lfloor (a+b)/2 \rfloor\) and its ceiling, overflow-proof, are planned for Malachite. Until they land, the bignums have no overflow to dodge, (&a + &b) >> 1 for the floor and (&a + &b + Natural::ONE) >> 1 for the ceiling, and the primitives use the classic carry-free spellings, (a & b) + ((a ^ b) >> 1) for the floor and (a | b) - ((a ^ b) >> 1) for the ceiling.

The combinatorial functions. binomial(n, k) is BinomialCoefficient’s T::binomial_coefficient(n, k), on the primitives and the bignums alike, with CheckedBinomialCoefficient for the primitive cases that overflow. multinomial is a fold of binomials on both sides of the boundary, \(\binom{k_1 + \cdots + k_m}{k_m} \cdots \binom{k_1 + k_2}{k_2}\), spelled with a running sum and binomial_coefficient; IterBinomial, which walks a row of Pascal’s triangle, is the exact recurrence b = b * (n - k) / (k + 1) in an iterator’s clothing, three lines with DivExact doing the division.

num-iter

  num Malachite
range (start, stop) exhaustive_natural_range, primitive_int_increasing_range
range_inclusive (start, stop) exhaustive_natural_inclusive_range, primitive_int_increasing_inclusive_range
range_from (start) successors
range_step, range_step_inclusive, range_step_from successors

The ranges. num-iter exists because a..b requires the unstable Step machinery, which bignum types cannot implement on stable Rust; num_iter::range(a, b) is the working spelling of a BigUint range, and exhaustive_natural_range is the same iterator over Naturals, half-open like num’s, with the _inclusive pair matching and primitive_int_increasing_range covering generic primitive code. The unbounded and stepped variants compose with the standard library: successors(Some(start), |x| Some(x + Natural::ONE)) climbs without bound, the step versions add a stride instead, and on primitives (a..b).step_by(n) needs no help. These sit inside a larger exhaustive-generation module, increasing, decreasing, and coverage-oriented orders over ranges and whole types, built for the same testing purposes as the random generators of the integers page.

That completes the num family: the concrete types on the integers and rationals pages, and the generic vocabulary here.