簡體   English   中英

Rust signed modulo unsigned -> unsigned

[英]Rust signed modulo unsigned -> unsigned

在(穩定的)Rust 中,是否有相對直接的方法來實現以下功能?

fn mod_euclid(val: i128, modulo: u128) -> u128;

注意類型,即“標准”歐氏模數(結果始終在[0, mod)范圍內),避免中間計算中的虛假溢出/下溢 一些測試用例:

// don't-care, just no panic or UB.
// Mild preference for treating this as though it was mod=1<<128 instead of 0.
assert_dc!(mod_euclid(i128::MAX,         0)); 
assert_dc!(mod_euclid(        0,         0)); 
assert_dc!(mod_euclid(i128::MIN,         0)); 

assert_eq!(mod_euclid(        1,        10),                  1);
assert_eq!(mod_euclid(       -1,        10),                  9);
assert_eq!(mod_euclid(       11,        10),                  1);
assert_eq!(mod_euclid(      -11,        10),                  9);
assert_eq!(mod_euclid(i128::MAX,         1),                  0);
assert_eq!(mod_euclid(        0,         1),                  0);
assert_eq!(mod_euclid(i128::MIN,         1),                  0);
assert_eq!(mod_euclid(i128::MAX, u128::MAX),  i128::MAX as u128);
assert_eq!(mod_euclid(        0, u128::MAX),                  0);
assert_eq!(mod_euclid(i128::MIN, u128::MAX),  i128::MAX as u128);

對於signed%signed->signed,或者unsigned%unsigned->unsigned,這個比較直接。 但是,我找不到一種不轉換其中一個參數就計算 signed % unsigned -> unsigned 的好方法——正如最后一個示例所示,無論您選擇哪個方向,這都可能溢出或下溢。

據我所知,標准庫中沒有這樣的函數,但是自己寫一個也不是很難:

fn mod_euclid(a: i128, b: u128) -> u128 {
    if a >= 0 {
        (a as u128) % b
    } else {
        let r = (!a as u128) % b;
        b - r - 1
    }
}

游樂場鏈接

怎么運行的:

  • 如果a是非負的,那么它很簡單——只需使用無符號余數運算符。
  • 否則,按位補碼!a是非負的(因為符號位被翻轉),並且在數值上等於-a - 1 這意味着r等價於b - a - 1b ,因此b - r - 1等價於ab 方便地, b - r - 1在預期范圍內0..b

也許更直接一點,盡可能使用rem_euclid並返回if a >= 0 {a} else {u128::MAX + a} else:

pub fn mod_euclid(a: i128, b: u128) -> u128 {
    const UPPER: u128 = i128::MAX as u128;
    match b {
        1..=UPPER => a.rem_euclid(b as i128) as u128,
        _ => a as u128 - (a < 0) as u128,
    }
}

(解析器不喜歡我在比賽中的鑄造,因此UPPER

操場

在 x86_64 上也會導致更少的指令和跳轉

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM