18: Add BigInt::modpow r=cuviper a=cuviper
This performs modular exponentiation on signed `BigInt`. The exponent
must be positive, and the modulus must be non-zero. The implementation
leverages `BigUint::modpow`, fixing the signs as needed afterward.
Closes#17.
This performs modular exponentiation on signed `BigInt`. The exponent
must be positive, and the modulus must be non-zero. The implementation
leverages `BigUint::modpow`, fixing the signs as needed afterward.
15: Implement Stein's algorithm for gcd r=cuviper a=Emerentius
This implements Stein's algorithm for bigints.
Asymptotically this has the same runtime complexity as the euclidean algorithm but it's faster because it avoids division in favor of bitshifts and subtractions.
There are faster algorithms for large bigints. For small ones, [gmp uses the binary gcd too](https://gmplib.org/manual/Binary-GCD.html).
I've run some benchmarks with the code in [this repo](https://github.com/Emerentius/bigint_gcd_bench)
This iterates through the sizes of 1-10 `BigDigit`s and generates 300 uniformly distributed random bigints at each size and computes the gcd for each combination with both Euclid's and Stein's algorithm. I'm only looking at combinations of numbers with the same number of `BigDigit`s
The speed gains are sizeable. See the benchmark results below. I'm running this on an ultrabook with a 15W CPU (i5 4210u). Performance may differ on different architectures, in particular if there is no intrinsic for counting trailing zeroes.
Please run the benchmark on your machine. It's just a simple
```
git clone https://github.com/Emerentius/bigint_gcd_bench
cargo run --release
```
```
2^32n bits euclidean gcd binary gcd speedup
n: 1 => 0.3050s 0.0728s 4.19
n: 2 => 0.6228s 0.1453s 4.29
n: 3 => 0.9618s 0.2214s 4.34
n: 4 => 1.3021s 0.3028s 4.30
n: 5 => 1.6469s 0.3875s 4.25
n: 6 => 2.0017s 0.4759s 4.21
n: 7 => 2.3636s 0.5667s 4.17
n: 8 => 2.7284s 0.6418s 4.25
n: 9 => 3.0712s 0.7302s 4.21
n: 10 => 3.4822s 0.8223s 4.23
```
The guys at gmp say these algorithms are quadratic in N, I'm not sure why they seem almost linear here.
350: Avoid large intermediate product in LCM r=cuviper a=mhogrefe
Changed the implementation of BigUint LCM from
`((self * other) / self.gcd(other))`
to
`self / self.gcd(other) * other`
The division is exact in both cases, so the result is the same, but the new code avoids the potentially-large intermediate product, speeding things up and using less memory.
I also removed the unnecessary parentheses, because I think it's clear what order everything will be executed in. But if others think differently I can add them back.
351: Remove num-macros r=cuviper a=cuviper
The first commit gives a final deprecation bump to `num-macros`, and
the second removes it from the repo altogether.
- 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