2 つの値のデータ型が「double」の場合。if や "?" などの比較演算子を使用せずに最大 2 つを取得する方法はありますか。もっと速い方法が必要です。
2 に答える
もっと速い方法が必要です。
比較より早い?とんでもない。Compare は、高度に最適化されたマシン命令を生成するだけです。あなたがそれをどのように改善するかわかりません。
しかし、ここにあなたの楽しみのためのいくつかの知的好奇心があります。
1 つの方法を次に示します。
double max = 0.5 * (a + b + fabs(a - b));
証拠:
a >= b => a - b >= 0
=> |a - b| = a - b
=> a + b + |a - b| = a + b + a - b = 2a
=> 0.5 * (a + b + |a - b|) = a
a < b => a - b < 0
=> |a - b| = b - a
=> a + b + |a - b| = a + b + b - a = 2b
=> 0.5 * (a + b + |a - b|) = b
これには弱点があることに注意してください。オーバーフローする可能性があります。
ここに別のものがあります:
double difference = a - b;
double sign = ((int)difference)>>63) & 1;
double max = a - difference * sign;
ここで直感が何であるかは明らかです。差の符号を (比較を使用せずに) 計算し、その符号を使用して最大値を計算します。
証拠:
a > b => a - b >= 0
=> difference >= 0
=> sign = 0
=> max = a - difference * sign = a - (a - b) * 0 = a
=> max = a
a < b => a - b < 0
=> difference < 0
=> sign = 1
=> max = a - difference * sign = a - (a - b) * 1 = a - a + b = b
=> max = b
注意してください、0 には +0d と -0d の 2 つの符号がありますが、それは問題ではありません! ただし、これもオーバーフローする可能性があります。
32 ビットまたは 64 ビット CPU 上のすべての最新の浮動小数点ユニットは、数クロック サイクルのレイテンシで、1 クロック サイクルごとに (少なくとも) 1 つの加算結果を生成できます。浮動小数点比較のパフォーマンスは、浮動小数点加算と同じです。したがって、他の浮動小数点命令の組み合わせを使用して浮動小数点比較を高速化することはできず、NaN の場合に整数比較を使用すると失敗します。
コンパイラがFCMOVcc
x86 のような条件付き移動を認識している場合、低速分岐命令を使用せずに最大 2 つの浮動小数点値を取得できます。