前提
コンパイラ(?)を変えると、割り算の結果が変わって困ります。
実現したいこと
コード上の計算で、int型の10を得たいです。floatの結果は10になっているのに、int型に式を入れるとなぜかg++の方だけ結果が9になります。paiza.io/ja/projects/newの方で試してみると全て結果が10となります。
どちらも、一旦float変数に代入してからキャストすると10が得られます。わざわざfloatの変数を経由するのが気に食わないので、g++で直接int型に10が入るようにしたいです。
発生している問題
//--g++の結果 10 9 10 //--paiza.io/ja/projects/newの結果 10 10 10
該当のソースコード
C++
1#include <iostream> 2using namespace std; 3int main(){ 4 float a = -1; 5 float b = 1; 6 float d = 0.2; 7 float float_res = (b-a)/d; 8 int int_res = (b-a)/d; 9 int int_res2 = (int)float_res; 10 cout << float_res << endl; 11 cout << int_res << endl; 12 cout << int_res2 << endl; 13 return 0; 14}
補足情報(FW/ツールのバージョンなど)
gcc version 9.2.0 (MinGW.org GCC Build-2)
paiza.io/ja/projects/new
float/double の演算には誤差がつきもの。
2.0/0.2 がぴったり 10.0 になることを期待してはいけない。
10進数の0.2は2進数では綺麗に表現できませんからね。
でもこのままではmingwだけ結果が違うのが可哀想なので新しめなもので実験してみました。
$ cat hoge.sh
cat >hoge.cpp <<EOF
#include <iostream>
int main(void){
std::cout << __VERSION__ << std::endl;
float a = -1.f, b = 1.f, d = .2f;
std::cout << static_cast<int>((a - b) / d) << std::endl;
return 0;
}
EOF
g++ --version
g++ -g -Wall -pedantic hoge.cpp -o hoge
./hoge
ldd hoge
$ sh hoge.sh
g++.exe (Rev6, Built by MSYS2 project) 12.2.0
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12.2.0
-10
ntdll.dll => /c/WINDOWS/SYSTEM32/ntdll.dll (0x7ffca8df0000)
KERNEL32.DLL => /c/WINDOWS/System32/KERNEL32.DLL (0x7ffca7bb0000)
KERNELBASE.dll => /c/WINDOWS/System32/KERNELBASE.dll (0x7ffca6960000)
msvcrt.dll => /c/WINDOWS/System32/msvcrt.dll (0x7ffca87f0000)
libstdc++-6.dll => /mingw64/bin/libstdc++-6.dll (0x7ffc1fca0000)
libgcc_s_seh-1.dll => /mingw64/bin/libgcc_s_seh-1.dll (0x7ffc907c0000)
libwinpthread-1.dll => /mingw64/bin/libwinpthread-1.dll (0x7ffc94030000)
$
一応他のと変わらないようです。hoge.cppをpaiza.ioで実行した結果は
Clang 10.0.0
-10
でした。↓ではいろいろなコンパイラの結果を試せます。
https://godbolt.org/z/Y93sojKK5
例えば fesetround で rounding mode を FE_TOWARDZERO に変更すれば、以下の様な結果になります。
https://wandbox.org/permlink/WbjJfJtk3ZkJIdcG
しかし、implicit conversion だけ異なるというのは不可解ではありますが。。。まぁ、標準のデフォルト値である FE_TONEAREST を指定してみて結果が変わるかどうかを確認してみるのもよいかもしれません。
暗黙的変換だけだったとは…
元のコードに直してmingwで実行し直しました
$ cat hoge.sh
cat >hoge.cpp <<EOF
#include <iostream>
int main(void){
std::cout << __VERSION__ << std::endl;
using namespace std;
float a = -1;
float b = 1;
float d = 0.2;
float float_res = (b-a)/d;
int int_res = (b-a)/d;
int int_res2 = (int)float_res;
cout << float_res << endl;
cout << int_res << endl;
cout << int_res2 << endl;
return 0;
}
EOF
g++ --version
g++ -g -Wall -pedantic hoge.cpp -o hoge
./hoge
ldd hoge
$ sh hoge.sh
g++.exe (Rev6, Built by MSYS2 project) 12.2.0
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12.2.0
10
10
10
ntdll.dll => /c/WINDOWS/SYSTEM32/ntdll.dll (0x7ffca8df0000)
KERNEL32.DLL => /c/WINDOWS/System32/KERNEL32.DLL (0x7ffca7bb0000)
KERNELBASE.dll => /c/WINDOWS/System32/KERNELBASE.dll (0x7ffca6960000)
msvcrt.dll => /c/WINDOWS/System32/msvcrt.dll (0x7ffca87f0000)
libstdc++-6.dll => /mingw64/bin/libstdc++-6.dll (0x7ffc51c40000)
libwinpthread-1.dll => /mingw64/bin/libwinpthread-1.dll (0x7ffc83360000)
libgcc_s_seh-1.dll => /mingw64/bin/libgcc_s_seh-1.dll (0x7ffc85240000)
$
結果は変わらずのようでした。
参考になりました
ありがとうございました
回答2件