オーバーフローの取扱について。
基本的にはオーバーフローすると開発ビルドではパニック、リリースビルドでは無視される。つまり、前者はエラー検出、後者は実行速度を優先している。この設定は Cargo.toml から以下のように変更できる (詳細は後述の仕様を参照)。
[profile.dev]
overflow-checks = false
checked_xxx
オーバーフローすると None が戻され、それ以外では Some で計算結果が戻される。
fn main() {
assert_eq!(i32::checked_add(2, 3), Some(5));
assert_eq!(i32::checked_add(i32::MAX, 1), None);
}
overflowing_xxxオーバーフローした上位ビットは無視され、共にオーバーフローの有無が戻される。
fn main() {
assert_eq!(i32::overflowing_add(2, 3), (5, false));
assert_eq!(i32::overflowing_add(i32::MAX, 3), (i32::MIN + 2, true));
}
saturating_xxx計算結果が最小値と最大値に抑制される。
fn main() {
assert_eq!(i32::saturating_add(2, 3), 5);
assert_eq!(i32::saturating_add(i32::MAX, 3), i32::MAX);
}
strict_xxxオーバーフローするとパニックする。
fn main() {
assert_eq!(i32::strict_add(2, 3), 5);
let _val = i32::strict_add(i32::MAX, 1); // ⚠️ Panic!
unreachable!();
}
unbounded_xxxビットシフト用。第二引数に整数型のビット数以上の値を指定可能にする。
fn main() {
assert_eq!(i32::unbounded_shl(1, 3), 8);
assert_eq!(i32::unbounded_shl(1, 32), 0);
}
unchecked_xxx
unsafe 関数。オーバーフローは UB (Undefineded Behavior) として処理する。
fn main() {
unsafe {
assert_eq!(i32::unchecked_add(2, 3), 5);
let _val = i32::unchecked_add(i32::MAX, 1); // ⚠️ UB!
}
}
wrapping_xxxオーバーフローした上位ビットは無視される。
fn main() {
assert_eq!(i32::wrapping_add(2, 3), 5);
assert_eq!(i32::wrapping_add(i32::MAX, 3), i32::MIN + 2);
}
Saturating
saturating_xxx のラッパー版。
use std::num::Saturating;
fn main() {
assert_eq!(Saturating(2) + Saturating(3), Saturating(5));
assert_eq!(Saturating(i32::MAX) + Saturating(3), Saturating(i32::MAX));
}
Wrapping
wrapping_xxx のラッパー版。
use std::num::Wrapping;
fn main() {
assert_eq!(Wrapping(2) + Wrapping(3), Wrapping(5));
assert_eq!(Wrapping(i32::MAX) + Wrapping(3), Wrapping(i32::MIN + 2));
}
、以下の API はまだナイトリーだが、参考としてメモしておく。
borrowing_xxx多倍長整数の演算に利用できる。前の減算のオーバーフローを今回の減算に加味しつつ、減算結果とオーバーフローの発生有無を取得する。
#![feature(signed_bigint_helpers)]
fn main() {
assert_eq!(i32::borrowing_sub(7, 3, false), (4, false));
assert_eq!(i32::borrowing_sub(7, 3, true), (3, false));
assert_eq!(i32::borrowing_sub(i32::MIN, 3, false), (i32::MAX - 2, true));
assert_eq!(i32::borrowing_sub(i32::MIN, 3, true), (i32::MAX - 3, true));
}
carrying_xxx多倍長整数の演算に利用できる。前の計算のオーバーフローを今回の計算に加味しつつ、計算結果とオーバーフローの発生有無 (乗算の場合は上位ビット群) を取得する。
#![feature(signed_bigint_helpers)]
fn main() {
assert_eq!(i32::carrying_add(2, 3, false), (5, false));
assert_eq!(i32::carrying_add(2, 3, true), (6, false));
assert_eq!(i32::carrying_add(i32::MAX, 3, false), (i32::MIN + 2, true));
assert_eq!(i32::carrying_add(i32::MAX, 3, true), (i32::MIN + 3, true));
}
widening_mul乗算結果とオーバーフローによる上位ビット群を取得する。
#![feature(widening_mul)]
fn main() {
assert_eq!(u8::widening_mul(2, 3), (6, 0));
assert_eq!(u8::widening_mul(0b1000_0000, 3), (0b1000_0000, 1));
}