- Now uses Toom-3 multiplication for large inputs.
- `BigInt`/`BigUint` parsing now accepts `_` separating digits.
- `BigInt`/`BigUint::assign_from_slice` reinitializes the value, keeping
the same internal buffer.
- `BigUint` now implements many `*Assign` ops.
- `BigUint::modpow(exp, mod)` performs efficient modular exponentiation.
`Complex` now implements `Num`, `Rem`, and `RemAssign`.
(Complex remainders don't have a clear mathematical basis, but we choose
to round toward zero to a gaussian integer.)
342: rational: check for NaN when approximating floats r=cuviper a=cuviper
We had a test for NaN already, but thanks to undefined casts (#119) it
was only passing by luck -- on armv7hl it failed:
https://bugzilla.redhat.com/show_bug.cgi?id=1511187
Now we check for NaN explicitly.
339: Implement modpow() for BigUint backed by Montgomery Multiplication r=cuviper a=str4d
Based on this Gist: https://gist.github.com/yshui/027eecdf95248ea69606
Also adds support to `BigUint.from_str_radix()` for using `_` as a visual separator.
Closes#136
340: Fix documentation formatting with commonmark enabled r=cuviper a=mbrubeck
This makes formatting correct with the new pulldown-cmark Markdown parser (rust-lang/rust#44229).
328: Optimizing BigUint and Bigint multiplication with the Toom-3 algorithm r=cuviper a=kompass
Hi !
I finally implemented the Toom-3 algorithm ! I first tried to minimize the memory allocations by allocating the `Vec<BigDigit>` myself, as was done for Toom-2, but Toom-3 needs more complex calculations, with negative numbers. So I gave up this method, to use `BigInt` directly, and it's already faster ! I also chose a better threshold for the Toom-2 algorithm.
Before any modification :
```
running 4 tests
test multiply_0 ... bench: 257 ns/iter (+/- 25)
test multiply_1 ... bench: 30,240 ns/iter (+/- 1,651)
test multiply_2 ... bench: 2,752,360 ns/iter (+/- 52,102)
test multiply_3 ... bench: 11,618,575 ns/iter (+/- 266,286)
```
With a better Toom-2 threshold (16 instead of 4) :
```
running 4 tests
test multiply_0 ... bench: 130 ns/iter (+/- 8)
test multiply_1 ... bench: 19,772 ns/iter (+/- 1,083)
test multiply_2 ... bench: 1,340,644 ns/iter (+/- 17,987)
test multiply_3 ... bench: 7,302,854 ns/iter (+/- 82,060)
```
With the Toom-3 algorithm (with a threshold of 300):
```
running 4 tests
test multiply_0 ... bench: 123 ns/iter (+/- 3)
test multiply_1 ... bench: 19,689 ns/iter (+/- 837)
test multiply_2 ... bench: 1,189,589 ns/iter (+/- 29,101)
test multiply_3 ... bench: 3,014,225 ns/iter (+/- 61,222)
```
I think this could be optimized, but it's a first step !
By starting with `split_at_mut`, the hot multiplication loop runs with
no bounds checking at all! The remaining carry loop has a slightly
simpler check for when the remaining iterator runs dry.
330: Implement *Assign for BigUint r=cuviper a=Darksonn
Not only does this change increase convenience of use, it also allows adding a `&BigUint` to a `&mut BigUint` without allocating (if not necessary) or tricks such as:
fn add(a: &mut BigUint, b: &BigUint) {
let aa = mem::replace(a, BigUint::from_slice(&[])); // BigUint::from_slice(&[]) does not allocate
*a = aa + b;
}
With this change:
fn add(a: &mut BigUint, b: &BigUint) {
*a += b;
}
It would make sense to add the same functionality to `BigInt`, but it uses some macros to handle the signs, and I'm not sure how to change the macros in order to perform this change.
327: Add general Rem and Num implementations for Complex<T> r=cuviper a=carrutstick
This should address #209 with eyes towards addressing #321.
It was a little tricky to get `Rem` working for a general `Num`, and I had to add a `PartialOrd` constraint to get it working, but I think it should be fairly robust.
I could probably use extra eyes on the `from_str_radix` function, as I mostly lifted the code from the `from_str` function and I may be missing some subtleties in how that works.