These should be easy to implement.
I created some implementations, but I don't want to check, which of them should be functions, methods or trait implementations.
I made all of them trait implementations for now.
If the value can not
Here are the implementations:
// Pow by ratio
// I only tested this function; I use it in my code
fn pow_ratio<I: PrimInt + Roots>(a: Ratio<I>, b: Ratio<u32>) -> Option<Ratio<I>> {
let (an, ad) = a.into();
let (bn, bd) = b.into();
let pown = an.pow(bn);
let powd = ad.pow(bn);
let n = pown.nth_root(bd);
let d = powd.nth_root(bd);
// If there does not exist a rational power, return none
if n.pow(bd) != pown || d.pow(bd) != powd {
None
} else {
Some(Ratio::new(n, d))
}
}
// Pow by integer
fn pow_integer<I: PrimInt>(a: Ratio<I>, b: u32) -> Ratio<I> {
let (an, ad) = a.into();
let pown = an.pow(b);
let powd = ad.pow(b);
Ratio::new(n, d)
}
// Root by integer
fn root_integer<I: PrimInt + Roots>(a: Ratio<I>, b: u32) -> Option<Ratio<I>> {
// add checks if b is zero and either return none or some result for more expressiveness
let (an, ad) = a.into();
let n = an.nth_root(b);
let d = ad.nth_root(b);
// If there does not exist a rational root, return none
if n.pow(b) != pown || d.pow(b) != powd {
None
} else {
Some(Ratio::new(n, d))
}
}
// Root by ratio
fn root_ratio<I: PrimInt + Roots>(a: Ratio<I>, b: Ratio<u32>) -> Option<Ratio<I>> {
// add checks if b is zero and either return none or some result for more expressiveness
pow_ratio(a, b.inv())
}
// Square root
fn sqrt<I: PrimInt + Roots>(a: Ratio<I>, b: Ratio<u32>) -> Option<Ratio<I>> {
// use a version of this function without the zero check for argument b
root_integer(a, 2)
}
// Cubic root
fn cbrt<I: PrimInt + Roots>(a: Ratio<I>, b: Ratio<u32>) -> Option<Ratio<I>> {
// use a version of this function without the zero check for argument b
root_integer(a, 3)
}
pow_integerand root_integer could be implemented using pow_ratio and root_ratio by supplying constant values.
The compiler should be able to optimize, at least if the functions are declared as inline.
Should all of these functions be added anyway?
These should be easy to implement.
I created some implementations, but I don't want to check, which of them should be functions, methods or trait implementations.
I made all of them trait implementations for now.
If the value can not
Here are the implementations:
pow_integerandroot_integercould be implemented usingpow_ratioandroot_ratioby supplying constant values.The compiler should be able to optimize, at least if the functions are declared as
inline.Should all of these functions be added anyway?