Crate rug [−] [src]
Arbitrary-precision numbers
Rug provides integers and floating-point numbers with arbitrary precision and correct rounding. Its main features are
- bignum integers with arbitrary precision,
- bignum rational numbers with arbitrary precision,
- multi-precision floating-point numbers with correct rounding, and
- multi-precision complex numbers with correct rounding.
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 1.0.0 coming soon
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.
Getting started
Setting up the crate
To use Rug in your crate, add it as a dependency inside Cargo.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:
extern crate rug;
More details are available in the Crate usage section below.
Quick example
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:
extern crate rug; use rug::{Assign, Integer}; fn main() { let mut int = Integer::new(); assert_eq!(int, 0); int.assign(14); assert_eq!(int, 14); int.assign(Integer::parse("12_345_678_901_234_567_890").unwrap()); assert!(int > 100_000_000); let hex_160 = "ffff0000ffff0000ffff0000ffff0000ffff0000"; int.assign(Integer::parse_radix(hex_160, 16).unwrap()); assert_eq!(int.significant_bits(), 160); int = (int >> 128) - 1; assert_eq!(int, 0xfffe_ffff_u32); }
Some points from this example follow:
Integer::new()
creates a newInteger
intialized to zero.- To assign values to Rug types, we use the
Assign
trait and its methodassign
. We do not use the assignment operator=
as that would move the left-hand-side operand, which would have the same type. - Arbitrary precision numbers can hold numbers that are too large
to fit in a primitive type. To assign such a number to the large
types, we use strings rather than primitives; in the example
this is done using both
Integer::parse
andInteger::parse_radix
. - We can compare Rug types with primitive types or with other Rug
types using the normal comparison operators, for example
int > 100_000_000_000
. - Most arithmetic operations are supported with Rug types and
primitive types on either side of the operator, for example
int >> 128
.
Using primitive types
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:
- Where they make sense, all arithmetic operators are overloaded
to work with Rug types and the primitives
i32
,u32
,f32
andf64
. - Where they make sense, conversions using the
From
trait and assignments using theAssign
trait are supported for all the primitives in 1 above as well as the other primitivesi8
,i16
,i64
,isize
,u8
,u16
,u64
andusize
. - Comparisons between Rug types and all the primitives listed in 1 and 2 above are supported.
- For
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. - For
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
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
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
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.
Incomplete computation values
There are two main reasons why operations like &a - &b
do not
perform a complete computation and return a Rug type:
- Sometimes we need to assign the result to an object that already exists. Since Rug types require memory allocations, this can help reduce the number of allocations.
- For the
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 theComplex
type.
There are two things that can be done with incomplete computatin values:
- Assign them to an existing object without unnecessary
allocations. This is usually achieved using the
Assign
trait or a similar method, for exampleint.assign(incomplete)
andfloat.assign_round(incomplete, Round::Up)
. - Convert them to the final value using the
From
trait or a similar method, for exampleInteger::from(incomplete)
andFloat::with_val(53, incomplete)
.
Let us consider a couple of examples.
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.
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:
- unary operators applied to references, for example
-&int
; - binary operators applied to two references, for example
&int1 + &int2
; - binary operators applied to a primitive and a reference, for
example
&int * 10
; - methods that take a reference, for example
int.abs_ref()
; - methods that take two references, for example
int1.div_rem_ref(&int2)
; - string parsing, for example
Integer::parse("12")
; - and more…
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.
Crate usage
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:
- the GNU Multiple Precision Arithmetic Library (GMP),
- the GNU MPFR Library, a library for multiple-precision floating-point computations, and
- GNU MPC, a library for the arithmetic of complex numbers with arbitrarily high precision.
It can be helpful to refer to the documentation of the gmp-mpfr-sys crate and of the GMP, MPFR and MPC libraries.
Optional features
The Rug crate has six optional features:
integer
, enabled by default. Required for theInteger
type and its supporting features.rational
, enabled by default. Required for theRational
type and its supporting features. This feature requires theinteger
feature.float
, enabled by default. Required for theFloat
type and its supporting features.complex
, enabled by default. Required for theComplex
type and its supporting features. This feature requires thefloat
feature.rand
, enabled by default. Required for theRandState
type and its supporting features. This feature requires theinteger
feature.serde
, disabled by default. This provides serialization support for theInteger
,Rational
,Float
andComplex
types, providing that they are enabled. This features 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:
[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.
Modules
complex |
Multi-precision complex numbers with correct rounding. |
float |
Multi-precision floating-point numbers with correct rounding. |
integer |
Aribtrary-precision integers. |
ops |
Operations on numbers. |
rand |
Random number generation. |
rational |
Arbitrary-precision rational numbers. |
Structs
Complex |
A multi-precision complex number with arbitrarily large precision and correct rounding. |
Float |
A multi-precision floating-point number with arbitrarily large precision and correct rounding |
Integer |
An arbitrary-precision integer. |
Rational |
An arbitrary-precision rational number. |
Traits
Assign |
Assigns to a number from another value. |