質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

2回答

1295閲覧

コンパイラ(?)で演算結果が変わる

Suisoniumu

総合スコア14

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

2クリップ

投稿2023/01/09 13:05

前提

コンパイラ(?)を変えると、割り算の結果が変わって困ります。

実現したいこと

コード上の計算で、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

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

episteme

2023/01/09 13:46

float/double の演算には誤差がつきもの。 2.0/0.2 がぴったり 10.0 になることを期待してはいけない。
dameo

2023/01/09 16:15

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
melian

2023/01/09 19:46

例えば fesetround で rounding mode を FE_TOWARDZERO に変更すれば、以下の様な結果になります。 https://wandbox.org/permlink/WbjJfJtk3ZkJIdcG しかし、implicit conversion だけ異なるというのは不可解ではありますが。。。まぁ、標準のデフォルト値である FE_TONEAREST を指定してみて結果が変わるかどうかを確認してみるのもよいかもしれません。
dameo

2023/01/10 00:46 編集

暗黙的変換だけだったとは… 元のコードに直して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) $ 結果は変わらずのようでした。
Suisoniumu

2023/01/10 08:17

参考になりました ありがとうございました
guest

回答2

0

ベストアンサー

言語仕様上、定義されきっていない箇所においてはコンパイラごとに異なる結果になりえます。

これは小数型に限ったことではありません。

小数計算での誤差は当然です。

0.2は2進数化すると有限桁で収まらないです。つまり、必ず誤差が発生します。計算過程で整数になると期待するのは、無理があります。小数計算で統一しましょう。

投稿2023/01/09 14:28

HogeAnimalLover

総合スコア4830

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

どちらも、一旦float変数に代入してからキャストすると10が得られます。わざわざfloatの変数を経由するのが気に食わないので、g++で直接int型に10が入るようにしたいです。

浮動小数点の演算はdoubleでなされます(で、コンパイラのバージョンにより、もっと他の精度で計算されたりなんかします)
floatでキャストすると結果が変わるのはそのせいですね

で、演算の結果ってのは、あなたの個人的な都合によって変わるもんじゃありません

投稿2023/01/09 22:50

編集2023/01/09 22:51
y_waiwai

総合スコア87784

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問