我正在try 编写在很多值上完成的代码,而我的代码正在做大量的额外工作.我甚至不太确定如何从数学上描述我想跳过的值,因为随着i变大,我想跳过i中越来越大的百分比.

使用伪代码来解释将是最容易的:

f(n)
    while n > 0
        if 32 < n%250 < 129 do work, else discard
        n = floor( n/250 )
        
g(n)
    while n > 0
        if n%3 == 0 do work, else discard
        n = floor( n/288 )

main()
    for i in range
        print f(i) and g(i) if neither function hits discard & both same total # of loops

我想要一个浪费尽可能少计算的range.到目前为止,我所能想到的优化方法是使用(0..n).step_by(3)来至少使g(n)的第一个循环始终是好的,并且首先运行+判断f(n),这样在命中丢弃时就不需要运行g(n)了.我正在寻找的是一种定义范围的方法,类似于.step_by(3)如何只try 对while中的所有循环的第一个循环g(n)有效的值.最好,我希望while循环中根本不需要任何if语句,而是有一个只try 成功值的范围.

基本上我想问的是,有没有办法try 更少的值,这样代码的大O与91有关,而不是250和288(或者如果你能从最后的if中加入一些逻辑,并使它甚至低于91,那就太棒了).我得到了正确的输出,但这需要很长时间.我试图在尽可能大的范围内运行它;最终目标是将它运行到250^40==8.27e95==2^319.7的数量级,因此在需要运行函数之前确定哪些值是可跳过的将节省大量计算.

to help me make sense of describing the values I want, I have drawn a grid for valid values only considering the g(n) case and with smaller numbers [n%2 and floor(n/6)]. the highlighted full blue columns are the numbers that would go through in this case and the highlighted white rows are the points where the values are discarded. grid of numbers with cases that make it through highlighted here's the same thing but with [n%3 and floor(n/6)] basically looks the same as the other one here's the f(n) function but with 1<n%6<4 enter image description here

如果您想查看完整代码或推荐任何其他优化,您也可以在下面看到:

