Rug provides integers and floating-point numbers with arbitrary precision and correct rounding. Its main features are
This crate is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. See the full text of the GNU LGPL and GNU GPL for details.
Version 0.10.0 is meant to be the last release before version 1.0.0. Unless some issue is discovered, version 1.0.0 will be like version 0.10.0 with all the deprecated items removed.
To use Rug in your crate, add it as a dependency inside Cargo.toml:
toml
[dependencies]
rug = "0.10.0"
This crate depends on the low-level bindings in the gmp-mpfr-sys crate which needs some setup to build; the gmp-mpfr-sys documentation has some details on usage under GNU/Linux, macOS and Windows.
You also need to declare the crate by adding this to your crate root:
rust
extern crate rug;
More details are available in the Crate usage section below.
For many operations, you can use the arbitrary-precision types such as
Integer like you use primitive types such as
i32. The main difference is that the Rug types do not
implement Copy. This is because they store their digits
in the heap, not on the stack, and copying them could involve an
expensive deep copy.
This code uses the Integer type:
```rust extern crate rug; use rug::{Assign, Integer};
fn main() { let mut int = Integer::new(); asserteq!(int, 0); int.assign(14); asserteq!(int, 14); int.assign(Integer::parse("12345678901234567890").unwrap()); assert!(int > 100000000); let hex160 = "ffff0000ffff0000ffff0000ffff0000ffff0000"; int.assign(Integer::parseradix(hex160, 16).unwrap()); asserteq!(int.significantbits(), 160); int = (int >> 128) - 1; asserteq!(int, 0xfffeffffu32); } ```
Some points from this example follow:
Integer::new() creates a new Integer
intialized to zero.Assign
trait and its method assign. We do not use
the assignment operator = as that would move
the left-hand-side operand, which would have the same type.Integer::parse and
Integer::parse_radix.int > 100_000_000_000.int >> 128.With Rust primitive types, arithmetic operators usually operate on two
values of the same type, for example 12i32 + 5i32. Unlike primitive
types, conversion to and from Rug types can be expensive, so the
arithmetic operators are overloaded to work on many combinations of
Rug types and primitives. The following are provided:
i32,
u32, f32 and f64.From
trait and assignments using the Assign trait are
supported for all the primitives in 1 above as well as the other
primitives i8, i16, i64,
isize, u8, u16,
u64 and usize.Rational numbers, operations are also supported
for tuples containing two primitives: the first is the numerator
and the second is the denominator which cannot be zero. The two
primitives do not need to have the same type.Complex numbers, operations are also supported for
tuples containing two primitives: the first is the real part and
the second is the imaginary part. The two primitives do not need to
have the same type.Operators are overloaded to work on Rug types alone or on a combination of Rug types and Rust primitives. When at least one operand is an owned Rug type, the operation will consume that type and return a Rug type. For example
rust
use rug::Integer;
let a = Integer::from(10);
let b = 5 - a;
assert_eq!(b, 5 - 10);
Here a is consumed by the subtraction, and b is an owned
Integer.
If on the other hand there are no owned Rug types and there are references instead, the returned value is not the final value, but an incomplete computation value. For example
rust
use rug::Integer;
let (a, b) = (Integer::from(10), Integer::from(20));
let incomplete = &a - &b;
// This would fail to compile: assert_eq!(incomplete, -10);
let sub = Integer::from(incomplete);
assert_eq!(sub, -10);
Here a and b are not consumed, and incomplete is not the final
value. It still needs to be converted or assigned into an
Integer. The reason is explained in the section about
incomplete computation values.
The left shift << and right shift >> operators support shifting by
negative values, for example a << 5 is equivalent to a >> -5. The
shifting operators are also supported for the Float and
Complex types, where they are equivalent to
multiplication or division by a power of two.
There are two main reasons why operations like &a - &b do not
perform a complete computation and return a Rug type:
Float type, we need to know the precision when
we create a value, and the operation itself does not convey
information about what precision is desired for the result. The
same holds for the Complex type.There are two things that can be done with incomplete computation values:
Assign trait or
a similar method, for example
int.assign(incomplete) and
float.assign_round(incomplete, Round::Up).From trait
or a similar method, for example
Integer::from(incomplete) and
Float::with_val(53, incomplete).Let us consider a couple of examples.
rust
use rug::{Assign, Integer};
let mut buffer = Integer::new();
// ... buffer can be used and reused ...
let (a, b) = (Integer::from(10), Integer::from(20));
let incomplete = &a - &b;
buffer.assign(incomplete);
assert_eq!(buffer, -10);
Here the assignment from incomplete into buffer does not require
an allocation unless the result does not fit in the current capacity
of buffer. And even then, the reallocation would take place before
the computation, so no copies are involved. If &a - &b returned an
Integer instead, then an allocation would take place even
if it is not necessary.
rust
use rug::Float;
use rug::float::Constant;
// x has a precision of 10 bits, y has a precision of 50 bits
let x = Float::with_val(10, 180);
let y = Float::with_val(50, Constant::Pi);
let incomplete = &x / &y;
// z has a precision of 45 bits
let z = Float::with_val(45, incomplete);
assert!(57.295 < z && z < 57.296);
The precision to use for the result depends on the requirements of the
algorithm being implemented. Here c is created with a precision of
45.
In these two examples, we could have left out the incomplete
variables altogether and used buffer.assign(&a - &b) and
Float::with_val(45, &x / &y) directly.
Many operations can return incomplete computation values:
-∫&int1 + &int2;&int * 10;int.abs_ref();int1.div_rem_ref(&int2);Integer::parse("12");These operations return objects that can be stored in temporary
variables like incomplete in the last few examples. However, the
names of the types are not public, and consequently, the incomplete
computation values cannot be for example stored in a struct. If you
need to store the value in a struct, convert it to its final type and
value.
Rug requires rustc version 1.18.0 or later.
This crate depends on the low-level bindings in the gmp-mpfr-sys crate, which provides Rust FFI bindings for:
It can be helpful to refer to the documentation of the gmp-mpfr-sys crate and of the GMP, MPFR and MPC libraries.
The Rug crate has six optional features:
integer, enabled by default. Required for the
Integer type and its supporting features.rational, enabled by default. Required for the
Rational type and its supporting features. This
feature requires the integer feature.float, enabled by default. Required for the Float
type and its supporting features.complex, enabled by default. Required for the
Complex type and its supporting features. This feature
requires the float feature.rand, enabled by default. Required for the
RandState type and its supporting features. This
feature requires the integer feature.serde, disabled by default. This provides serialization support
for the Integer, Rational,
Float and Complex types, providing that
they are enabled. This feature requires the
serde crate.The first five optional features are enabled by default; to use features selectively, you can add the dependency like this to Cargo.toml:
toml
[dependencies.rug]
version = "0.10.0"
default-features = false
features = ["integer", "float", "rand"]
Here only the integer, float and rand features are enabled. If
none of the features are selected, the gmp-mpfr-sys crate is
not required and thus not enabled. In that case, only the
Assign trait and some other traits are
provided by the crate.