2つの大きな整数の乗算時にオーバーフローをキャッチして計算する
2023-09-11 13:21:02
質問
私は、比較的大きな数値を乗算し、その結果を1つまたは複数の整数に格納するための効率的な(オプションとして標準的でエレガント、かつ実装が簡単な)ソリューションを探しています。
例えば、2つの64ビット整数がこのように宣言されているとします。
uint64_t a = xxx, b = yyy;
をすると
a * b
を実行したとき、演算がオーバーフローしたかどうかを検出し、この場合キャリーをどこかに保存するにはどうしたらよいでしょうか?
以下のことに注意してください。 大きな数のライブラリは使いたくありません。 というのも、数字を保存する方法に制約があるからです。
どのように解決するのですか?
1. オーバーフローを検出する :
x = a * b;
if (a != 0 && x / a != b) {
// overflow handling
}
編集:
0
(を修正しました(Markさんありがとうございます!)。
2. キャリーの計算 はかなり複雑です。1つのアプローチは、両方のオペランドをハーフワードに分割し、その後に 長い乗算 を半単語に適用することです。
uint64_t hi(uint64_t x) {
return x >> 32;
}
uint64_t lo(uint64_t x) {
return ((1ULL << 32) - 1) & x;
}
void multiply(uint64_t a, uint64_t b) {
// actually uint32_t would do, but the casting is annoying
uint64_t s0, s1, s2, s3;
uint64_t x = lo(a) * lo(b);
s0 = lo(x);
x = hi(a) * lo(b) + hi(x);
s1 = lo(x);
s2 = hi(x);
x = s1 + lo(a) * hi(b);
s1 = lo(x);
x = s2 + hi(a) * hi(b) + hi(x);
s2 = lo(x);
s3 = hi(x);
uint64_t result = s1 << 32 | s0;
uint64_t carry = s3 << 32 | s2;
}
部分和自体がどれもオーバーフローしないことを確認するために、最悪のケースを考えてみます。
x = s2 + hi(a) * hi(b) + hi(x)
を
B = 1 << 32
. そして、次のようになります。
x <= (B - 1) + (B - 1)(B - 1) + (B - 1)
<= B*B - 1
< B*B
少なくともSjlverのテストケースには対応しています。それ以外は未検証です (そして、もう手元に C++ コンパイラがないので、コンパイルさえできないかもしれません)。
関連
-
[解決済み] Valgrind が初期化されていないバイトについて警告する
-
[解決済み] 初期化でポインタ対象の型から修飾語を捨てる
-
[解決済み] C言語でchar配列をコピーする方法は?
-
[解決済み] 0から9までのランダムな整数を生成する
-
[解決済み] 配列のすべてのメンバーを同じ値で初期化するには?
-
[解決済み] C言語でオブジェクト指向のコードを書くとしたら、どのようにすればよいのでしょうか?[クローズド]
-
[解決済み] フリーは、どのように無料化を知っているのですか?
-
[解決済み] 2次元配列の反復処理において、ループの順序がパフォーマンスに影響するのはなぜですか?
-
[解決済み】C言語でシフト演算子を使った掛け算・割り算は実は速い?
-
[解決済み] C/C++の符号付きオーバーフローを検出する
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
ポインタ定数および定数ポインタ
-
error: 'for' loop initial declaration is only allowed in C99 mode 原因と解決方法
-
[解決済み] munmap_chunk(): 無効なポインタ
-
[解決済み] stdinとSTDIN_FILENOの違いは何ですか?
-
[解決済み] Windows用Cコンパイラ?[クローズド]
-
[解決済み] SQLiteのINSERT/per-secondのパフォーマンスを向上させる
-
[解決済み] Cプリプロセッサはなぜ "linux "という単語を定数 "1 "と解釈するのですか?
-
[解決済み] プログラム終了前にmallocの後にfreeをしないと本当に何が起こるのか?
-
[解決済み] .aファイル、.soファイルとは何ですか?
-
[解決済み] 2次元配列の反復処理において、ループの順序がパフォーマンスに影響するのはなぜですか?