2017-10-20 55 views
1

我想实现一个依赖于模幂运算的算法。我找不到像u64(仅适用于bigint)等原生类型的任何模幂运算构造,所以我想我会编码一个标准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() { 
[...] 

仍然给人错误。我该如何解决?

回答

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()

参见: