59: Added `MulAdd` and `MulAddAssign` traits r=cuviper a=regexident
Both `f32` and `f64` implement fused multiply-add, which computes `(self * a) + b` with only one rounding error. This produces a more accurate result with better performance than a separate multiplication operation followed by an add:
```rust
fn mul_add(self, a: f32, b: f32) -> f32[src]
```
It is however not possible to make use of this in a generic context by abstracting over a trait.
My concrete use-case is machine learning, [gradient descent](https://en.wikipedia.org/wiki/Gradient_descent) to be specific,
where the core operation of updating the gradient could make use of `mul_add` for both its `weights: Vector` as well as its `bias: f32`:
```rust
struct Perceptron {
weights: Vector,
bias: f32,
}
impl MulAdd<f32, Self> for Vector {
// ...
}
impl Perceptron {
fn learn(&mut self, example: Vector, expected: f32, learning_rate: f32) {
let alpha = self.error(example, expected, learning_rate);
self.weights = example.mul_add(alpha, self.weights);
self.bias = self.bias.mul_add(alpha, self.bias)
}
}
```
(The actual impl of `Vector` would be generic over its value type: `Vector<T>`, thus requiring the trait.)
Co-authored-by: Vincent Esche <regexident@gmail.com>
Co-authored-by: Josh Stone <cuviper@gmail.com>
Make the checked left and right shifts take a `u32` as right-hand side,
which is more consistent with the other checked operations. Also drop
`CheckedShl` and `CheckedShr` from the `PrimInt` trait, to not break
existing code. Add doctests for the two traits.
Add traits `CheckedShl` and `CheckedShr` that correspond to the standard
library's `checked_shl` and `checked_shr` functions. Implement the trait
on all primitive integer types by default, akin to what the standard
library does.
The stdlib is somewhat inconsistent when it comes to the type of the
shift amount. The `checked_*` functions have a `u32` shift amount, but
the `std::ops::{Shl,Shr}` traits are generic over the shift amount. Also
the stdlib implements these traits for all primitive integer types as
right-hand sides. Our implementation mimics this behaviour.