std::min の引数順で浮動小数点のコンパイラ出力が変わる
疑問点
コンパイラエクスプローラでいじっていたら、std::minに渡される引数の順番で、生成されるアセンブリが変わることがわかりました。
以下は Godbolt Compiler Explorer での例です。
double std_min_xy(double x, double y) {
return std::min(x, y);
}
double std_min_yx(double x, double y) {
return std::min(y, x);
}
これをコンパイルすると(例えばclang 9.0.0では-O3付き)、次のようになります。
std_min_xy(double, double): # @std_min_xy(double, double)
minsd xmm1, xmm0
movapd xmm0, xmm1
ret
std_min_yx(double, double): # @std_min_yx(double, double)
minsd xmm0, xmm1
ret
これは std::min を古い三項演算子に変えても変わりません。また、私が試したすべての最新のコンパイラー (clang、gcc、icc) にわたって持続します。
基礎となる命令は
minsd
. ドキュメントを読むと、最初の引数は
minsd
の最初の引数は答えの行き先でもあります。どうやら xmm0 は私の関数がその戻り値を置くことになっている場所なので、もし xmm0 が最初の引数として使われるなら、そこには
movapd
は必要ありません。しかし、もしxmm0が第2引数であるなら、それは
movapd xmm0, xmm1
でxmm0に値を取り込むことができます(編集部注:そうです。
x86-64システムV
は FP の引数を xmm0, xmm1 などで渡し、xmm0 で返します)。
私の質問:なぜコンパイラは引数の順番自体を切り替えないのでしょうか?そうすれば、この
movapd
は必要ないのでしょうか?それはきっと、minsdへの引数の順序が答えを変えないことを知っているに違いない?私が評価していない何らかの副作用があるのでしょうか?
どのように解決するのか?
minsd a,b
はいくつかの特殊なFP値に対して可換でなく、また
std::min
を使用しない限り
-ffast-math
.
minsd a,b
まさに
実装
(a<b) ? a : b
を実装しており、厳密なIEEE-754セマンティックスの符号付きゼロとNaNについて暗示しているすべてを含んでいます。(すなわち、それはソースオペランドを保持します。
b
を、順序のない
1
またはそれに等しい)。 Artyerが指摘するように
-0.0
と
+0.0
は等しいことを比較する(つまり
-0. < 0.
は偽)ですが、両者は区別されます。
std::min
が定義されているのは
(a<b)
の比較式 (
cppreference
) を使って
(a<b) ? a : b
とは異なり、可能な実装として
std::fmin
とは異なり、特にどちらかのオペランドからのNaN伝搬を保証しています。 (
fmin
は元々C++のテンプレートではなく、Cの数学ライブラリから来たものです)。
参照 x86で分岐のないFPのminとmaxを与える命令は何ですか? minss/minsd / maxss/maxsd (そして、いくつかのGCCバージョンを除いて、同じ非可換ルールに従う対応する組込み関数)についてのより多くの詳細については、以下を参照してください。
脚注 1: 覚えておいてほしいのは
NaN<b
が偽であることを忘れないでください。
b
に対して、また任意の比較述語に対して偽となります。 例えば
NaN == b
は偽で、同様に
NaN > b
. であっても
NaN == NaN
は偽です。 ペアのうちの1つ以上がNaNであるとき、それらは互いに"unordered"です。
と
-ffast-math
(NaNがないと仮定することや、その他の仮定や近似をコンパイラに指示する)、コンパイラは
は
に最適化し、どちらかの関数を単一の
minsd
.
https://godbolt.org/z/a7oK91
GCCについては
https://gcc.gnu.org/wiki/FloatingPointMath
clang は同様のオプションをサポートしています。
-ffast-math
をキャッチオールとします。
これらのオプションのいくつかは、奇妙なレガシーコードベースを除いて、ほとんどすべての人が有効にすべきもので、例えば
-fno-math-errno
. (参照
この Q&A で推奨される数学的最適化について詳しく説明しています。
). また、gcc
-fno-trapping-math
はデフォルトでオンになっているにもかかわらず、 いずれにせよ完全には機能しないからです (いくつかの最適化は、例外がマスクされていない場合に発生する FP 例外を、時には 1 から 0 や 0 から 0 以外に変更することさえ含みます、IRC です)。
gcc -ftrapping-math
は、例外のセマンティクスに関してさえ100%安全であるいくつかの最適化をブロックするので、かなり悪いです。 を使わないコードでは
fenv.h
を使用しないコードでは、その違いは決してわからないでしょう。
しかし
std::min
を可換とすることは、NaNを仮定しないオプションなどでしか実現できないので、間違いなく "safe"とは呼べないでしょう。
は、NaNで何が起こるかを正確に気にするコードのために、 例えば、以下のようになります。
-ffinite-math-only
はNaNがない(無限大もない)と仮定しています。
clang -funsafe-math-optimizations -ffinite-math-only
は、あなたが探している最適化を行います。 (unsafe-math-optimizations は、符号付きゼロのセマンティクスを気にしないなど、より具体的なオプションの束を意味します)。
関連
-
[解決済み] SDカードからファイルを削除する方法を教えてください。
-
[解決済み] Android Webview - キャッシュを完全に削除する
-
[解決済み] 深くネストされたスタックから離れるとき、Fragmentのバックスタックをクリーンアップする方法はこれで良いのでしょうか?
-
[解決済み] 「KotlinとAndroidで「パラメータTを推測するのに十分な情報がありません。
-
[解決済み] アンドロイドのクライアントでヒープアップデートを有効にする方法
-
[解決済み] Android: ランドスケープモード用の代替レイアウト xml
-
[解決済み] キャンバスに複数行のテキストを描画する
-
[解決済み] AsyncTaskLoaderとAsyncTaskの比較
-
[解決済み] Android: xml リソースからの整数値
-
[解決済み] HttpURLConnectionを使ったPOSTによるファイル送信
最新
-
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 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] 設定ページに移動せずに位置情報サービスをオンにする
-
[解決済み] ArrayAdapter<myClass> の使用方法
-
[解決済み] Android Webview - キャッシュを完全に削除する
-
[解決済み] 深くネストされたスタックから離れるとき、Fragmentのバックスタックをクリーンアップする方法はこれで良いのでしょうか?
-
[解決済み] Androidでマイナスマージンを使用するのは悪いことですか?
-
[解決済み] Androidのadb logcatでTAG名で特定のメッセージを除外する方法は?
-
[解決済み] アンドロイドのクライアントでヒープアップデートを有効にする方法
-
[解決済み] AsyncTaskLoaderとAsyncTaskの比較
-
[解決済み] アンドロイドボタンセレクター
-
[解決済み] Recyclerviewと異なるタイプの行のインフレーションの処理