Malachite for num Users: Integers
This page maps the types of the num-bigint
crate, BigUint and BigInt, onto their Malachite counterparts:
Natural and
Integer, from
the malachite-nz crate. It covers num-bigint 0.4.8 as re-exported by the
num umbrella crate, together with the parts of
num-integer 0.1.46 and
num-traits 0.2.19 that these types implement,
since methods like div_floor and checked_add reach a num user through those traits. The
mapping index lists the whole family of pages.
Unlike the C libraries on the other pages, num has no manual whose organization a mapping can follow: its API is the sum of a type’s inherent methods and its trait implementations, spread across three crates. The sections below are therefore organized by theme, and together they cover the full public surface of the two types.
One asset exists here that no other page has. Because num and Malachite are both Rust,
migration has two routes. The drop-in route is
malachite-bigint, a crate that reimplements the
num-bigint API on top of Malachite’s arithmetic, so that most code keeps compiling with a
changed use line. The native route is this page: the same operations in Malachite’s own
vocabulary, which is in places differently shaped. The drop-in route is the fast
way off the fence; the native route is where the rest of Malachite, from
Rational to
Float,
becomes available. Measured performance comparisons between the libraries live on
the performance page, not here.
Conventions
The types
The correspondence is one-to-one, and closer than on any other page of this family. BigUint
is an unsigned bignum and BigInt wraps one in a sign, Sign being Minus, NoSign, or
Plus; a
Natural is an
unsigned bignum and an
Integer is a
sign and a Natural magnitude. Both libraries maintain the same invariants without help, no
high zero digits and a zero that is never negative, so no canonicalization caveats appear
anywhere below. Both keep the magnitude in machine words sized to match the platform: num’s
BigUint holds a Vec of 64-bit digits on 64-bit targets and 32-bit digits elsewhere, keyed
to the pointer width, while Malachite’s limbs are 64-bit by default and 32-bit under the
32_bit_limbs feature. One representation difference is worth knowing: a BigUint stores its
digits on the heap whenever it is nonzero, while a Natural or Integer whose magnitude is
less than \(2^{64}\) is stored inline with no allocation, as described
on the GMP integers page.
Idiom parity
Most of the friction the C-library pages document does not arise here. Both libraries
implement the arithmetic operators for owned and borrowed operands in all combinations, so
&a + &b and a + b mean the same things on both sides; both implement the *Assign
operators; both follow the primitive types’ conventions where they apply, truncating / and
% for signed division included. Values are created, not initialized; dropping frees; there
are no rounding modes or ternary values, these being exact types. The differences that remain
are vocabulary. num reaches much of its API through traits, num_traits::One,
num_integer::Integer, and so on, imported by their crate paths; Malachite’s equivalents live
in malachite_base’s trait modules
and are re-exported through the umbrella
malachite crate. Where num names a method
after C tradition or its own history, Malachite tends to spell the operation out; the tables
give the dictionary.
Features
The feature flags correspond directly. num-bigint’s serde is Malachite’s serde;
num-bigint’s rand is Malachite’s random, with different generator designs described under
Random below; both libraries work without std, num by disabling its default std feature
and Malachite by default. num-bigint’s arbitrary and quickcheck integrations have no
Malachite counterparts, Malachite’s testing story being its own
generator machinery.
Categories
Each item 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; the notes say why. |
| ✗ | Malachite does not fully support this yet, but will in a future version. |
Construction and constants
| num | Malachite | |
|---|---|---|
| ✓ | BigUint::new (digits: Vec<u32>) -> BigUint |
from_power_of_2_digits_asc, from_limbs_asc |
| ✓ | BigUint::from_slice (slice: &[u32]) -> BigUint |
from_power_of_2_digits_asc, from_limbs_asc |
| ✓ | BigUint::assign_from_slice (&mut self, slice: &[u32]) |
from_power_of_2_digits_asc |
| ✓ | BigUint::from_bytes_be (bytes: &[u8]) -> BigUint |
from_power_of_2_digits_desc |
| ✓ | BigUint::from_bytes_le (bytes: &[u8]) -> BigUint |
from_power_of_2_digits_asc |
| ✓ | BigUint::from_radix_be (buf: &[u8], radix: u32) -> Option<BigUint> |
from_digits_desc |
| ✓ | BigUint::from_radix_le (buf: &[u8], radix: u32) -> Option<BigUint> |
from_digits_asc |
| ✓ | BigInt::new (sign: Sign, digits: Vec<u32>) -> BigInt |
from_sign_and_abs |
| ✓ | BigInt::from_biguint (sign: Sign, data: BigUint) -> BigInt |
from_sign_and_abs |
| ✓ | BigInt::from_slice (sign: Sign, slice: &[u32]) -> BigInt |
from_sign_and_abs |
| ✓ | BigInt::assign_from_slice (&mut self, sign: Sign, slice: &[u32]) |
from_sign_and_abs |
| ✓ | BigInt::from_bytes_be (sign: Sign, bytes: &[u8]) -> BigInt |
from_sign_and_abs |
| ✓ | BigInt::from_bytes_le (sign: Sign, bytes: &[u8]) -> BigInt |
from_sign_and_abs |
| ≈ | BigInt::from_signed_bytes_be (digits: &[u8]) -> BigInt |
from_twos_complement_limbs_desc |
| ≈ | BigInt::from_signed_bytes_le (digits: &[u8]) -> BigInt |
from_twos_complement_limbs_asc |
| ✓ | BigInt::from_radix_be (sign: Sign, buf: &[u8], radix: u32) -> Option<BigInt> |
from_digits_desc |
| ✓ | BigInt::from_radix_le (sign: Sign, buf: &[u8], radix: u32) -> Option<BigInt> |
from_digits_asc |
| ✓ | Default (BigUint, BigInt) |
Default |
| ✓ | Zero, ConstZero (zero(), ZERO, is_zero) |
Zero |
| ✓ | One, ConstOne (one(), ONE, is_one) |
One |
| ✓ | From<u8..u128, usize> for BigUint |
From |
| ✓ | From<all primitive ints> for BigInt |
From |
| ≈ | FromPrimitive for BigUint (from_u64, from_i64, from_f64, …) |
TryFrom, RoundingFrom |
| ≈ | FromPrimitive for BigInt |
TryFrom, RoundingFrom |
The word-digit constructors. BigUint::new, from_slice, and assign_from_slice build
from “base 232 digits… ordered least significant digit first”, and num keeps that
u32 interface on every platform, whatever its internal digit size. Malachite offers the same
construction two ways: Natural::from_power_of_2_digits_asc(32, digits.iter().copied())
matches num’s interface digit for digit, and
from_limbs_asc
builds from native limbs, 64 bits by default. assign_from_slice is plain reassignment,
without the buffer-reuse intent behind num’s version. For BigInt, wrap the magnitude:
Integer::from_sign_and_abs(sign, abs) takes a bool where num takes a Sign, and the
three-valued Sign collapses cleanly, Plus and Minus becoming true and false and
NoSign taking care of itself, a zero magnitude producing zero whatever the sign argument
says.
The byte constructors. Big- and little-endian bytes are base-256 digits:
from_power_of_2_digits_desc(8, ...) and from_power_of_2_digits_asc(8, ...) respectively,
with an empty slice giving zero in both libraries. The signed pair is ≈ for a granularity
reason: from_signed_bytes_be reads two’s complement bytes, while Malachite’s
from_twos_complement_limbs_asc and _desc read two’s complement limbs, so the bytes must
be repacked into limbs, sign-extending the top byte into a full word, before the same
semantics apply.
The radix constructors. from_radix_be and from_radix_le take digit values, one per
byte, in any radix from 2 to 256, and num’s documentation demonstrates base 190;
from_digits_desc
and from_digits_asc are the same constructors with the 256 ceiling removed, the base being
any unsigned primitive or even a
Natural.
Both libraries return None when a digit is not below the base.
The constants. Default is zero on both sides. num’s Zero and One, with their 0.4.8
ConstZero and ConstOne refinements, map to Malachite’s
Zero
and One, whose ZERO and ONE are associated constants usable in const contexts from the
start; the is_zero and is_one predicates are == Natural::ZERO-style comparisons or the
Zero/One traits’ own methods on the num side. Malachite adds Two, NegativeOne on
Integer, and
const-buildable small values beyond the identities through const_from.
The primitive conversions. From covers every unsigned primitive into
Natural and
every primitive into
Integer,
matching num’s infallible impls. FromPrimitive is the Option-returning layer, and its ≈ is
shape rather than substance: BigUint::from_i64(-1) returns None where
Natural::try_from(-1i64) returns an Err, and from_f64 accepts a float, discards its
fractional part, and returns None for NaN, infinities, and negatives, which in Malachite is
spelled with an explicit rounding, Natural::rounding_from(f, Down), or exactly, with
try_from; the float cases that num answers with None are panics or Errs here, stated at
each site’s documentation.
Conversion
The outward direction, plus the traffic between the two types. Every digit and byte deconstructor from the previous section has its inverse here, and the same correspondences hold, with one recurring edge noted below: what zero deconstructs to.
| num | Malachite | |
|---|---|---|
| ✓ | BigUint::to_bytes_be (&self) -> Vec<u8> |
to_power_of_2_digits_desc |
| ✓ | BigUint::to_bytes_le (&self) -> Vec<u8> |
to_power_of_2_digits_asc |
| ✓ | BigUint::to_radix_be (&self, radix: u32) -> Vec<u8> |
to_digits_desc |
| ✓ | BigUint::to_radix_le (&self, radix: u32) -> Vec<u8> |
to_digits_asc |
| ✓ | BigUint::to_u32_digits (&self) -> Vec<u32> |
to_power_of_2_digits_asc |
| ✓ | BigUint::to_u64_digits (&self) -> Vec<u64> |
to_limbs_asc |
| ✓ | BigUint::iter_u32_digits (&self) -> U32Digits |
PowerOf2DigitIterable |
| ✓ | BigUint::iter_u64_digits (&self) -> U64Digits |
limbs |
| ≈ | ToPrimitive for BigUint (to_u64, to_i64, to_f64, …) |
TryFrom, RoundingFrom |
| ✓ | TryFrom<&BigUint> for u8..u128, i8..i128 |
TryFrom |
| ✓ | ToBigInt for BigUint (to_bigint) |
From |
| ✓ | BigInt::to_bytes_be (&self) -> (Sign, Vec<u8>) |
Sign, to_power_of_2_digits_desc |
| ✓ | BigInt::to_bytes_le (&self) -> (Sign, Vec<u8>) |
Sign, to_power_of_2_digits_asc |
| ≈ | BigInt::to_signed_bytes_be (&self) -> Vec<u8> |
to_twos_complement_limbs_desc |
| ≈ | BigInt::to_signed_bytes_le (&self) -> Vec<u8> |
to_twos_complement_limbs_asc |
| ✓ | BigInt::to_radix_be (&self, radix: u32) -> (Sign, Vec<u8>) |
Sign, to_digits_desc |
| ✓ | BigInt::to_radix_le (&self, radix: u32) -> (Sign, Vec<u8>) |
Sign, to_digits_asc |
| ✓ | BigInt::to_u32_digits (&self) -> (Sign, Vec<u32>) |
Sign, to_power_of_2_digits_asc |
| ✓ | BigInt::to_u64_digits (&self) -> (Sign, Vec<u64>) |
Sign, to_limbs_asc |
| ✓ | BigInt::iter_u32_digits (&self) -> U32Digits |
PowerOf2DigitIterable |
| ✓ | BigInt::iter_u64_digits (&self) -> U64Digits |
limbs |
| ≈ | ToPrimitive for BigInt |
TryFrom, RoundingFrom |
| ✓ | TryFrom<&BigInt> for u8..u128, i8..i128 |
TryFrom |
| ✓ | TryFrom<BigInt> for BigUint |
TryFrom |
| ✓ | BigInt::magnitude (&self) -> &BigUint |
unsigned_abs_ref |
| ✓ | BigInt::into_parts (self) -> (Sign, BigUint) |
Sign, UnsignedAbs |
| ✓ | BigInt::sign (&self) -> Sign |
Sign |
| ✓ | ToBigUint for BigInt (to_biguint) |
TryFrom |
| ✓ | From<BigUint> for BigInt |
From |
Digits and bytes, outward. The deconstructors mirror the constructors: bytes are base-256
digits through to_power_of_2_digits_desc(8) and _asc(8), to_radix_be and _le are
to_digits_desc(&radix) and _asc with the base-256 ceiling again removed, to_u32_digits
is to_power_of_2_digits_asc(32), and to_u64_digits is to_limbs_asc, with
limbs
and
PowerOf2DigitIterable’s
power_of_2_digits(32) playing the allocation-free roles of iter_u64_digits and
iter_u32_digits. The one recurring difference is zero: num deconstructs it to a single zero
element, vec![0], while Malachite deconstructs it to nothing, an empty Vec or an empty
iterator, so round trips agree but the two libraries’ outputs for zero differ by that element.
The BigInt versions return the num Sign alongside the magnitude’s digits, which is
x.sign() paired with the same calls on x.unsigned_abs_ref(); the signed-bytes pair is the
two’s complement granularity ≈ from the previous section, in
the other direction.
ToPrimitive. The integer targets are the same story as FromPrimitive, Option against
Err: u64::try_from(&n) answers what n.to_u64() answers. The float targets differ more
than shape. num’s to_f64 takes the value’s 64 most significant bits and converts them, so an
input whose discarded lower bits sit against a rounding boundary can land one ulp from the
correctly rounded result; f64::rounding_from(&n, Nearest) rounds the full value correctly,
with the mode explicit and the direction reported. Values beyond f64’s range become
infinity in both libraries.
The magnitude and the sign. BigInt::magnitude borrows the magnitude, and
unsigned_abs_ref
borrows the same thing, a &Natural at no cost; the owning decomposition into_parts is
(x.sign(), x.unsigned_abs()) through the
UnsignedAbs
trait. BigInt::sign maps to Malachite’s
Sign
with a three-for-three dictionary: Plus, NoSign, and Minus are Greater, Equal, and
Less, an Ordering against
zero. Malachite adds one more member here:
mutate_unsigned_abs
gives closure-mediated write access to the magnitude, restoring the sign invariant afterward,
where num offers no mutable path to magnitude()’s target.
Between the types. BigInt::to_biguint and TryFrom<BigInt> for BigUint both answer
Natural::try_from(&x), failing exactly on negatives; BigUint::to_bigint and
From<BigUint> for BigInt are Integer::from(n), infallible. num’s fallible conversions
carry a
TryFromBigIntError,
which for owned conversions returns the original value inside the error; Malachite’s error
types are lighter, and the original is not consumed when the conversion borrows.
Comparison
Both libraries derive or implement the standard comparison traits, and since these are exact types the orders are total, so the table is short; what distinguishes the libraries here is everything Malachite implements beyond it, described after the table.
| num | Malachite | |
|---|---|---|
| ✓ | PartialEq, Eq (BigUint, BigInt) |
PartialEq, Eq |
| ✓ | PartialOrd, Ord (BigUint, BigInt) |
PartialOrd, Ord |
| ✓ | Hash (BigUint, BigInt) |
Hash |
| ✓ | Signed::is_positive, is_negative (BigInt) |
PartialOrd |
The standard traits. Equal values compare and hash equally on both sides, Ord agrees
with the numeric order, and x == y, x < y, and HashMap keys behave identically. The
Signed predicates are spelled as comparisons against a primitive zero, x > 0u32 and
x < 0u32, both false for zero as num’s are; the rest of the Signed trait, abs and its
kin, appears with the operators below.
Mixed comparisons and the magnitude order. num compares its types against themselves;
comparing a
BigUint with a u64 or a BigInt with a BigUint means converting first. Malachite
implements the mixed comparisons directly, in both argument orders: PartialEq and
PartialOrd against every primitive integer, against every primitive float, exactly and
without allocating, and between
Integer and
Natural
across the type boundary. Alongside the value order there is a magnitude order:
OrdAbs,
PartialOrdAbs,
and
EqAbs
compare |x| against |y| without materializing either absolute value, again across the
mixed operand types. In num, a.magnitude().cmp(b.magnitude()) covers the same-type case.
The rest is native-route territory, the drop-in route keeping num’s own API surface.
Arithmetic operators
| num | Malachite | |
|---|---|---|
| ✓ | Add, AddAssign (BigUint, BigInt) |
Add, AddAssign |
| ✓ | Sub, SubAssign |
Sub, SubAssign |
| ✓ | Mul, MulAssign |
Mul, MulAssign |
| ✓ | Div, DivAssign |
Div, DivAssign |
| ✓ | Rem, RemAssign |
Rem, RemAssign |
| ≈ | scalar operators (BigUint ± u32/u64/u128, BigInt ± i32/i64/i128/u32/u64/u128, both orders) |
From |
| ✓ | Neg (BigInt) |
Neg, NegAssign |
| — | CheckedAdd, CheckedMul (BigUint, BigInt), CheckedSub (BigInt) |
|
| ✓ | CheckedSub (BigUint) |
CheckedSub |
| ≈ | CheckedDiv (BigUint, BigInt) |
Div |
| ✓ | Sum, Product (BigUint, BigInt) |
Sum, Product |
| ✓ | Signed::abs (BigInt) |
Abs, AbsAssign |
| ≈ | Signed::abs_sub (BigInt) |
Sub |
| ✓ | Signed::signum (BigInt) |
Sign |
The operators. Full parity, combination by combination: both libraries implement the five
operators and their *Assign forms for owned and borrowed operands, division and remainder
truncate toward zero with the remainder taking the dividend’s sign, dividing by zero panics,
subtracting a larger BigUint or
Natural from
a smaller one panics, and neither unsigned type has Neg. A num expression built from these
operators means the same thing after a find-and-replace of the type names.
The scalar operators. Here the comparison section’s asymmetry runs the other way: num
implements the operators against 32-, 64-, and 128-bit primitives in both operand orders,
while Malachite keeps its operators between its own types and asks for a lift,
x + Natural::from(5u32), exact and cheap for any word-sized value. So num has mixed
operators but not mixed comparisons, and Malachite mixed comparisons but not mixed operators;
the lift is the price of the native route in this direction.
The checked family. Only two of these operations can actually fail on bignums: unsigned
subtraction, where num’s checked_sub and Malachite’s
CheckedSub
both answer None below zero, and division, where num’s checked_div turns the zero-divisor
panic into None and Malachite spells the same guard directly,
(y != 0u32).then(|| x / y). The rest, checked_add, checked_mul, and checked_sub on
BigInt, cannot fail and always return Some; num implements them so that generic code
written against the checked traits accepts bignums, a role that belongs to
the traits page, and Malachite leaves them off the types. In the other direction,
Natural has
a saturating story:
SaturatingSub
and SaturatingSubMul clamp at zero instead of panicking or optioning.
Sum and Product. Both libraries let iterators of values or references fold into a
total, and iter.sum::<Natural>() replaces iter.sum::<BigUint>() unchanged.
The Signed arithmetic. abs is
Abs
with its assign form, and the
UnsignedAbs
variants from Conversion cross into
Natural at
the same time. abs_sub, the positive difference \(\max(a - b, 0)\), is a comparison and a
subtraction spelled out, if a > b { a - b } else { Integer::ZERO }. signum is a match on
Sign:
Greater, Equal, and Less become 1, 0, and -1. The division-family variants,
div_floor and its relatives from num-integer along with num-traits’ Euclid, have a section
of their own next.
The division family
num-integer’s Integer trait and num-traits’ Euclid supply the division variants beyond the
truncating operators, named by convention: div_floor, div_ceil, div_euclid. Malachite
names the same operations by their rounding mode or by the quantity returned; the dictionary
first, the additions after.
| num | Malachite | |
|---|---|---|
| ✓ | Integer::div_floor (&self, other: &Self) -> Self |
DivRound |
| ✓ | Integer::mod_floor (&self, other: &Self) -> Self |
Mod |
| ✓ | Integer::div_mod_floor (&self, other: &Self) -> (Self, Self) |
DivMod |
| ✓ | Integer::div_rem (&self, other: &Self) -> (Self, Self) |
DivRem |
| ✓ | Integer::div_ceil (&self, other: &Self) -> Self |
DivRound |
| ✓ | Integer::is_multiple_of (&self, other: &Self) -> bool |
DivisibleBy |
| ≈ | Integer::next_multiple_of (&self, other: &Self) -> Self |
RoundToMultiple |
| ≈ | Integer::prev_multiple_of (&self, other: &Self) -> Self |
RoundToMultiple |
| ✓ | Euclid::div_euclid (&self, v: &Self) -> Self |
DivEuclidean |
| ✗ | Euclid::rem_euclid (&self, v: &Self) -> Self |
Mod |
| ≈ | CheckedEuclid::checked_div_euclid, checked_rem_euclid |
DivEuclidean |
The floor, ceiling, and truncating divisions. div_floor is x.div_round(&y, Floor),
div_ceil is x.div_round(&y, Ceiling), and num’s doctests are Malachite’s semantics
exactly, (-1).div_floor(&2) giving \(-1\) on both sides. mod_floor is x.mod_op(&y), the
remainder with the divisor’s sign; the simultaneous pair div_mod_floor is
DivMod;
and div_rem, the truncating pair whose remainder takes the dividend’s sign, keeps its exact
name and meaning in Malachite’s
DivRem.
On BigUint and
Natural all
of these coincide with the plain operators. Malachite completes the matrix with
CeilingDivMod
and CeilingMod, the ceiling pair that num does not offer.
Divisibility and multiples. is_multiple_of, and its deprecated alias divides, is
DivisibleBy:
x.divisible_by(&y). The multiple-rounding pair is ≈ for a directional subtlety worth
quoting: num’s next_multiple_of moves in the direction of the divisor’s sign, its doctest
showing (-23).next_multiple_of(&-8) landing at \(-24\), below its argument. Malachite’s
RoundToMultiple
takes the direction as an explicit
RoundingMode,
so next_multiple_of is round_to_multiple with Ceiling for a positive divisor and
Floor for a negative one, and prev_multiple_of the reverse.
Euclidean division. The quotient-remainder convention with the remainder always in
\([0, |d|)\): div_euclid maps directly to
DivEuclidean’s
div_euclidean, with its assign form. The remainder half is a gap: a ModEuclidean
companion to DivEuclidean is planned, and until it lands the operation is one step away,
since a floor remainder by a positive divisor is already Euclidean:
x.mod_op(Integer::from(y.unsigned_abs())). On the
unsigned types, Euclidean, floor, and truncating division are all the same thing, which is how
num implements Euclid for BigUint. The CheckedEuclid pair adds the zero-divisor guard,
answered as checked_div was in
the previous section: test the divisor, then divide.
Beyond the dictionary. Malachite’s division constellation continues past num’s:
DivRound
accepts every RoundingMode, including Nearest with ties to even and the panicking Exact;
DivExact
is the fast path for quotients known to be exact;
EqMod
tests \(x \equiv y \pmod m\) without forming either remainder; and the power-of-2
specializations,
DivisibleByPowerOf2,
ModPowerOf2,
RoundToMultipleOfPowerOf2,
and
EqModPowerOf2,
do their work with shifts and masks. None of these have num counterparts.
Bits and logic
| num | Malachite | |
|---|---|---|
| ✓ | BigUint::bits (&self) -> u64 |
SignificantBits |
| ✓ | BigUint::bit (&self, bit: u64) -> bool |
BitAccess |
| ✓ | BigUint::set_bit (&mut self, bit: u64, value: bool) |
BitAccess |
| ✓ | BigUint::count_ones (&self) -> u64 |
CountOnes |
| ✓ | BigUint::trailing_zeros (&self) -> Option<u64> |
TrailingZeros |
| ✓ | BigUint::trailing_ones (&self) -> u64 |
BitScan |
| ✓ | BigInt::bits (&self) -> u64 |
SignificantBits |
| ✓ | BigInt::bit (&self, bit: u64) -> bool |
BitAccess |
| ✓ | BigInt::set_bit (&mut self, bit: u64, value: bool) |
BitAccess |
| ✓ | BigInt::trailing_zeros (&self) -> Option<u64> |
TrailingZeros |
| ✓ | BitAnd, BitOr, BitXor, *Assign (BigUint) |
BitAnd, BitOr, BitXor |
| ✓ | BitAnd, BitOr, BitXor, *Assign (BigInt) |
BitAnd, BitOr, BitXor |
| ✓ | Not (BigInt) |
Not |
| ≈ | Shl, Shr, *Assign (amounts: u8..usize, i8..isize) |
Shl, Shr |
The bit queries. bits is
significant_bits,
zero for zero and, on the signed types, the magnitude’s bit length in both libraries. bit
and set_bit are
BitAccess’s
get_bit and assign_bit, with set_bit, clear_bit, and flip_bit as finer-grained
spellings, and the semantics on negative values agree exactly, num reading and writing “using
the two’s complement for negative numbers” as
Integer
does. count_ones is
CountOnes;
trailing_zeros matches down to the return type, Option<u64> with None for zero; and
trailing_ones is
BitScan’s
index_of_next_false_bit(0), the first clear bit being one past the trailing ones.
The bitwise operators. Present in all operand combinations on both sides, with BigInt
and Integer agreeing on two’s complement semantics for negatives, and !x = -x - 1 through
Not on the signed types. One implementation exists only on the Malachite side: Not for
Natural,
crossing into Integer for the result, since the complement of an unsigned value is negative.
The shifts. Both libraries shift by any primitive integer type, and >> on the signed
types is arithmetic, rounding toward negative infinity, in both. The ≈ is what a negative
signed amount means, and it is a real behavioral divergence: num panics, “attempt to shift
left with negative”, while Malachite reverses direction, x << -3 meaning x >> 3, a
deliberate convention used throughout the library. Ported code that never shifts by a negative
amount is unaffected; code that relied on the panic as a guard will silently compute instead.
Beyond the dictionary. Malachite’s logic module keeps going:
BitScan
finds the next set or clear bit from any starting index, not just index zero;
BitBlockAccess
reads and writes whole bit ranges;
BitIterable
iterates over bits and
BitConvertible
converts to and from bit vectors;
HammingDistance
counts differing bits on Natural, with
CheckedHammingDistance
answering None for Integers of opposite sign; and Integer gets checked_count_ones and
checked_count_zeros, defined exactly when the two’s complement expansion makes them finite.
Powers and roots
| num | Malachite | |
|---|---|---|
| ✓ | pow (&self, exponent: u32); Pow (exponents u8..u128, usize, BigUint) |
Pow, PowAssign |
| ✓ | BigUint::modpow (&self, exponent: &Self, modulus: &Self) -> Self |
ModPow |
| ≈ | BigInt::modpow (&self, exponent: &Self, modulus: &Self) -> Self |
Mod, ModPow |
| ✓ | BigUint::modinv (&self, modulus: &Self) -> Option<Self> |
ModInverse |
| ≈ | BigInt::modinv (&self, modulus: &Self) -> Option<Self> |
Mod, ModInverse |
| ✓ | Roots::sqrt, cbrt, nth_root (n: u32) (BigUint) |
FloorSqrt, FloorRoot |
| ✓ | Roots::sqrt (BigInt) |
FloorSqrt |
| ≈ | Roots::cbrt, nth_root (BigInt) |
FloorRoot, CeilingRoot |
Powers. num spreads exponentiation across an inherent pow taking u32 and Pow
implementations taking every unsigned primitive and even a BigUint; Malachite’s
Pow
takes a u64, with
PowAssign
in place. The bignum-exponent implementations are wider in type only: any power a machine
could ever finish computing has an exponent that fits comfortably in a u64, so
u64::try_from(&e) loses nothing but the out-of-memory outcome.
Modular exponentiation and inversion. BigUint::modpow is
ModPow’s
x.mod_pow(&e, &m), and BigUint::modinv is
ModInverse’s
x.mod_inverse(&m), Option for Option, None exactly when no inverse exists. The
BigInt versions are ≈ because Malachite’s modular arithmetic lives on
Natural
residues: num documents that its modpow “rounds like mod_floor, not like the %
operator”, putting results in \([0, m)\) for a positive modulus, so the mapping reduces first
with x.mod_op(&m), whose floor semantics are the same, and exponentiates the reduced
residue; a negative num modulus, with results in \((m, 0]\), follows from the same reduction
by \(|m|\) and a shift by \(m\). num’s panics, on a negative exponent and on a zero modulus,
have no occasion to arise once the operands are residues by construction.
Roots. All roots agree on the unsigned types: num-integer’s sqrt, cbrt, and
nth_root are floor roots, floor_sqrt and floor_root(n). On the signed types the even
cases agree, both libraries panicking on an even root of a negative number, but odd roots of
negative values diverge: num truncates toward zero, its own doctest sending
(i32::MIN + 1).nth_root(31) to \(-1\), while floor_root floors, sending the same value to
\(-2\). num’s behavior on a negative argument is therefore Malachite’s
CeilingRoot:
if x >= 0 { x.floor_root(n) } else { x.ceiling_root(n) } reproduces nth_root exactly.
Beyond the dictionary. Every root comes in three rounding flavors and an assign form:
FloorSqrt, CeilingSqrt, and
CheckedSqrt,
which answers Some only for perfect squares, with the same triple for general roots; and
SqrtRem
and RootRem return the root together with the remainder in one pass.
Square
is the dedicated squaring num spells as &x * &x. The power-of-2 family,
PowerOf2,
IsPowerOf2, and NextPowerOf2, and the integer logarithms, floor_log_base_2,
ceiling_log_base_2, and their general-base and checked relatives, are further additions. On
the modular side, Malachite continues into the
ModPowerOf2
tower, arithmetic modulo \(2^k\) with its own mod_power_of_2_pow and
mod_power_of_2_inverse, where masks and shifts replace division throughout.
GCD and parity
| num | Malachite | |
|---|---|---|
| ✓ | Integer::gcd (&self, other: &Self) -> Self (BigUint) |
Gcd, GcdAssign |
| ✓ | Integer::lcm (&self, other: &Self) -> Self (BigUint) |
Lcm, LcmAssign |
| ≈ | Integer::gcd (BigInt) |
UnsignedAbs, Gcd |
| ≈ | Integer::lcm (BigInt) |
UnsignedAbs, Lcm |
| ≈ | Integer::gcd_lcm (&self, other: &Self) -> (Self, Self) |
Gcd, Lcm |
| ≈ | Integer::extended_gcd, extended_gcd_lcm (BigInt) |
ExtendedGcd |
| ✓ | Integer::is_even, is_odd (BigUint, BigInt) |
Parity |
GCD and LCM. On the unsigned types the mapping is direct, x.gcd(&y) on both sides, with
gcd(0, 0) = 0 and the assign forms in place. Malachite keeps
Gcd
and Lcm on
Natural
only, on the argument that a GCD is a property of magnitudes; num’s BigInt versions, which
also return nonnegative results, are the same values through
a.unsigned_abs().gcd(b.unsigned_abs()), lifted back with Integer::from when the signed
type is wanted. gcd_lcm returns both at once, and one GCD suffices for the pair:
let g = (&a).gcd(&b); then let l = (&a / &g) * &b;, with the zero pair handled first.
The extended GCD. Both libraries compute the Bézout triple, gcd with cofactors x and
y satisfying \(\gcd = ax + by\), num returning its ExtendedGcd struct and Malachite a
tuple. The cofactors are signed by nature, even for unsigned inputs, and the two libraries
respond differently: Malachite’s
ExtendedGcd
is implemented for Natural and
Integer
alike, with the cofactors always Integers, while num’s BigUint instantiation inherits a
default implementation whose intermediate subtractions require signed values, so the usable
form is BigInt’s. Each library documents its own normalization of the cofactor pair, so
ported code should rely on the Bézout identity rather than on particular cofactor values.
extended_gcd_lcm composes the triple with the one-GCD lcm spelling above.
Parity. is_even and is_odd are
Parity’s
x.even() and x.odd(), on both types.
Beyond the dictionary. Malachite adds
CoprimeWith,
a dedicated coprimality test that can stop earlier than a full GCD, and the number-theoretic
symbols, LegendreSymbol,
JacobiSymbol, and KroneckerSymbol, on both types. In the other direction, num-integer
defines an Average trait, but num-bigint does not implement it for the bignum types, so it
reappears with the generic machinery on the traits page; Malachite has no averaging functions
either, and a
(&a + &b) >> 1 computes the floor average exactly, bignums having no overflow to dodge.
Random generation
Under num’s rand feature, the RandBigInt trait extends any rand::Rng with bignum
generators, and adapter types plug the bignums into rand’s distribution machinery. Malachite’s
random feature is a self-contained framework instead: generators take a
Seed and
return infinite iterators, and the per-call get_random_* functions draw from a
RandomPrimitiveInts source built from one. The same uniform distributions are on both sides;
what differs is who owns the randomness.
| num | Malachite | |
|---|---|---|
| ✓ | RandBigInt::gen_biguint (&mut self, bit_size: u64) -> BigUint |
get_random_natural_with_up_to_bits |
| ✓ | RandBigInt::gen_bigint (&mut self, bit_size: u64) -> BigInt |
get_random_natural_with_up_to_bits, from_sign_and_abs |
| ✓ | RandBigInt::gen_biguint_below (&mut self, bound: &BigUint) -> BigUint |
get_random_natural_less_than |
| ✓ | RandBigInt::gen_biguint_range (&mut self, lbound: &BigUint, ubound: &BigUint) -> BigUint |
uniform_random_natural_range |
| ✓ | RandBigInt::gen_bigint_range (&mut self, lbound: &BigInt, ubound: &BigInt) -> BigInt |
get_uniform_random_integer_from_range |
| — | RandomBits (a rand Distribution) |
|
| — | UniformBigUint, UniformBigInt (rand SampleUniform backends) |
The generators. gen_biguint draws uniformly among values of up to bit_size bits, which
is get_random_natural_with_up_to_bits; the exactly-n-bits refinement,
get_random_natural_with_bits,
is there when the top bit must be set. gen_bigint attaches a random sign to a random
magnitude, which is the same draw wrapped in
from_sign_and_abs
with a coin flip. The bounded draws map directly: gen_biguint_below is
get_random_natural_less_than, and the half-open ranges are the uniform_random_*_range
generators, with
get_uniform_random_integer_from_range
as the per-call form on
Integer; on
Natural the
per-call range draw is low + get_random_natural_less_than(&mut source, &(high - low)). Empty
ranges panic on both sides.
The adapters. RandomBits, UniformBigUint, and UniformBigInt exist to plug the bignum
types into rand’s Distribution and gen_range machinery. Malachite’s framework has no
separate adapter layer: a seeded iterator like uniform_random_natural_range is the
distribution object, bound to its source, so these rows need no counterpart.
Beyond the dictionary. The generators described on
the other pages are all here too:
mean-parameterized streams like
random_naturals,
the striped families whose long runs of ones and zeros probe corner cases, sign-restricted
Integer streams, and ranges unbounded above through random_natural_range_to_infinity.
Strings, formatting, and serde
| num | Malachite | |
|---|---|---|
| ✓ | Display, Debug (BigUint, BigInt) |
Display, Debug |
| ✓ | Binary, Octal, LowerHex, UpperHex |
Binary, Octal, LowerHex, UpperHex |
| ✓ | to_str_radix (&self, radix: u32) -> String |
ToStringBase |
| ≈ | FromStr (error: ParseBigIntError) |
FromStr |
| ✓ | Num::from_str_radix (s: &str, radix: u32) -> Result |
FromStringBase |
| ✓ | parse_bytes (buf: &[u8], radix: u32) -> Option |
FromStringBase |
| ≈ | Serialize, Deserialize |
Serialize, Deserialize |
Formatting. Display prints decimal, Debug prints exactly what Display prints, in
both libraries, and the radix formatting traits are present on both sides with the #
alternate prefixes. Beyond the formatter traits, to_str_radix handles bases 2 through 36 in
lowercase;
ToStringBase
covers the same range with to_string_base, and adds to_string_base_upper, upper-case
digits in any base rather than only the hexadecimal 16. Negative values print with a leading
- everywhere.
Parsing. FromStr parses base 10 on both sides, ≈ only in its error type: num returns a
ParseBigIntError describing the failure, Malachite’s base-10 parse signals it with a unit
error. from_str_radix and its byte-slice twin parse_bytes are
FromStringBase’s
from_string_base(base, s), Option-returning as parse_bytes is, accepting the same
case-insensitive digits.
serde. Both libraries serialize stably and portably, and in mutually incompatible forms.
num-bigint writes a BigUint as a sequence of base-\(2^{32}\) digits, a format its source
pledges to keep independent of the internal representation; Malachite writes a hexadecimal
string, "0x1f4", the same on every platform and Limb width. In a JSON snapshot the same
value is an array of numbers under num and a string under Malachite, so serialized data does
not migrate between the libraries directly; it crosses through any of the explicit forms from
Conversion, bytes, digits, or strings, re-serialized on the other side.
That closes the type-level mapping. What remains of the num-bigint experience is its generic
face, the num-traits and num-integer traits themselves, which the traits page, next in this
family, takes up for code written against T: Num rather than a concrete bignum.