私はsize_t s=(size_t)floorf(f);
のようなものを計算する必要がある状況にあります。つまり、引数は浮動小数点ですが、整数値(floorf(f)
は正確に表現するのに十分小さいと仮定します)を持ちます。これを最適化しながら、面白いことを発見しました。`uint64_t`はなぜ難しいですか? (変換アセンブリを `float`から)
float
から整数(GCC 5.2.0 -O3)への変換があります。わかりやすくするために、与えられた変換はテスト関数の戻り値です。
はここint32_t x=(int32_t)f
です:
cvttss2si eax, xmm0
ret
はここuint32_t x=(uint32_t)f
です:
cvttss2si rax, xmm0
ret
ここint64_t x=(int64_t)f
です:
cvttss2si rax, xmm0
ret
最終、ここuint64_t x=(uint64_t)f;
です:
ucomiss xmm0, DWORD PTR .LC2[rip]
jnb .L4
cvttss2si rax, xmm0
ret
.L4:
subss xmm0, DWORD PTR .LC2[rip]
movabs rdx, -9223372036854775808
cvttss2si rax, xmm0
xor rax, rdx
ret
.LC2:
.long 1593835520
この最後のものは他のものよりずっと複雑です。さらに、ClangとMSVCも同様に動作します。あなたの便宜のために、私は擬似C言語に翻訳しました:
float lc2 = (float)(/* 2^63 - 1 */);
if (f<lc2) {
return (uint64_t)f;
} else {
f -= lc2;
uint64_t temp = (uint64_t)f;
temp ^= /* 2^63 */; //Toggle highest bit
return temp;
}
これは、最初のオーバーフローモード64を正しく計算しようとしているようです。ちなみに、私は、the documentation for cvttss2siは、オーバーフローが発生した場合(2^32ではなく2^64)、「不定の整数値(80000000H)が返されます。
私の質問:
- これは本当に何をしている、となぜか?
- 他の整数型でも同様のことが行われなかったのはなぜですか?
- 同様のコード(出力行3と4のみ)を生成するように変換を変更するにはどうしたらいいですか(値は正確に表現可能であるとします)?
cvttss2si
以来
このブログの投稿とこのコメントは、あなたの質問に関連しています:http://blog.frama-c.com/index.php?post/2013/10/09/Overflow-float-integer#c379 –