如何创建对各种整数类型通用的 is_prime 函数?

Posted

技术标签:

【中文标题】如何创建对各种整数类型通用的 is_prime 函数?【英文标题】:How can I create an is_prime function that is generic over various integer types? 【发布时间】:2015-01-04 19:24:12 【问题描述】:

我刚刚深入研究了 Rust,并想制作一些通用的基本数学函数。我有以下is_prime 函数:

fn is_prime(n: i64) -> bool 
    if n == 2 || n == 3 
        return true;
     else if n % 2 == 0 || n % 3 == 0 
        return false;
    

    let mut i = 5i64;
    let mut w = 2i64;
    while i*i <= n 
        if n % i == 0 
            return false;
        
        i += w;
        w = 6 - w;
    
    true

我需要什么才能将isizei64usize 等作为参数传递?我已经阅读了主页上的Rust guide,但我不确定如何将特质的想法应用到我的目标中。

【问题讨论】:

【参考方案1】:

使用通用数字类型可能会很麻烦,但是一旦您掌握了它们,它们就不会太糟糕,尽管有点冗长。这些方法的标准构建块是来自 crates.io 的 the num crate 中的特征,最值得注意的是 NumZeroOne,以及标准库的 std::cmp::PartialOrd

数字字面量不能泛型于任何数字类型;它们必须通过 trait 方法调用来完成; Zero::zero()One::one() 足以满足大多数用途——我们想要的数字是 0、1、2、3、5 和 6,这些数字可以通过这些构建块实现。您还可以使用生成这些值的静态方法创建自己的特征,并为您喜欢的任何数字类型实现它,但只使用 Num 保证的内容是一个更好的主意。

基本过程是将泛型类型参数指定为基于Num(以及PartialOrd,如果你在该类型的值上写不等式,例如i * i &lt;= n),并将任何数字文字替换为构造的文字从零到一,正如下面方法开头的半打 let 语句所示。这通常就足够了。

以下是这个特定方法的最终结果:

// You’ll also need the appropriate dependencies.num addition to Cargo.toml
extern crate num;

use num::Num;

fn is_prime<N: Num + PartialOrd + Copy>(n: N) -> bool 
    let _0 = N::zero();
    let _1 = N::one();
    let _2 = _1 + _1;
    let _3 = _2 + _1;
    let _5 = _2 + _3;
    let _6 = _3 + _3;
    if n == _2 || n == _3 
        return true;
     else if n % _2 == _0 || n % _3 == _0 
        return false;
    

    let mut i = _5;
    let mut w = _2;
    while i * i <= n 
        if n % i == _0 
            return false;
        
        i = i + w;
        w = _6 - w;
    
    true

【讨论】:

不使用Num trait 作为约束,也可以使用实际需要的基本特征:N: PartialEq + PartialOrd + Add&lt;N, N&gt; + Sub&lt;N, N&gt; + Mul&lt;N, N&gt; + Rem&lt;N, N&gt; + One + ZeroNum 只是一个方便的快捷方式。【参考方案2】:

要添加到 Chris Morgan 的答案,您可以使用 num::NumCast::from 转换为不适合使用 ZeroOne 的通用数字类型。在你的情况下:

use num::Num, NumCast;

fn is_prime<N: Num + Ord + NumCast + Copy>(n: N) -> bool 
    let _0: N = NumCast::from(0usize).unwrap();
    let _1: N = NumCast::from(1usize).unwrap();
    let _2: N = NumCast::from(2usize).unwrap();
    let _3: N = NumCast::from(3usize).unwrap();
    let _4: N = NumCast::from(4usize).unwrap();
    let _5: N = NumCast::from(5usize).unwrap();
    let _6: N = NumCast::from(6usize).unwrap();

【讨论】:

以上是关于如何创建对各种整数类型通用的 is_prime 函数?的主要内容,如果未能解决你的问题,请参考以下文章

区间素数筛法

(76)C#里怎么样选择各种通用类型容器

(76)C#里怎么样选择各种通用类型容器

如何制作一个比较任意数量的相同类型的通用 lambda

在Haskell中,如何创建具有多种类型的列表?

给定传递给它的参数类型,如何确定函数参数的类型?