我试图实现依赖于模幂运算的算法。我找不到像u64
这样的原生类型的任何模幂运算构造(仅适用于bigints),所以我认为我编写了标准modular exponentiation by repeated squaring method。
这是我想出的:
fn powm(base: &u64, exponent: &u64, modulus: &u64) -> u64 {
if *modulus == 1u64 {
0
} else {
let mut result = 1;
let mut base = self % modulus;
let mut exp = *exponent;
while exp > 0 {
if exp % 2 == 1 {
result = (result * base) % modulus;
}
exp >>= 1;
base = (base * base) % modulus;
}
result
}
}
这很好用。现在,我想将此功能设为通用,以便它也适用于u64
以外的数字类型。这是我开始有点迷失的地方。
我找到了num个包,它具有Num
个特征,指定了基本的数字操作。在分离出新的PowM
特征并创建一堆特征边界后,我最终得到:
extern crate num;
use num::Num;
use std::ops::{ShrAssign,Rem};
pub trait PowM {
fn powm(&self, exponent: &Self, modulus: &Self) -> Self;
}
pub trait Two {
fn two() -> Self;
}
impl Two for u64 {
fn two() -> u64 { return 2u64 }
}
impl Two for usize {
fn two() -> usize { return 2usize }
}
impl<T> PowM for T
where T: Num + Two + ShrAssign<T> + Rem<T> + PartialOrd<T> {
fn powm(&self, exponent: &T, modulus: &T) -> T {
if modulus == T::one() {
T::zero()
} else {
let mut result = T::one();
let mut base = *self % *modulus;
let mut exp = *exponent;
while exp > T::zero() {
if exp % T::two() == T::one() {
result = (result * base) % *modulus;
}
exp >>= T::one();
base = (base * base) % *modulus;
}
result
}
}
}
编译器提出的唯一抱怨如下
error[E0277]: the trait bound `&T: std::cmp::PartialEq<T>` is not satisfied
|
30 | if modulus == T::one() {
| ^^ can't compare `&T` with `T`
|
= help: the trait `std::cmp::PartialEq<T>` is not implemented for `&T`
= help: consider adding a `where &T: std::cmp::PartialEq<T>` bound
我试图添加特征界限,但最终追逐很多关于生命周期的编译器错误,我还不完全理解,最终坚持以下内容:
impl<'a, T> PowM for T
where T: 'a + Num + Two + ShrAssign<T> + Rem<T> + PartialOrd<T>,
&'a T: PartialEq<T> {
fn powm(&self, exponent: &T, modulus: &T) -> T {
if modulus == T::one() {
[...]
仍然会出错。我该如何解决这个问题?
答案 0 :(得分:2)
您可以忽略该问题,并将引用与非引用的引用或非引用进行比较:
if modulus == &T::one() {
// Or
if *modulus == T::one() {
或者您可以使用更高排名的特质界限:
impl<T> PowM for T
where
T: Num + Two + ShrAssign<T> + Rem<T> + PartialOrd<T>,
for <'a> &'a T: PartialEq<T>,
{
// ...
}
在任何一种情况下,您都需要T
实施Copy
或实施Clone
,然后向.clone()
添加适当的调用。
另见: