You can think of it as first generating (0, 0), whose sum is 0; then (1, 0) and (0, 1), whose sum is 1; then (2, 0), (1, 1), and (0, 2), whose sum is 2; and so on. This path describes a bijection between the indices 0, 1, 2, ..., and all pairs of natural numbers. The opposite direction of this bijection, that takes pairs to indices, is known as the Cantor pairing function.
This bijection has some nice properties; for example, the function from pairs to indices is a polynomial in the elements of the pair: the pair $$(x, y)$$ corresponds to index $$\tfrac{1}{2}(x + y)(x + y + 1)$$. We can also look at the two functions from sequence index to the first and second elements of the pairs. These functions look like this:
Although the functions jump around a lot (they have to, since they must evaluate to every natural number infinitely many times), there's a sense in which they are nicely balanced. Both are $$O(\sqrt n)$$, and if you take evaluate them at a random large input, they're generally about the same size:
However, it isn't obvious how generalize the Cantor pairing function to triples in a balanced way. The standard way to create a tripling function from a pairing function is $$g(x, y, z) = f(x, f(y, z))$$, but this is no longer balanced. If $$f$$ is the Cantor pairing function, then the three outputs of $$g^{-1}$$ are $$O(\sqrt n)$$, $$O(\sqrt[4] n)$$, and $$O(\sqrt[4]n)$$. Here's what the corresponding table looks like:
## More balance and flexibility with bit interleaving
Instead of the Cantor pairing function, Malachite uses bit interleaving. This idea is not new; it has been described by [Steven Pigeon](https://hbfs.wordpress.com/2011/09/27/pairing-functions/) and others.
To generate the pairs corresponding to index 0, 1, 2, and so on, first write the indices in binary, with infinitely many leading zeros:
And then distribute the bits of each index into the two slots of the corresponding pair. The even-indexed bits (counting from the right) end up in the second slot, and the odd-indexed bits in the first:
I've color-coded the bits according to which slot they end up in. Malachite keeps track of this using an explicit bit map that looks like $$[1, 0, 1, 0, 1, 0, \ldots]$$, indicating that bit 0 goes to slot 1, bit 1 goes to slot 0, bit 2 goes to slot 1, and so on.
This is how this method walks through the grid of pairs of natural numbers:
This path is called a [Z-order curve](https://en.wikipedia.org/wiki/Z-order_curve), although with this choice of coordinates it looks like it's made up of N's rather than Z's.
And here's what the functions from the index to the first and second elements of the pairs look like:
Like the inverses of the Cantor pairing function, these functions are balanced in the sense that both are $$O(\sqrt n)$$, although here the first element lags noticeably behind the second. And here's a table showing them evaluated at large indices:
The advantage that this approach has over the Cantor pairing approach is flexibility. We can generate triples in a balanced way simply by changing the bit map to $$[2, 1, 0, 2, 1, 0, 2, 1, 0, \ldots]$$:
Here are the three functions from index to output. They each are $$O(\sqrt[3]n)$$.
Here they are evaluated at large indices:
This generalizes straightforwardly to $$k$$-tuples for any $$k$$. Notice that the first $$2^{ka}$$ tuples are all the tuples with elements less than $$2^a$$.
## Customized balancing
By changing the bit map further, we can deliberately unbalance the tuples. For example, if we want to produce pairs where the second element of the pair is $$O(\sqrt[3]n)$$ and the first element is $$O(n^{2/3})$$, we can use the bit map $$[1, 0, 0, 1, 0, 0, 1, 0, 0, \ldots]$$. If we want the the first element to be exponentially larger than the second, we can use $$[0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, \ldots]$$, where there is a 1 at the $$2^i$$th position and 0 elsewhere.
To actually generate the pair sequences in the two preceding examples, you can use
```rust
exhaustive_pairs_custom_output(
exhaustive_naturals(),
exhaustive_naturals(),
BitDistributorOutputType::normal(2),
BitDistributorOutputType::normal(1),
)
```
and
```rust
exhaustive_pairs_custom_output(
exhaustive_naturals(),
exhaustive_naturals(),
BitDistributorOutputType::normal(1),
BitDistributorOutputType::tiny(),
)
```
respectively. See the documentation of [exhaustive_pairs_custom_output](https://docs.rs/malachite-base/0.2.4/malachite_base/tuples/exhaustive/fn.exhaustive_pairs_custom_output.html) and [BitDistributorOutputType](https://docs.rs/malachite-base/latest/malachite_base/iterators/bit_distributor/struct.BitDistributorOutputType.html) for more details.
## Generating tuples of other iterators
So far I've only talked about generating tuples of `Natural`s. What about tuples of elements from some other iterator `xs`? If `xs` is infinitely long, then the process is straightforward. Instead of generating, say, (8, 3), generate the pair consisting of the 8th and 3rd elements of `xs` (indexing from 0, of course). Internally, Malachite uses a structure called [`IteratorCache`](https://docs.rs/malachite-base/latest/malachite_base/iterators/iterator_cache/struct.IteratorCache.html), which stores the values produced by `xs` into a `Vec` for easy access.
For example, here's how to generate all pairs of the characters `'a'` to `'z'` (in this case, there are additional complications due to `xs` being finite, but we'll address those in a moment):
```rust
for p in exhaustive_pairs_from_single('a'..='z').take(10) {
println!("{:?}", p);
}
```
```
(a, a)
(a, b)
(b, a)
(b, b)
(a, c)
(a, d)
(b, c)
(b, d)
(c, a)
(c, b)
```
## Dealing with finite iterators
Finite iterators are a bit of a problem. You can't generate the (8th, 3rd) pair if the input iterator has no 8th element. To take an extreme case, consider `exhaustive_pairs(exhaustive_naturals(), exhaustive_bools())`. There are only two bools, so any index pair $$(i, j)$$ where $$j \geq 2$$ can't be used for indexing. Here's our grid of indices again, with valid indices green and invalid indices red:
My original solution was just to skip over the invalid indices, with a bit of extra logic to determine when both input iterators are finished. This was very slow: out of the first $$n$$ pairs, only about $$2 \sqrt n$$ are valid, and the situation gets worse for higher-arity tuples. So what does `exhaustive_pairs` do instead?
Again, we can leverage the bit map! This scenario is actually what led me to make the bit map an explicit object in memory. What `exhaustive_pairs` does is notice when one of its iterators has completed, and then adjusts the bit map on the fly. In this particular case, it realizes that since `exhaustive_bools` produces two elements, it only needs a single bit for indexing; and then bit map is modified from $$[1, 0, 1, 0, 1, 0, 1, 0, \ldots]$$, to $$[1, 0, 0, 0, 0, 0, 0, \ldots]$$. In general, modifying the bit map on the fly is dangerous because you might end up repeating some output that you've already produced, but `exhaustive_pairs` only modifies the part of the map that hasn't been used yet.
If the finite iterator's length is a power of 2, as it was in this example, then updating the bit map results in all indices being valid. If it isn't a power of 2, then some indices will remain invalid; for example, in `exhaustive_pairs(exhaustive_naturals(), 0..6)` the bit map will be updated from $$[1, 0, 1, 0, 1, 0, 1, 0, \ldots]$$, to $$[1, 0, 1, 0, 1, 0, 0, 0, \ldots]$$, so that the index of the second pair slot will vary from 0 to 7, and only $$3/4$$ of all the indices will be valid. But this is a constant proportion; it's much better than the earlier example where only $$(2 \sqrt n)/n$$ were valid.
(In this particular case, the best thing to do would be to use `lex_pairs(exhaustive_naturals(), exhaustive_bools())`, which would produce (0, false), (0, true), (1, false), (1, true), and so on. But in general, when you call `exhaustive_pairs(xs, ys)` you might not know ahead of time whether `ys` is short, long, or infinite.)
In the next part, I will discuss how Malachite generates all `Vec`s containing elements from some iterator.
================================================
FILE: docs/_posts/2022-07-30-denominators.md
================================================
---
layout: post
title: Which denominators does an interval contain?
author: Mikhail Hogrefe
---
## Introduction
In this post I'm going to talk a bit about a problem that came up when I was figuring out how to generate rational numbers exhaustively. Malachite generates all positive rationals using the [Calkin-Wilf sequence](https://en.wikipedia.org/wiki/Calkin%E2%80%93Wilf_tree#Breadth_first_traversal):
1, 1/2, 2, 1/3, 3/2, 2/3, 3, 1/4, 4/3, 3/5, 5/2, 2/5, 5/3, 3/4, 4, 1/5, 5/4, 4/7, 7/3, 3/8, ...,
and by manipulating this sequence a bit it can also generate all rationals, all negative rationals, and so on. How about generating all rationals in a specified interval? This has many uses: for example, when testing conversion from rationals to floats, we might want to generate rationals that fall into the 64-bit subnormal float range.
For the remainder of this post I'm going to consider closed intervals only.
## First try
The most straightforward approach is this:
1. Generate all rationals in $$[0, 1]$$.
2. Scale those rationals to bring them into the target interval.
Step 1 is easy: we can generate 0 and 1, and then select every other rational from the above sequence:
0, 1, 1/2, 1/3, 2/3, 1/4, 3/5, 2/5, 3/4, 1/5, 4/7, 3/8, 5/7, 2/7, 5/8, 3/7, 4/5, 1/6, 5/9, 4/11, ... .
Step 2 is also easy. If our target interval is $$[a, b]$$, we transform each rational using $$x \to (b - a)x + a$$. For example, here are the rationals in $$[1/3, 1/2]$$:
1/3, 1/2, 5/12, 7/18, 4/9, 3/8, 13/30, 2/5, 11/24, 11/30, 3/7, 19/48, 19/42, 8/21, 7/16, 17/42, 7/15, 13/36, 23/54, 13/33, ... .
For a simple interval this approach works fine. But what if we generate intervals in $$[268876667/98914198, 245850922/78256779]$$? The endpoints of this interval are the simplest rationals that round to the best 64-bit float representations of $$e$$ and $$\pi$$, respectively. Our algorithm gives us
268876667/98914198, 245850922/78256779, 45359568684866149/15481413065696484, 33200495296270871/11611059799272363, 69677715462056705/23222119598544726, 87442412500217335/30962826131392968, 19172880691153809/6450588777373535, 111760559277407891/38703532664241210, 31331954079749087/10320942043797656, 54241917203946464/19351766332120605, ... .
This is not so nice. Our interval contains nice rationals like 3, 11/4, 14/5, and 17/6, but they are nowhere to be seen (they will appear eventually, but much later in the sequence). We want an algorithm that gives preferential treatment to rationals with small denominators. Here's what Malachite does:
An improved algorithm
---------------------
Malachite's algorithm needs to be able to do three things:
1. Determine which denominators occur in an interval;
2. Generate all rationals with a given denominator in an interval;
3. Given infinitely many iterators, each generating rationals with different denominators, interleave the iterators into a single iterator.
Number 2 is easy to do and not very interesting. You can see the details [here](https://docs.rs/malachite-q/latest/malachite_q/exhaustive/fn.exhaustive_rationals_with_denominator_inclusive_range.html). Number 3 is more interesting, but already solved. I'll post about it in the future, but for now I'll just leave a link to the relevant function [here](https://docs.rs/malachite-base/latest/malachite_base/tuples/exhaustive/fn.exhaustive_dependent_pairs.html). That leaves number 1.
## Finding all denominators in an interval
Let's define the problem more explicitly.
**Problem:** Given a closed interval $$[a, b]$$ with $$a, b \in \mathbb{Q}$$ and $$a < b$$, for which $$d \in \N^+$$ does there exist an $$n \in \Z$$ with $$\gcd(n, d) = 1$$ and $$n/d \in [a, b]$$?
The simplest algorithm is to consider each denominator 1, 2, 3, ... in turn and determine whether some rational with the denominator exists in the interval. This works fine unless the diameter $$b - a$$ is very small. If the interval is $$[0, 2^{-100}]$$, it would take a very long time to find an admissible denominator greater than 1.
Luckily, Malachite knows how to find the simplest rational in an interval ("simplest" meaning "having the lowest denominator"). It uses the continued fractions of the endpoints and follows the algorithm sketched out [here](https://en.wikipedia.org/wiki/Continued_fraction#Best_rational_approximations). This gives us the lowest denominator in the interval in $$O(n^2 \log n \log\log n)$$ time, $$n$$ being the maximum bit-length of the numerators and denominators of both endpoints. Once we've found the lowest denominator, we can find the $$m$$ rationals with that denominator in $$[a, b]$$ and then partition $$[a, b]$$ into $$m + 1$$ smaller intervals. Then we can repeat the process to get the second-lowest denominator, and so on.
This algorithm is efficient enough to be useful, but it's still a bit cumbersome. Our intuition suggests that $$[a, b]$$ contains every denominator in $$\N^+$$ except for finitely many exceptions: in other words, that for every interval $$[a, b]$$ there exists a threshold $$D$$ such that for all $$d \geq D$$, $$[a, b]$$ contains a rational with denominator $$d$$. If we knew what $$D$$ was, then we could find start finding denominators using our cumbersome continued-fraction method, but once we reached $$D$$ we could simply generate $$D, D + 1, D + 2, \ldots$$ forever.
For the remainder of this post, I'll prove that a $$D$$ exists for any interval and give an efficient algorithm for finding it (though it generally won't be the lowest possible $$D$$).
## The relationship between an interval's diameter and the denominators it contains
Let $$s = b - a$$ be the diameter of $$[a, b]$$. If $$s \geq 1$$, then we can take $$D = 1$$: $$[a, b]$$ contains all denominators in $$\N^+$$. (For any denominator $$d$$, $$k + 1/d$$ is in $$[a, b]$$ for some integer $$k$$.)
What if $$s < 1$$? We might think that if $$s \geq 1/d$$ then $$[a, b]$$ must contain some rational with denominator $$d$$, but this is not the case. For example, an interval with $$s > 1/6$$ might not contain any sixths:
The largest gap between sixths is $$2/3$$. Let's define $$f(d)$$ to be the largest gap between fractions with denominator $$d$$:
Any interval with $$s \geq f(d)$$ is, by definition, guaranteed to contain some rational with denominator $$d$$. If $$f$$ were monotonically decreasing, then we could use that to prove that $$D$$ exists. We'd simply need to find a $$D$$ such that $$f(D) \leq s$$, and then any $$f(d)$$ for $$d \geq D$$ would also be less than or equal to $$s$$. But $$f$$ does not monotonically decrease.
## The Jacobsthal function and primorials
I couldn't find any reference to $$f(n)$$ in the literature, but fortunately $$g(n) = n f(n)$$ has been studied: it's called the [Jacobsthal function](http://oeis.org/A048669) (not to be confused with the Jacobsthal numbers, which are something unrelated). $$g(n)$$ is the size of the maximal gap in the list of all integers relatively prime to $$n$$.
We can make use of the bound ([^1]) $$g(n) \leq 2^w$$, where $$w$$ is the number of distinct prime factors of $$n$$.
| constraint on $$n$$ | bound on $$w$$ | bound on $$g$$ | bound on $$f$$ |
|-----------------------|----------------|------------------|----------------------|
| $$1 \leq n < 2$$ | $$w \leq 0$$ | $$g(n) \leq 1$$ | $$f(n) \leq 1$$ |
| $$2 \leq n < 6$$ | $$w \leq 1$$ | $$g(n) \leq 2$$ | $$f(n) \leq 1$$ |
| $$6 \leq n < 30$$ | $$w \leq 2$$ | $$g(n) \leq 4$$ | $$f(n) \leq 2/3$$ |
| $$30 \leq n < 210$$ | $$w \leq 3$$ | $$g(n) \leq 8$$ | $$f(n) \leq 4/15$$ |
| $$210 \leq n < 2310$$ | $$w \leq 4$$ | $$g(n) \leq 16$$ | $$f(n) \leq 8/105$$ |
| $$\ldots$$ | $$\ldots$$ | $$\ldots$$ | $$\ldots$$ |
The sequence in the leftmost column, 1, 2, 6, 30, 210, ..., is the sequence of [primorials](https://en.wikipedia.org/wiki/Primorial): they are the products of the first 0, 1, 2, ... primes and therefore the smallest integers with 0, 1, 2, ... distinct prime factors. The $$n$$th primorial is denoted $$p_n\#$$. The sequence of bounds in the rightmost column, 1, 1, 2/3, 4/15, 8/105, ... is $$2^n/p_n\#$$ and is weakly monotonically decreasing. This allows us to construct a weakly monotonically decreasing function $$h$$ that bounds $$f$$ from above:
$$h(n) = 2^k/p_k\# \ \text{where} \ p_k\# \leq n < p_{k+1}\#$$.
Here are $$f$$ and $$h$$ plotted together:
$$h$$ is not a very tight bound. With more careful analysis, we could come up with a better one, perhaps by interpolating between the primorials or by making use of the bound ([^1]) $$g(h) \leq 2k^{2+2e\log k}$$.
We now have an algorithm or determining a threshold $$D$$ for an interval $$[a, b]$$:
1. Find the diameter $$s = b - a$$.
2. Compute the sequence $$2^n/p_n\#$$ until it is less than or equal to $$s$$: the sequence decreases as $$O((2/n)^n)$$, so this step doesn't take long.
3. Let $$n$$ be the value at which $$2^n/p_n\# \leq s$$. Then take $$D$$ to be $$p_n\#$$.
## Results
Let's go back to our example interval, $$[268876667/98914198, 245850922/78256779]$$. Its diameter is about 0.42, so its $$D$$ is 30, meaning that it's guaranteed to contain all denominators greater than or equal to 30. This threshold is low enough that we can just test all the denominators 1 through 29, and after doing this we find that the denominators 1, 4, and all denominators greater than 4 are present.
Malachite generates the rationals contained in the interval in this order:
3, 11/4, 14/5, 20/7, 17/6, 23/8, 25/8, 30/11, 25/9, 29/10, 26/9, 31/11, 28/9, 31/10, 32/11, 41/15, 34/11, 35/12, 37/12, 39/14, ... .
[^1]: Hans-Joachim Kanold, *Über eine zahlentheoretische Funktion von Jacobsthal*, Mathematische Annalen 170.4 (1967): 314-326
================================================
FILE: docs/assets/denominators/gap-and-bound-graph.asy
================================================
import graph;
size(600,400,IgnoreAspect);
int gcd(int a, int b) {
while (b != 0) {
int t = b;
b = a % b;
a = t;
}
return a;
}
int jacobsthal(int n) {
int previous = 0;
int largest_gap = 0;
for (int i = 0; i <= 2 * n; ++i) {
if (gcd(i, n) == 1) {
int gap = i - previous;
if (gap > largest_gap) {
largest_gap = gap;
}
previous = i;
}
}
return largest_gap;
}
scale(Linear,Log);
real[] x={};
real[] y1={};
real[] y2={};
for (int i = 1; i < 500; ++i) {
x.push(i);
y1.push(jacobsthal(i)/i);
if (i < 6) {
y2.push(1);
} else if (i < 30) {
y2.push(2/3);
} else if (i < 210) {
y2.push(4/15);
} else if (i < 2310) {
y2.push(8/105);
}
}
draw(graph(x,y1),black,"$f(n)$");
draw(graph(x,y2),red,"$h(n)$");
xaxis(BottomTop,LeftTicks);
yaxis(LeftRight, RightTicks);
add(legend(),point(NW),(50,-25),UnFill);
================================================
FILE: docs/assets/denominators/gap-graph.asy
================================================
import graph;
size(600,400,IgnoreAspect);
int gcd(int a, int b) {
while (b != 0) {
int t = b;
b = a % b;
a = t;
}
return a;
}
int jacobsthal(int n) {
int previous = 0;
int largest_gap = 0;
for (int i = 0; i <= 2 * n; ++i) {
if (gcd(i, n) == 1) {
int gap = i - previous;
if (gap > largest_gap) {
largest_gap = gap;
}
previous = i;
}
}
return largest_gap;
}
scale(Linear,Log);
real[] x={};
real[] y={};
for (int i = 1; i < 500; ++i) {
x.push(i);
y.push(jacobsthal(i)/i);
}
draw(graph(x,y),black,"$f(n)$");
xaxis(BottomTop,LeftTicks);
yaxis(LeftRight, RightTicks);
add(legend(),point(NW),(25,-25),UnFill);
================================================
FILE: docs/assets/denominators/gaps.asy
================================================
import graph;
size(15cm);
pen small=fontcommand("\scriptsize");
int gcd(int a, int b) {
while (b != 0) {
int t = b;
b = a % b;
a = t;
}
return a;
}
int jacobsthal(int n) {
int previous = 0;
int largest_gap = 0;
for (int i = 0; i <= 2 * n; ++i) {
if (gcd(i, n) == 1) {
int gap = i - previous;
if (gap > largest_gap) {
largest_gap = gap;
}
previous = i;
}
}
return largest_gap;
}
string gap_function(int d) {
int n = jacobsthal(d);
int g = gcd(n, d);
n = n#g;
d = d#g;
if (d == 1) {
return string(n);
} else {
return string(n) + "/" + string(d);
}
}
void draw_rationals(int d, real offset) {
guide gaxis=(0,offset)--(20,offset);
draw(gaxis);
for(int i = 0; i < 3; ++i){
tick(relpoint(gaxis,i/2),-plain.I*reldir(gaxis,i/2),ticksize*2);
}
for(int i = 0; i < 20; ++i){
tick(relpoint(gaxis,i/20),-plain.I*reldir(gaxis,i/20),ticksize);
}
label("$0$",relpoint(gaxis,0),-3*plain.I*reldir(gaxis,0));
label("$1$",relpoint(gaxis,0.5),-3*plain.I*reldir(gaxis,0.5));
label("$2$",relpoint(gaxis,1),-3*plain.I*reldir(gaxis,1));
for (int i= 0; i <= 2 * d; ++i) {
if (gcd(i, d) == 1) {
dot((i*10/d, offset), red);
if (d != 1) {
label("$" + string(i) + "/" + string(d) + "$",relpoint(gaxis,i/(2*d)),-2*plain.I*reldir(gaxis,0.5), red+small);
}
}
}
label("$f(" + string(d) + ") = " + gap_function(d) + "$",(24.5, offset), align=LeftSide);
}
real offset = 0;
for (int d = 1; d <= 10; ++d) {
draw_rationals(d, offset);
offset -= 2;
}
// Force bottom margin to expand
draw(box((-1,1),(-0.5, -20)),white);
================================================
FILE: docs/assets/denominators/j-graph.asy
================================================
import graph;
size(600,400,IgnoreAspect);
int gcd(int a, int b) {
while (b != 0) {
int t = b;
b = a % b;
a = t;
}
return a;
}
int jacobsthal(int n) {
int previous = 0;
int largest_gap = 0;
for (int i = 0; i <= 2 * n; ++i) {
if (gcd(i, n) == 1) {
int gap = i - previous;
if (gap > largest_gap) {
largest_gap = gap;
}
previous = i;
}
}
return largest_gap;
}
//scale(Linear,Log);
real[] x={};
real[] y={};
for (int i = 1; i < 500; ++i) {
x.push(i);
y.push(jacobsthal(i));
}
draw(graph(x,y),black,"$g(n)$");
xaxis(BottomTop,LeftTicks);
yaxis(LeftRight, RightTicks);
add(legend(),point(NW),(25,-25),UnFill);
================================================
FILE: docs/assets/denominators/sixths.asy
================================================
import graph;
size(10cm);
guide gaxis=(0,0)--(20,0);
pen small=fontcommand("\footnotesize");
draw(gaxis);
for(int i = 0; i < 3; ++i){
tick(relpoint(gaxis,i/2),-plain.I*reldir(gaxis,i/2),ticksize*2);
}
for(int i = 0; i < 20; ++i){
tick(relpoint(gaxis,i/20),-plain.I*reldir(gaxis,i/20),ticksize);
}
label("$0$",relpoint(gaxis,0),-3*plain.I*reldir(gaxis,0));
label("$1$",relpoint(gaxis,0.5),-3*plain.I*reldir(gaxis,0.5));
label("$2$",relpoint(gaxis,1),-3*plain.I*reldir(gaxis,1));
int gcd(int a, int b) {
while (b != 0) {
int t = b;
b = a % b;
a = t;
}
return a;
}
for (int i= 0; i <= 12; ++i) {
if (gcd(i, 6) == 1) {
dot((i*10/6, 0), red);
label("$" + string(i) + "/6$",relpoint(gaxis,i/(2*6)),-2*plain.I*reldir(gaxis,0.5), red+small);
}
}
draw((1.8, 0.2)--(1.8, -0.2),blue+linewidth(0.5mm));
draw((1.8, 0)--(8.2, 0),blue+linewidth(0.5mm));
draw((8.2, 0.2)--(8.2, -0.2),blue+linewidth(0.5mm));
================================================
FILE: docs/assets/exhaustive-part-2/cantor-graph.asy
================================================
import graph;
size(600,400,IgnoreAspect);
pair unpair(int i) {
int j = 0;
int r = i;
while (r >= j) {
r -= j;
j += 1;
}
j -= 1;
return (j - r, r);
}
real[] x={};
real[] y1={};
real[] y2={};
for (int i = 0; i < 500; ++i) {
x.push(i);
y1.push(unpair(i).x);
y2.push(unpair(i).y);
}
real[] z=sqrt(2x);
draw(graph(x,y1),red,"first element");
draw(graph(x,y2),blue,"second element");
draw(graph(x,z),black,"$\sqrt{2x}$");
xaxis(BottomTop,LeftTicks);
yaxis(LeftRight, RightTicks);
add(legend(),point(NW),(25,-25),UnFill);
================================================
FILE: docs/assets/exhaustive-part-2/cantor-grid.asy
================================================
unitsize(1cm);
int size = 5;
for (int x = 0; x < size; ++x) {
for (int y = 0; y < size; ++y) {
dot((x, y));
}
}
pair unpair(int i) {
int j = 0;
int r = i;
while (r >= j) {
r -= j;
j += 1;
}
j -= 1;
return (j - r, r);
}
path boundary = box((-0.5, -0.5), (size + 0.5, size + 0.5));
pair previous = (0, 0);
for (int i = 1; i < 15; ++i) {
pair next = unpair(i);
bool previous_in_range = previous.x < size && previous.y < size;
bool next_in_range = next.x < size && next.y < size;
if (previous_in_range && next_in_range) {
draw(previous -- next, arrow=Arrow, gray);
} else {
draw(previous -- next, gray+Dotted());
}
previous = next;
}
clip(boundary);
================================================
FILE: docs/assets/exhaustive-part-2/cantor-large.tex
================================================
\documentclass[11pt]{article}
\usepackage{amsmath}
\begin{document}
\begin{equation*}
\begin{split}
3^{20} &\rightarrow (33123, 50384) \\
3^{40} &\rightarrow (2293673435, 2637384353) \\
3^{60} &\rightarrow (158808187801698, 132365843578904) \\
3^{80} &\rightarrow (12105097562203174223, 5088437816790055004) \\
3^{100} &\rightarrow (416864661676079910029691, 598396408918091282666529) \\
\end{split}
\end{equation*}
\end{document}
================================================
FILE: docs/assets/exhaustive-part-2/cantor-triples-large.tex
================================================
\documentclass[11pt]{article}
\usepackage{amsmath}
\begin{document}
\begin{equation*}
\begin{split}
3^{20} &\rightarrow (33123, 298, 18) \\
3^{40} &\rightarrow (2293673435, 7475, 65152) \\
3^{60} &\rightarrow (158808187801698, 13757728, 2512848) \\
3^{80} &\rightarrow (12105097562203174223, 2695483339, 494638230) \\
3^{100} &\rightarrow (416864661676079910029691, 871747234874, 222233029040) \\
\end{split}
\end{equation*}
\end{document}
================================================
FILE: docs/assets/exhaustive-part-2/interleave-bits-1.tex
================================================
\documentclass[11pt]{article}
\usepackage{amsmath}
\begin{document}
\begin{tabular}{rcr}
0 & $\rightarrow$ & \ldots 000000 \\
1 & $\rightarrow$ & \ldots 000001 \\
2 & $\rightarrow$ & \ldots 000010 \\
3 & $\rightarrow$ & \ldots 000011 \\
4 & $\rightarrow$ & \ldots 000100 \\
5 & $\rightarrow$ & \ldots 000101 \\
6 & $\rightarrow$ & \ldots 000110 \\
7 & $\rightarrow$ & \ldots 000111 \\
\end{tabular}
\end{document}
================================================
FILE: docs/assets/exhaustive-part-2/interleave-bits-2.tex
================================================
\documentclass[11pt]{article}
\usepackage{amsmath}
\usepackage{xcolor}
\begin{document}
\begin{tabular}{rcrcrcr}
0 & $\rightarrow$ & \ldots \color{red}0\color{blue}0\color{red}0\color{blue}0\color{red}0\color{blue}0 & $\rightarrow$ & $(\color{red} \ldots 00000, \ \color{blue} \ldots 00000 \color{black})$ & $\rightarrow$ & $(0, 0)$ \\
1 & $\rightarrow$ & \ldots \color{red}0\color{blue}0\color{red}0\color{blue}0\color{red}0\color{blue}1 & $\rightarrow$ & $(\color{red} \ldots 00000, \ \color{blue} \ldots 00001 \color{black})$ & $\rightarrow$ & $(0, 1)$ \\
2 & $\rightarrow$ & \ldots \color{red}0\color{blue}0\color{red}0\color{blue}0\color{red}1\color{blue}0 & $\rightarrow$ & $(\color{red} \ldots 00001, \ \color{blue} \ldots 00000 \color{black})$ & $\rightarrow$ & $(1, 0)$ \\
3 & $\rightarrow$ & \ldots \color{red}0\color{blue}0\color{red}0\color{blue}0\color{red}1\color{blue}1 & $\rightarrow$ & $(\color{red} \ldots 00001, \ \color{blue} \ldots 00001 \color{black})$ & $\rightarrow$ & $(1, 1)$ \\
4 & $\rightarrow$ & \ldots \color{red}0\color{blue}0\color{red}0\color{blue}1\color{red}0\color{blue}0 & $\rightarrow$ & $(\color{red} \ldots 00000, \ \color{blue} \ldots 00010 \color{black})$ & $\rightarrow$ & $(0, 2)$ \\
5 & $\rightarrow$ & \ldots \color{red}0\color{blue}0\color{red}0\color{blue}1\color{red}0\color{blue}1 & $\rightarrow$ & $(\color{red} \ldots 00000, \ \color{blue} \ldots 00011 \color{black})$ & $\rightarrow$ & $(0, 3)$ \\
6 & $\rightarrow$ & \ldots \color{red}0\color{blue}0\color{red}0\color{blue}1\color{red}1\color{blue}0 & $\rightarrow$ & $(\color{red} \ldots 00001, \ \color{blue} \ldots 00010 \color{black})$ & $\rightarrow$ & $(1, 2)$ \\
7 & $\rightarrow$ & \ldots \color{red}0\color{blue}0\color{red}0\color{blue}1\color{red}1\color{blue}1 & $\rightarrow$ & $(\color{red} \ldots 00001, \ \color{blue} \ldots 00011 \color{black})$ & $\rightarrow$ & $(1, 3)$ \\
\end{tabular}
\end{document}
================================================
FILE: docs/assets/exhaustive-part-2/interleave-grid-filtered.asy
================================================
unitsize(1cm);
int size = 8;
for (int x = 0; x < size; ++x) {
for (int y = 0; y < size; ++y) {
if (y < 2) {
dot((x, y), green);
} else {
dot((x, y), red);
}
}
}
pair unpair(int i) {
int x = 0;
int y = 0;
bool on_x = false;
int out_mask = 1;
while (i != 0) {
if (i % 2 != 0) {
if (on_x) {
x += out_mask;
} else {
y += out_mask;
}
}
if (on_x) {
on_x = false;
out_mask *= 2;
} else {
on_x = true;
}
i #= 2;
}
return (x, y);
}
path boundary = box((-0.5, -0.5), (size + 0.5, size + 0.5));
pair previous = (0, 0);
for (int i = 1; i < size * size; ++i) {
pair next = unpair(i);
bool previous_in_range = previous.x <= size && previous.y <= size;
bool next_in_range = next.x <= size && next.y <= size;
if (previous_in_range && next_in_range) {
draw(previous -- next, arrow=Arrow, gray);
} else {
draw(previous -- next, gray+Dotted());
}
previous = next;
}
clip(boundary);
================================================
FILE: docs/assets/exhaustive-part-2/interleave-grid.asy
================================================
unitsize(1cm);
int size = 8;
for (int x = 0; x < size; ++x) {
for (int y = 0; y < size; ++y) {
dot((x, y));
}
}
pair unpair(int i) {
int x = 0;
int y = 0;
bool on_x = false;
int out_mask = 1;
while (i != 0) {
if (i % 2 != 0) {
if (on_x) {
x += out_mask;
} else {
y += out_mask;
}
}
if (on_x) {
on_x = false;
out_mask *= 2;
} else {
on_x = true;
}
i #= 2;
}
return (x, y);
}
path boundary = box((-0.5, -0.5), (size + 0.5, size + 0.5));
pair previous = (0, 0);
for (int i = 1; i < size * size; ++i) {
pair next = unpair(i);
bool previous_in_range = previous.x <= size && previous.y <= size;
bool next_in_range = next.x <= size && next.y <= size;
if (previous_in_range && next_in_range) {
draw(previous -- next, arrow=Arrow, gray);
} else {
draw(previous -- next, gray+Dotted());
}
previous = next;
}
clip(boundary);
================================================
FILE: docs/assets/exhaustive-part-2/interleave-large.tex
================================================
\documentclass[11pt]{article}
\usepackage{amsmath}
\begin{document}
\begin{equation*}
\begin{split}
3^{20} &\rightarrow (47160, 48725) \\
3^{40} &\rightarrow (4005651428, 74192769) \\
3^{60} &\rightarrow (191657527975116, 14476912773621) \\
3^{80} &\rightarrow (8489200491033962112, 13032031964488297961) \\
3^{100} &\rightarrow (231900172002858385847832, 957915753008438345446493) \\
\end{split}
\end{equation*}
\end{document}
================================================
FILE: docs/assets/exhaustive-part-2/interleave-pairs-graph.asy
================================================
import graph;
size(600,400,IgnoreAspect);
pair unpair(int i) {
int x = 0;
int y = 0;
bool on_x = false;
int out_mask = 1;
while (i != 0) {
if (i % 2 != 0) {
if (on_x) {
x += out_mask;
} else {
y += out_mask;
}
}
if (on_x) {
on_x = false;
out_mask *= 2;
} else {
on_x = true;
}
i #= 2;
}
return (x, y);
}
real[] x={};
real[] y1={};
real[] y2={};
for (int i = 0; i < 10000; ++i) {
x.push(i);
y1.push(unpair(i).x);
y2.push(unpair(i).y);
}
real[] z=sqrt(3*x);
draw(graph(x,y1),red,"first element");
draw(graph(x,y2),blue,"second element");
draw(graph(x,z),black,"$\sqrt{3x}$");
xaxis(BottomTop,LeftTicks);
yaxis(LeftRight, RightTicks);
add(legend(),point(NW),(25,-25),UnFill);
================================================
FILE: docs/assets/exhaustive-part-2/interleave-triples-bits.tex
================================================
\documentclass[11pt]{article}
\usepackage{amsmath}
\usepackage{xcolor}
\begin{document}
\begin{tabular}{rcrcrcr}
0 & $\rightarrow$ & \ldots \color{green}0\color{red}0\color{blue}0\color{green}0\color{red}0\color{blue}0\color{green}0 & $\rightarrow$ & $(\color{red} \ldots 00000, \ \color{blue} \ldots 00000, \ \color{green} \ldots 00000 \color{black})$ & $\rightarrow$ & $(0, 0, 0)$ \\
1 & $\rightarrow$ & \ldots \color{green}0\color{red}0\color{blue}0\color{green}0\color{red}0\color{blue}0\color{green}1 & $\rightarrow$ & $(\color{red} \ldots 00000, \ \color{blue} \ldots 00000, \ \color{green} \ldots 00001 \color{black})$ & $\rightarrow$ & $(0, 0, 1)$ \\
2 & $\rightarrow$ & \ldots \color{green}0\color{red}0\color{blue}0\color{green}0\color{red}0\color{blue}1\color{green}0 & $\rightarrow$ & $(\color{red} \ldots 00000, \ \color{blue} \ldots 00001, \ \color{green} \ldots 00000 \color{black})$ & $\rightarrow$ & $(0, 1, 0)$ \\
3 & $\rightarrow$ & \ldots \color{green}0\color{red}0\color{blue}0\color{green}0\color{red}0\color{blue}1\color{green}1 & $\rightarrow$ & $(\color{red} \ldots 00000, \ \color{blue} \ldots 00001, \ \color{green} \ldots 00001 \color{black})$ & $\rightarrow$ & $(0, 1, 1)$ \\
4 & $\rightarrow$ & \ldots \color{green}0\color{red}0\color{blue}0\color{green}0\color{red}1\color{blue}0\color{green}0 & $\rightarrow$ & $(\color{red} \ldots 00001, \ \color{blue} \ldots 00000, \ \color{green} \ldots 00000 \color{black})$ & $\rightarrow$ & $(1, 0, 0)$ \\
5 & $\rightarrow$ & \ldots \color{green}0\color{red}0\color{blue}0\color{green}0\color{red}1\color{blue}0\color{green}1 & $\rightarrow$ & $(\color{red} \ldots 00001, \ \color{blue} \ldots 00000, \ \color{green} \ldots 00001 \color{black})$ & $\rightarrow$ & $(1, 0, 1)$ \\
6 & $\rightarrow$ & \ldots \color{green}0\color{red}0\color{blue}0\color{green}0\color{red}1\color{blue}1\color{green}0 & $\rightarrow$ & $(\color{red} \ldots 00001, \ \color{blue} \ldots 00001, \ \color{green} \ldots 00000 \color{black})$ & $\rightarrow$ & $(1, 1, 0)$ \\
7 & $\rightarrow$ & \ldots \color{green}0\color{red}0\color{blue}0\color{green}0\color{red}1\color{blue}1\color{green}1 & $\rightarrow$ & $(\color{red} \ldots 00001, \ \color{blue} \ldots 00001, \ \color{green} \ldots 00001 \color{black})$ & $\rightarrow$ & $(1, 1, 1)$ \\
8 & $\rightarrow$ & \ldots \color{green}0\color{red}0\color{blue}0\color{green}1\color{red}0\color{blue}0\color{green}0 & $\rightarrow$ & $(\color{red} \ldots 00000, \ \color{blue} \ldots 00000, \ \color{green} \ldots 00010 \color{black})$ & $\rightarrow$ & $(0, 0, 2)$ \\
9 & $\rightarrow$ & \ldots \color{green}0\color{red}0\color{blue}0\color{green}1\color{red}0\color{blue}0\color{green}1 & $\rightarrow$ & $(\color{red} \ldots 00000, \ \color{blue} \ldots 00000, \ \color{green} \ldots 00011 \color{black})$ & $\rightarrow$ & $(0, 0, 3)$ \\
10 & $\rightarrow$ & \ldots \color{green}0\color{red}0\color{blue}0\color{green}1\color{red}0\color{blue}1\color{green}0 & $\rightarrow$ & $(\color{red} \ldots 00000, \ \color{blue} \ldots 00001, \ \color{green} \ldots 00010 \color{black})$ & $\rightarrow$ & $(0, 1, 2)$ \\
11 & $\rightarrow$ & \ldots \color{green}0\color{red}0\color{blue}0\color{green}1\color{red}0\color{blue}1\color{green}1 & $\rightarrow$ & $(\color{red} \ldots 00000, \ \color{blue} \ldots 00001, \ \color{green} \ldots 00011 \color{black})$ & $\rightarrow$ & $(0, 1, 3)$ \\
12 & $\rightarrow$ & \ldots \color{green}0\color{red}0\color{blue}0\color{green}1\color{red}1\color{blue}0\color{green}0 & $\rightarrow$ & $(\color{red} \ldots 00001, \ \color{blue} \ldots 00000, \ \color{green} \ldots 00010 \color{black})$ & $\rightarrow$ & $(1, 0, 2)$ \\
13 & $\rightarrow$ & \ldots \color{green}0\color{red}0\color{blue}0\color{green}1\color{red}1\color{blue}0\color{green}1 & $\rightarrow$ & $(\color{red} \ldots 00001, \ \color{blue} \ldots 00000, \ \color{green} \ldots 00011 \color{black})$ & $\rightarrow$ & $(1, 0, 3)$ \\
14 & $\rightarrow$ & \ldots \color{green}0\color{red}0\color{blue}0\color{green}1\color{red}1\color{blue}1\color{green}0 & $\rightarrow$ & $(\color{red} \ldots 00001, \ \color{blue} \ldots 00001, \ \color{green} \ldots 00010 \color{black})$ & $\rightarrow$ & $(1, 1, 2)$ \\
15 & $\rightarrow$ & \ldots \color{green}0\color{red}0\color{blue}0\color{green}1\color{red}1\color{blue}1\color{green}1 & $\rightarrow$ & $(\color{red} \ldots 00001, \ \color{blue} \ldots 00001, \ \color{green} \ldots 00011 \color{black})$ & $\rightarrow$ & $(1, 1, 3)$ \\
\end{tabular}
\end{document}
================================================
FILE: docs/assets/exhaustive-part-2/interleave-triples-graph.asy
================================================
import graph;
size(600,400,IgnoreAspect);
triple untriple(int i) {
int x = 0;
int y = 0;
int z = 0;
int j = 2;
int out_mask = 1;
while (i != 0) {
if (i % 2 != 0) {
if (j == 0) {
x += out_mask;
} else if (j == 1) {
y += out_mask;
} else {
z += out_mask;
}
}
if (j == 0) {
j = 2;
out_mask *= 2;
} else if (j == 1) {
j = 0;
} else {
j = 1;
}
i #= 2;
}
return (x, y, z);
}
real[] x={};
real[] y1={};
real[] y2={};
real[] y3={};
for (int i = 0; i < 10000; ++i) {
x.push(i);
y1.push(untriple(i).x);
y2.push(untriple(i).y);
y3.push(untriple(i).z);
}
real[] z=(7*x)^(1/3);
draw(graph(x,y1),red,"first element");
draw(graph(x,y2),blue,"second element");
draw(graph(x,y3),green,"third element");
draw(graph(x,z),black,"$\sqrt[3]{7x}$");
xaxis(BottomTop,LeftTicks);
yaxis(LeftRight, RightTicks);
add(legend(),point(NW),(25,-25),UnFill);
================================================
FILE: docs/assets/exhaustive-part-2/interleave-triples-large.tex
================================================
\documentclass[11pt]{article}
\usepackage{amsmath}
\begin{document}
\begin{equation*}
\begin{split}
3^{20} &\rightarrow (460, 1414, 1881) \\
3^{40} &\rightarrow (709242, 1441904, 2284385) \\
3^{60} &\rightarrow (2679879830, 1355562942, 821033137) \\
3^{80} &\rightarrow (3812501379408, 1191406597864, 8482842874549) \\
3^{100} &\rightarrow (7172636040844612, 458719279115590, 7931619284932509) \\
\end{split}
\end{equation*}
\end{document}
================================================
FILE: docs/assets/logo.asy
================================================
unitsize(1mm);
pair p1 = (25.0, -279.5970461708813);
pair p2 = (73.21397343575165, -453.91200545461675);
pair p3 = (87.46591514137958, -478.59709259527415);
pair p4 = (135.6798885771313, -87.89385577922775);
pair p5 = (139.89273037187124, -171.40290740472582);
pair p6 = (202.35864551325085, -370.4029538291187);
pair p7 = (214.32011142286873, -607.5090980498909);
pair p8 = (284.53465067912623, -562.1061442207722);
pair p9 = (310.7480582943721, -42.490901950109105);
pair p10 = (339.2519417056279, -42.490901950109105);
pair p11 = (347.00056582050587, -196.08799454538328);
pair p12 = (425.6407886662433, -408.50905162549805);
pair p13 = (435.67988857713124, -607.5090980498909);
pair p14 = (514.3201114228686, -87.89385577922775);
pair p15 = (550.5726189490025, -241.49094837450195);
pair p16 = (562.5340848586204, -478.59709259527415);
pair p17 = (576.7860265642483, -453.91200545461675);
pair p18 = (625.0, -279.5970461708813);
pair a = (0.5, sqrt(3)/2);
pair b = (0, 0);
pair c = (1, 0);
pair center = (0.5, sqrt(3)/6);
pen[] colors = new pen [] {
RGB(115, 209, 160),
RGB(86,158,118),
RGB(56,106,76),
RGB(27, 44, 34)
};
fill(p1 -- p3 -- p6 -- p5 -- cycle, colors[2]);
fill(p12 -- p17 -- p13 -- p8 -- cycle, colors[2]);
fill(p9 -- p14 -- p15 -- p11 -- cycle, colors[2]);
fill(p6 -- p12 -- p11 -- cycle, colors[2]);
fill(p3 -- p8 -- p7 -- cycle, colors[2]);
fill(p9 -- p5 -- p4 -- cycle, colors[2]);
fill(p17 -- p15 -- p18 -- cycle, colors[2]);
fill(p1 -- p2 -- p3 -- cycle, colors[1]);
fill(p3 -- p6 -- p8 -- cycle, colors[1]);
fill(p6 -- p8 -- p12 -- cycle, colors[0]);
fill(p6 -- p5 -- p11 -- cycle, colors[0]);
fill(p13 -- p8 -- p7 -- cycle, colors[1]);
fill(p13 -- p16 -- p17 -- cycle, colors[1]);
fill(p12 -- p17 -- p15 -- cycle, colors[1]);
fill(p12 -- p11 -- p15 -- cycle, colors[0]);
fill(p1 -- p5 -- p4 -- cycle, colors[1]);
fill(p9 -- p5 -- p11 -- cycle, colors[1]);
fill(p9 -- p10 -- p14 -- cycle, colors[1]);
fill(p14 -- p15 -- p18 -- cycle, colors[1]);
================================================
FILE: docs/index.md
================================================
Malachite is an arbitrary-precision arithmetic library for [Rust](https://www.rust-lang.org/). It
achieves high performance in part by using algorithms derived from [GMP](https://gmplib.org/),
[FLINT](https://www.flintlib.org/), and [MPFR](https://www.mpfr.org/).
The documentation for Malachite is [here](https://docs.rs/malachite/latest/malachite/), and its crate is [here](https://crates.io/crates/malachite).
```rust
use malachite::num::arithmetic::traits::Factorial;
use malachite::Natural;
fn main() {
println!("{}", Natural::factorial(100));
}
```
The code above outputs the following:
```
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
```
You have to scroll to see the entire output.
Here's a more complex example, calculating the negative-one-millionth power of 3 and displaying the
result with 30 digits of precision.
```rust
use malachite::num::arithmetic::traits::Pow;
use malachite::num::conversion::string::options::ToSciOptions;
use malachite::num::conversion::traits::ToSci;
use malachite::Rational;
fn main() {
let mut options = ToSciOptions::default();
options.set_precision(30);
println!("{}", Rational::from(3).pow(-1_000_000i64).to_sci_with_options(options));
}
```
The output is this:
```
5.56263209915712886588211486263e-477122
```
Every digit is correct, except that the least-significant digit was rounded up from 2. The default
rounding mode,
[`Nearest`](https://docs.rs/malachite-base/latest/malachite_base/rounding_modes/enum.RoundingMode.html#variant.Nearest),
uses [bankers' rounding](https://en.wikipedia.org/wiki/Rounding#Rounding_half_to_even), but you may
specify different rounding behavior via the options parameter.
Malachite is designed to work with very large numbers efficiently. See [here](/performance) for a
performance comparison against other libraries.
Malachite uses `no_std`, unless the `random`, `test_build`, or `bin_build` features are enabled.
To use Malachite, add the following to your project's `Cargo.toml` file:
```yaml
[dependencies.malachite]
version = "0.9.1"
```
By default, all of Malachite's features are included, but you can opt out of some of them. For
example, if you want to use `Natural` and `Integer` but not `Rational`, you can instead use
```yaml
[dependencies.malachite]
version = "0.9.1"
default-features = false
features = [ "naturals_and_integers" ]
```
The `malachite` crate re-exports three sub-crates.
- **malachite-base** ([crates.io](https://crates.io/crates/malachite-base)) is a collection of utilities
supporting the other crates. It includes
- Traits that wrap functions from the standard library, like
[`CheckedAdd`](https://docs.rs/malachite-base/latest/malachite_base/num/arithmetic/traits/trait.CheckedAdd.html);
- Traits that give extra functionality to primitive types, like
[`Gcd`](https://docs.rs/malachite-base/latest/malachite_base/num/arithmetic/traits/trait.Gcd.html),
[`FloorSqrt`](https://docs.rs/malachite-base/latest/malachite_base/num/arithmetic/traits/trait.FloorSqrt.html),
and
[`BitAccess`](https://docs.rs/malachite-base/latest/malachite_base/num/logic/traits/trait.BitAccess.html);
- Iterator-producing functions that let you generate values for testing.
- **malachite-nz** ([crates.io](https://crates.io/crates/malachite-nz)) defines two bignum types,
[`Natural`](https://docs.rs/malachite-nz/latest/malachite_nz/natural/struct.Natural.html)s and
[`Integer`](https://docs.rs/malachite-nz/latest/malachite_nz/integer/struct.Integer.html)s. The
functions defined on these types include
- All the ones you'd expect, like addition, subtraction, multiplication, and integer division;
- Implementations of
[`DivRound`](https://docs.rs/malachite-base/latest/malachite_base/num/arithmetic/traits/trait.DivRound.html),
which provides division that rounds according to a specified
[`RoundingMode`](https://docs.rs/malachite-base/latest/malachite_base/rounding_modes/enum.RoundingMode.html);
- Various mathematical functions, like implementations of
[`FloorSqrt`](https://docs.rs/malachite-base/latest/malachite_base/num/arithmetic/traits/trait.FloorSqrt.html)
and
[`Gcd`](https://docs.rs/malachite-base/latest/malachite_base/num/arithmetic/traits/trait.Gcd.html);
- Modular arithmetic functions, like implementations of
[`ModAdd`](https://docs.rs/malachite-base/latest/malachite_base/num/arithmetic/traits/trait.ModAdd.html)
and
[`ModPow`](https://docs.rs/malachite-base/latest/malachite_base/num/arithmetic/traits/trait.ModPow.html),
and of traits for arithmetic modulo a power of 2, like
[`ModPowerOf2Add`](https://docs.rs/malachite-base/latest/malachite_base/num/arithmetic/traits/trait.ModPowerOf2Add.html)
and
[`ModPowerOf2Pow`](https://docs.rs/malachite-base/latest/malachite_base/num/arithmetic/traits/trait.ModPowerOf2Pow.html);
- Various functions for logic and bit manipulation, like
[`BitAnd`](https://doc.rust-lang.org/nightly/core/ops/trait.BitAnd.html) and
[`BitAccess`](https://docs.rs/malachite-base/latest/malachite_base/num/logic/traits/trait.BitAccess.html).
If you need to explicitly include this crate as a dependency of the `malachite` crate, use the
`naturals_and_integers` or `malachite-nz` feature.
- **malachite-q** ([crates.io](https://crates.io/crates/malachite-q)) defines
[`Rational`](https://docs.rs/malachite-q/latest/malachite_q/struct.Rational.html)s. The
functions defined on this type include
- All the ones you'd expect, like addition, subtraction, multiplication, and division;
- Functions related to conversion between
[`Rational`](https://docs.rs/malachite-q/latest/malachite_q/struct.Rational.html)s and other
kinds of numbers, including primitive floats;
- Functions for Diophantine approximation;
- Functions for expressing
[`Rational`](https://docs.rs/malachite-q/latest/malachite_q/struct.Rational.html)s in
scientific notation.
If you need to explicitly include this crate as a dependency of the `malachite` crate, use the
`rationals` or `malachite-q` feature.
- **malachite-float** Arbitrary-precision floating-point numbers. These are in development, and
most features are missing.
Malachite is under active development, with many more types and features planned for the future.
Nonetheless, it is extensively tested and documented, and ready for use today. Just be aware that
its API is not stable yet, and that Malachite is licensed under LGPL 3.0.
Malachite is developed by Mikhail Hogrefe. `malachite-bigint`, a drop-in num-bigint replacement based on Malachite, was created by Steve Shi and is now maintained by Mikhail Hogrefe. Thanks to b4D8, florian1345, konstin, Rowan Hart, YunWon Jeong, Park Joon-Kyu, Antonio Mamić, OliverNChalk, shekohex, and skycloudd for additional contributions.
# FAQ
**How is "Malachite" pronounced, and what does it mean?**
"Malachite" is pronounced MA-luh-kite, or /ˈmæl.əˌkaɪt/. It is the name of
[a green gemstone](https://en.wikipedia.org/wiki/Malachite). Unfortunately, malachite does not
contain iron, which would have made it a particularly good namesake for a Rust library.
Malachite's logo is an image of a [snub cube](https://en.wikipedia.org/wiki/Snub_cube).
**When does Malachite allocate memory?**
Any `Natural` less than $$2^{64}$$ is represented inline, without allocating memory. Any `Integer`
whose absolute value is less than $$2^{64}$$ doesn't allocate either, and neither does any
`Rational` whose absolute numerator and denominator are both less than $$2^{64}$$. If you're using
a build with `--features 32_bit_limbs`, then the threshold is $$2^{32}$$ instead.
**Can I build Malachite for WebAssembly?**
Yes. If, in the future, Malachite includes code incompatible with Wasm (for example, code that uses
[rayon](https://docs.rs/rayon/latest/rayon/)), it will be possible to disable that code with cargo
flags.
# Blog Posts
The most significant operations involved in adding two rational numbers (fractions) are GCD
computation and division.
For GCD computation, `num` uses the
[binary GCD algorithm](https://en.wikipedia.org/wiki/Binary_GCD_algorithm), a quadratic algorithm.
Malachite follows GMP in using
[Lehmer's GCD algorithm](https://en.wikipedia.org/wiki/Lehmer%27s_GCD_algorithm), which takes
advantage of fast multiplication algorithms to achieve $$O(n (\log n)^2 \log \log n)$$ time.
For division, `num` uses Knuth's
[Algorithm D](https://ridiculousfish.com/blog/posts/labor-of-division-episode-iv.html), which is
also quadratic. Malachite, again following GMP, uses several division algorithms depending on the
input size. For the largest inputs, it uses a kind of
[Barrett reduction](https://en.wikipedia.org/wiki/Barrett_reduction), which takes
$$O(n \log n \log \log n)$$ time.
## Converting a Natural to a string
`cargo run --features bin_build --release -- -l 100000 -m random -b benchmark_natural_to_string_library_comparison -c "mean_bits_n 1024"`
When converting a natural number to a string, `num` seems to use an $$O(n^{3/2})$$ algorithm.
Malachite uses a divide-and-conquer algorithm that takes $$O(n (\log n)^2 \log \log n)$$ time.
## Natural multiplication
`cargo run --features bin_build --release -- -l 20000 -m random -b benchmark_natural_mul_library_comparison -c "mean_bits_n 16384"`
For multiplying two natural numbers, `num` uses a basecase quadratic algorithm for small inputs,
then [Toom-22](https://en.wikipedia.org/wiki/Toom%E2%80%93Cook_multiplication) (Karatsuba)
multiplication for larger inputs, and finally Toom-33 for the largest ones. This means that
multiplication takes $$O(n^{\log_3 5}) \approx O(n^{1.465})$$ time.
Malachite also uses a basecase quadratic algorithm, then 13 variants of Toom-Cook multiplication,
and finally [Schönhage-Strassen (FFT) multiplication](https://en.wikipedia.org/wiki/Schonhage-Strassen_algorithm) for the largest inputs, achieving $$O(n \log n \log \log n)$$
time.
Given all of this machinery, it's a little disappointing that Malachite isn't much faster at
multiplying than `num` is, in practice. I have a few improvements in mind that should boost
Malachite's multiplication performance further.
For numbers of up to 1000 bits, all three libraries are about equally fast:
`cargo run --features bin_build --release -- -l 100000 -m random -b benchmark_natural_mul_library_comparison -c "mean_bits_n 64"`
## Natural addition
`cargo run --features bin_build --release -- -l 100000 -m random -b benchmark_natural_add_library_comparison -c "mean_bits_n 1024"`