use arrayvec::ArrayVec;
fn main() {
    'outer: for n in (0..18446744073709551615u64).step_by(3) { //2^64-1; make smaller if you want the code to finish
        let mut base250: ArrayVec<u8, 8> = ArrayVec::new(); //using ArrayVec makes reallocation slowdowns go away
        let mut tmp:u8;
        let mut m = n;
        while m > 0 { //f(n) of the psudocode; inlined here
            tmp = (m%250).try_into().unwrap(); //type goes from u64(n) into u8(tmp)
            if tmp-33 < 96 { //takes advantage of uint rollover to just do 1 comparison
                base250.push(tmp-1);
            } else { continue 'outer; } //condition broke; discard this run and try the next value
            m /= 250;
        }
        m = n;
        let mut base288: ArrayVec<u8, 8> = ArrayVec::new();
        while m > 0 { //g(n) of the psudocode; inlined here
            if m%3==0 {
                base288.push((m/3%96+32).try_into().unwrap()); //type goes from u64(n) into u8(t)
            } else { continue 'outer; } //condition broke; discard this run and try the next value
            m /= 288;
        }
        base250.reverse();
        if base250.iter().zip(base288.iter()).filter(|&(a,b)| a==b).count() > 3 { //checks how many values are matching
            let long:String = base250.iter().map(|&c|{if c == 127u8 {'¶'} // convert the vector to a string
                                                  else if c == 32u8 {'█'} // with readable newlines and spaces
                                                  else {c.try_into().unwrap()} }).collect();
            let short:String = base288.iter().map(|&c|{if c == 127u8 {'¶'}
                                                  else if c == 32u8 {'█'}
                                                  else {c.try_into().unwrap()} }).collect();
            println!("{long}   {short}   {n}");
        }
    }
}

一位 comments 者建议我try 一次一个值地保存向量,以消除While循环,但由于While循环比for循环小得多,我认为更值得try 少做大循环.我试着实现它,但在我的计算机可以运行的所有范围内,它都慢得多;无论如何,如果你有什么建议可以加快它的速度,这里就是它.从数学上讲,这段代码与前一段代码完全相同.我见过有人说.clone()调用成本很高,但我对*&的了解还不够多,无法在没有.clone()的情况下编译它

fn main() {
    let mut base250known: HashMap<u64, ArrayVec<u8, 8>> = HashMap::from([(0u64,ArrayVec::new())]);
    let mut base288known: HashMap<u64, ArrayVec<u8, 8>> = HashMap::from([(0u64,ArrayVec::new())]);
    for n in 1..18446744073709551615u64 {
        let mut check: bool = true;
        if n%250-33 < 96 {
            let mut old = match base250known.get(&(n/250)) { //get the value from the previous loop
                Some(old) => old.clone(),
                None => ArrayVec::from([255u8,255u8,255u8,255u8,255u8,255u8,255u8,255u8])
            }; //max ArrayVec will never be set; we can use this to check if we hit a known value
            if old != ArrayVec::from([255u8,255u8,255u8,255u8,255u8,255u8,255u8,255u8]) {
                old.push((n%250-1).try_into().unwrap()); //add the new value
                base250known.insert(n,old); //save it in the new spot
            } else { check = false; }
        } else { check = false; }
        if n%3==0 {
            let mut old = match base288known.get(&(n/288)) {
                Some(old) => old.clone(),
                None => ArrayVec::from([255u8,255u8,255u8,255u8,255u8,255u8,255u8,255u8])
            };
            if old != ArrayVec::from([255u8,255u8,255u8,255u8,255u8,255u8,255u8,255u8]) {
                old.push((n/3%96+32).try_into().unwrap());
                base288known.insert(n,old);
            } else { check = false; }
        } else { check = false; } //all these check=false s are to make sure we don't get an unassigned hash in this if
        if check { if base250known[&n].iter().zip(base288known[&n].iter().rev()).filter(|&(a,b)| a==b).count() > 3 {
            let long:String = base250known[&n].iter().map(|&c|{if c == 127u8 {'¶'}
                                                                else if c == 32u8 {'█'}
                                                                else {c.try_into().unwrap()} }).collect();
            let short:String = base288known[&n].iter().rev().map(|&c|{if c == 127u8 {'¶'}
                                                                    else if c == 32u8 {'█'}
                                                                    else {c.try_into().unwrap()} }).collect();
            println!("{long}   {short}   {n}");   }   }   }   } //inlining the close parens makes the scrollbar go away

推荐答案

这是一个不言而喻的答案,也是一个糟糕的答案,但从技术上讲,我得到了代码来做我说我想做的事情.本质上,这使得第一次判断范围,所以每次While在原始代码中循环时,我只是创建一个新的for循环.在创建了范围之后,第二个判断变成了一个过滤器,我将其分解为位于代码末尾的第二个函数.只要您创建足够的循环来捕获整个范围,它就是相同的代码.

use arrayvec::ArrayVec;
use itertools::iproduct;

fn main() {
    for a in (33u64..129u64).filter(|a| acceptable(&[a])) {
            let mut raw: u64 = a;
            let mut base288: ArrayVec<u8, 1> = ArrayVec::new();
            while raw > 0 {
                base288.push((raw/3%96+32).try_into().unwrap());
                raw /= 288;
            }
            let base250: ArrayVec<u8, 1> = ArrayVec::from([a.try_into().unwrap()]);

            if base250.iter().zip(base288.iter()).filter(|&(a,b)| a-1==*b).count() >= 0 {
                let s:String = base250.iter().map(|&c|{if (c-1) == 127u8 {'¶'}
                                                    else if (c-1) == 32u8 {'█'}
                                                    else {(c-1).try_into().unwrap()} }).collect();
                let t:String = base288.iter().map(|&c|{if (c) == 127u8 {'¶'}
                                                    else if (c) == 32u8 {'█'}
                                                    else {(c).try_into().unwrap()} }).collect();
                let n: u64 = a;
                println!("{s}   {t}   {n}");
            }
        }
    println!("1 digit");
    for (b,a) in (iproduct![33u64..129u64,33u64..129u64]).filter(|(b,a)| acceptable(&[a,b])) {
            let mut raw: u64 = (b)*250u64 + (a);
            let mut base288: ArrayVec<u8, 2> = ArrayVec::new();
            while raw > 0 {
                base288.push((raw/3%96+32).try_into().unwrap());
                raw /= 288;
            }
            let base250: ArrayVec<u8, 2> = ArrayVec::from([b.try_into().unwrap(),a.try_into().unwrap()]);

            if base250.iter().zip(base288.iter()).filter(|&(a,b)| a-1==*b).count() > 0 {
                let s:String = base250.iter().map(|&c|{if (c-1) == 127u8 {'¶'}
                                                    else if (c-1) == 32u8 {'█'}
                                                    else {(c-1).try_into().unwrap()} }).collect();
                let t:String = base288.iter().map(|&c|{if (c) == 127u8 {'¶'}
                                                    else if (c) == 32u8 {'█'}
                                                    else {(c).try_into().unwrap()} }).collect();
                let n: u64 = (b)*250u64 + (a);
                println!("{s}   {t}   {n}");
            }
        }
    println!("2 digits");
    for (c,b,a) in (iproduct![33u64..129u64,33u64..129u64,33u64..129u64]).filter(|(c,b,a)| acceptable(&[a,b,c])) {
            let mut raw: u64 = (c)*250u64.pow(2) + (b)*250u64 + (a);
            let mut base288: ArrayVec<u8, 3> = ArrayVec::new();
            while raw > 0 {
                base288.push((raw/3%96+32).try_into().unwrap());
                raw /= 288;
            }
            let base250: ArrayVec<u8, 3> = ArrayVec::from([c.try_into().unwrap(),b.try_into().unwrap(),a.try_into().unwrap()]);

            if base250.iter().zip(base288.iter()).filter(|&(a,b)| a-1==*b).count() > 1 {
                let s:String = base250.iter().map(|&c|{if (c-1) == 127u8 {'¶'}
                                                    else if (c-1) == 32u8 {'█'}
                                                    else {(c-1).try_into().unwrap()} }).collect();
                let t:String = base288.iter().map(|&c|{if (c) == 127u8 {'¶'}
                                                    else if (c) == 32u8 {'█'}
                                                    else {(c).try_into().unwrap()} }).collect();
                let n: u64 = (c)*250u64.pow(2) + (b)*250u64 + (a);
                println!("{s}   {t}   {n}");
            }
        }
    println!("3 digits");
    for (d,c,b,a) in (iproduct![33u64..129u64,33u64..129u64,33u64..129u64,33u64..129u64]).filter(|(d,c,b,a)| acceptable(&[a,b,c,d])) {
            let mut raw: u64 = (d)*250u64.pow(3) + (c)*250u64.pow(2) + (b)*250u64 + (a);
            let mut base288: ArrayVec<u8, 4> = ArrayVec::new();
            while raw > 0 {
                base288.push((raw/3%96+32).try_into().unwrap());
                raw /= 288;
            }
            let base250: ArrayVec<u8, 4> = ArrayVec::from([d.try_into().unwrap(),c.try_into().unwrap(),b.try_into().unwrap(),a.try_into().unwrap()]);

            if base250.iter().zip(base288.iter()).filter(|&(a,b)| a-1==*b).count() > 2 {
                let s:String = base250.iter().map(|&c|{if (c-1) == 127u8 {'¶'}
                                                    else if (c-1) == 32u8 {'█'}
                                                    else {(c-1).try_into().unwrap()} }).collect();
                let t:String = base288.iter().map(|&c|{if (c) == 127u8 {'¶'}
                                                    else if (c) == 32u8 {'█'}
                                                    else {(c).try_into().unwrap()} }).collect();
                let n: u64 = (d)*250u64.pow(3) + (c)*250u64.pow(2) + (b)*250u64 + (a);
                println!("{s}   {t}   {n}");
            }
        }
    println!("4 digits");
    for (e,d,c,b,a) in (iproduct![33u64..129u64,33u64..129u64,33u64..129u64,33u64..129u64,33u64..129u64]).filter(|(e,d,c,b,a)| acceptable(&[a,b,c,d,e])) {
            let mut raw: u64 = (e)*250u64.pow(4) + (d)*250u64.pow(3) + (c)*250u64.pow(2) + (b)*250u64 + (a);
            let mut base288: ArrayVec<u8, 5> = ArrayVec::new();
            while raw > 0 {
                base288.push((raw/3%96+32).try_into().unwrap());
                raw /= 288;
            }
            let base250: ArrayVec<u8, 5> = ArrayVec::from([e.try_into().unwrap(),d.try_into().unwrap(),c.try_into().unwrap(),b.try_into().unwrap(),a.try_into().unwrap()]);

            if base250.iter().zip(base288.iter()).filter(|&(a,b)| a-1==*b).count() > 3 {
                let s:String = base250.iter().map(|&c|{if (c-1) == 127u8 {'¶'}
                                                    else if (c-1) == 32u8 {'█'}
                                                    else {(c-1).try_into().unwrap()} }).collect();
                let t:String = base288.iter().map(|&c|{if (c) == 127u8 {'¶'}
                                                    else if (c) == 32u8 {'█'}
                                                    else {(c).try_into().unwrap()} }).collect();
                let n: u64 = (e)*250u64.pow(4) + (d)*250u64.pow(3) + (c)*250u64.pow(2) + (b)*250u64 + (a);
                println!("{s}   {t}   {n}");
            }
        }
    println!("5 digits");
    for (f,e,d,c,b,a) in (iproduct![33u64..129u64,33u64..129u64,33u64..129u64,33u64..129u64,33u64..129u64,33u64..129u64]).filter(|(f,e,d,c,b,a)| acceptable(&[a,b,c,d,e,f])) {
            let mut raw: u64 = (f)*250u64.pow(5) + (e)*250u64.pow(4) + (d)*250u64.pow(3) + (c)*250u64.pow(2) + (b)*250u64 + (a);
            let mut base288: ArrayVec<u8, 6> = ArrayVec::new();
            while raw > 0 {
                base288.push((raw/3%96+32).try_into().unwrap());
                raw /= 288;
            }
            let base250: ArrayVec<u8, 6> = ArrayVec::from([f.try_into().unwrap(),e.try_into().unwrap(),d.try_into().unwrap(),c.try_into().unwrap(),b.try_into().unwrap(),a.try_into().unwrap()]);

            if base250.iter().zip(base288.iter()).filter(|&(a,b)| a-1==*b).count() > 4 {
                let s:String = base250.iter().map(|&c|{if (c-1) == 127u8 {'¶'}
                                                    else if (c-1) == 32u8 {'█'}
                                                    else {(c-1).try_into().unwrap()} }).collect();
                let t:String = base288.iter().map(|&c|{if (c) == 127u8 {'¶'}
                                                    else if (c) == 32u8 {'█'}
                                                    else {(c).try_into().unwrap()} }).collect();
                let n: u64 = (f)*250u64.pow(5) + (e)*250u64.pow(4) + (d)*250u64.pow(3) + (c)*250u64.pow(2) + (b)*250u64 + (a);
                println!("{s}   {t}   {n}");
            }
        }
    println!("6 digits");
    for (g,f,e,d,c,b,a) in (iproduct![33u64..129u64,33u64..129u64,33u64..129u64,33u64..129u64,33u64..129u64,33u64..129u64,33u64..129u64]).filter(|(g,f,e,d,c,b,a)| acceptable(&[a,b,c,d,e,f,g])) {
        let mut raw: u64 = (g)*250u64.pow(6) + (f)*250u64.pow(5) + (e)*250u64.pow(4) + (d)*250u64.pow(3) + (c)*250u64.pow(2) + (b)*250u64 + (a);
        let mut base288: ArrayVec<u8, 7> = ArrayVec::new();
        while raw > 0 {
            base288.push((raw/3%96+32).try_into().unwrap());
            raw /= 288;
        }
        let base250: ArrayVec<u8, 7> = ArrayVec::from([g.try_into().unwrap(),f.try_into().unwrap(),e.try_into().unwrap(),d.try_into().unwrap(),c.try_into().unwrap(),b.try_into().unwrap(),a.try_into().unwrap()]);

        if base250.iter().zip(base288.iter()).filter(|&(a,b)| a-1==*b).count() > 5 {
            let s:String = base250.iter().map(|&c|{if (c-1) == 127u8 {'¶'}
                                                else if (c-1) == 32u8 {'█'}
                                                else {(c-1).try_into().unwrap()} }).collect();
            let t:String = base288.iter().map(|&c|{if (c) == 127u8 {'¶'}
                                                else if (c) == 32u8 {'█'}
                                                else {(c).try_into().unwrap()} }).collect();
            let n: u64 = (g)*250u64.pow(6) + (f)*250u64.pow(5) + (e)*250u64.pow(4) + (d)*250u64.pow(3) + (c)*250u64.pow(2) + (b)*250u64 + (a);
            println!("{s}   {t}   {n}");
        }
    }
    println!("7 digits");
    for (h,g,f,e,d,c,b,a) in (iproduct![33u64..129u64,33u64..129u64,33u64..129u64,33u64..129u64,33u64..129u64,33u64..129u64,33u64..129u64,33u64..129u64]).filter(|(h,g,f,e,d,c,b,a)| acceptable(&[a,b,c,d,e,f,g,h])) {
        let mut raw: u64 = (h)*250u64.pow(7) + (g)*250u64.pow(6) + (f)*250u64.pow(5) + (e)*250u64.pow(4) + (d)*250u64.pow(3) + (c)*250u64.pow(2) + (b)*250u64 + (a);
        let mut base288: ArrayVec<u8, 8> = ArrayVec::new();
        while raw > 0 {
            base288.push((raw/3%96+32).try_into().unwrap());
            raw /= 288;
        }
        let base250: ArrayVec<u8, 8> = ArrayVec::from([h.try_into().unwrap(),g.try_into().unwrap(),f.try_into().unwrap(),e.try_into().unwrap(),d.try_into().unwrap(),c.try_into().unwrap(),b.try_into().unwrap(),a.try_into().unwrap()]);

        if base250.iter().zip(base288.iter()).filter(|&(a,b)| a-1==*b).count() > 6 {
            let s:String = base250.iter().map(|&c|{if (c-1) == 127u8 {'¶'}
                                                else if (c-1) == 32u8 {'█'}
                                                else {(c-1).try_into().unwrap()} }).collect();
            let t:String = base288.iter().map(|&c|{if (c) == 127u8 {'¶'}
                                                else if (c) == 32u8 {'█'}
                                                else {(c).try_into().unwrap()} }).collect();
            let n: u64 = (h)*250u64.pow(7) + (g)*250u64.pow(6) + (f)*250u64.pow(5) + (e)*250u64.pow(4) + (d)*250u64.pow(3) + (c)*250u64.pow(2) + (b)*250u64 + (a);
            println!("{s}   {t}   {n}");
        }
    }
    println!("8 digits");
    fn acceptable (nums: &[&u64]) -> bool {
        let mut raw: u64 = 0;
        for i in 0..nums.len() { raw += nums[i] * 250u64.pow(i.try_into().unwrap()); }
        while raw > 0 { if raw%3==0 { raw /= 288; } else { return false; } }
        return true;
    }
}

代码重复得很愚蠢,而且非常长,所以我觉得它应该能够重写为形式的一个循环

for j in (1..) {
    for a in (iproduct!(33u64..129u64 j times)).filter(|j variables| acceptable(&[j variables backwards]) {
}

诸如此类,但我不知道如何用铁 rust 来形容.我仍然欢迎更多关于加快速度的 comments ,特别是这里的判断:

base250.iter().zip(base288.iter()).filter(|&(a,b)| a-1==*b).count() > j

因为我怀疑这是计算机正在做的大量工作.我只是想判断两个vec之间的相似性,如果你知道一个更快的方法来判断'接近但不一定精确',即使它是一个不同的实现,从这一行的概念,我会非常感激.

Rust相关问答推荐

如何将元素添加到向量并返回对该元素的引用?

rust 迹-内存管理-POP所有权-链表

如何在 struct 的自定义序列化程序中使用serde序列化_WITH

integer cast as pointer是什么意思

如何循环遍历0..V.len()-1何时v可能为空?

如何从ruust中的fig.toml中读取?

如何go 除多余的(0..)在迭代中,当它不被使用时?

找不到 .has_func 或 .get_func 的 def

当我try 使用 SKI 演算中的S I I实现递归时,为什么 Rust 会失败?

如何强制匹配的返回类型为()?

为什么某些类型参数仅在特征边界中使用的代码在没有 PhantomData 的情况下进行编译?

无法理解 Rust 对临时值的不可变和可变引用是如何被删除的

Rust 将特性传递给依赖项

当我不满足特征界限时会发生什么?

我如何将 google_gmail1::Gmail> 传递给线程生成?

如何为返回正确类型的枚举实现 get 方法?

您如何使用枚举反序列化字符串,其中任何其他值反序列化为新类型变体同时保留字符串?

在传输不可复制的值时实现就地枚举修改

为什么 `ref` 会导致此示例*取消引用*一个字段?

有什么办法可以用 Rust 访问 Windows 最近的文件夹吗?