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

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

ただいまの
回答率

90.45%

  • C

    4677questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

  • C++

    4544questions

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

floor,ceil関数と整数の等価比較について

解決済

回答 3

投稿

  • 評価
  • クリップ 1
  • VIEW 1,919

Eki

score 382

よくdouble同士の==による比較は危険だと言われます。実際,二進数で表せないような小数はどうしても切り捨てによる誤差が生まれる,ということは分かります。

そこに小数を(double型の)整数で返すようなfloorceilといった関数があります。整数はdouble型で確かにきっかり表せると思いますが,僅かにゴミの残ったほとんど整数,のような値が返ることはないのでしょうか。そうだとすると,このような関数が返すような整数値は==で比較してもよいのでしょうか。(ただし,関数に渡す値にINFやNaNや非正規化数などの変な入力はないとします。)

一応,例えば次のようなプログラムを書いてみて,自分の環境ではこれが1を表示したはしたのですが

double x = floor(2.1);
std::cout << (x == 2.) << std::endl;

自分の環境では次のプログラムも同様に1を表示するので,誤差が現れていないだけなのか,存在しないのか,2.1という数字が都合良かっただけなのか,自分には分かりません・・・。

double x = 0.5;
double y = 0;
for (int i = 0; i < 5; i++) {
    y += 0.1;
}
std::cout << (x == y) << std::endl;

お力をお貸しください。

 環境

$ clang++ --version
clang version 4.0.0 (tags/RELEASE_400/final)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+3

こんにちは。

例えば、floor関数で想定外の切り捨てが発生しないのであれば、切り捨て後の比較で問題はでません。

しかし、切り捨てはなかなか怖くて、0.9999999999999999999999は0になります。
実は誤差のない計算であれば1.0になるような場合でもです。

切り捨て時、切り上げ時にこのようなケースがあっても問題にならないケースであれば大丈夫な筈です。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/07/02 00:55

    回答ありがとうございます。
    確かに落とし穴になりそうですね。
    ただ,この場合でも切り捨て後の整数は厳密に0と一致するということですね。

    少しだけ反れますが,一般に2進小数で表せるような数だけを経由した四則演算の結果(で非正規化数とか変な数にもならない場合)は誤差が入りようがないと思うのですが,厳密に==で比較できますか。

    キャンセル

  • 2017/07/02 01:30

    (10進数から内部表現への変換と==も含む)全ての計算過程で丸めも桁落ちも発生しなかったら==で厳密に比較できると思います。

    キャンセル

  • 2017/07/06 22:51

    ありがとうございます,納得しました。

    キャンセル

+1

C99およびC11の規格において、floor()ceil()は整数値が返ると規定されているので、問題ありません。(NaNとINFを除く)

7.12.9.1 The ceil functions
The ceil functions compute the smallest integer value not less than x.

7.12.9.2 The floor functions
The floor functions compute the largest integer value not greater than x.

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/07/06 22:50

    回答ありがとうございます。遅くなり申し訳ありません。
    なるほど,ありがとうございます。規格はやはり安心感が違いますね。

    キャンセル

0

通常は浮動小数点の表現は仮数部と指数部から成ります。 このとき指数部が 0 であれば実質的に整数であり、誤差のない比較が可能です。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/07/02 00:38

    「仮数部の小数点以下の桁が0」というべきではないでしょうか?

    キャンセル

  • 2017/07/02 00:47

    回答ありがとうございます。浮動小数点数で指数部が0になるとき,つまり普通に整数を代入するようなときは,誤差のない比較ができるということですね。
    floor関数やceil関数がどのように実装されているかを私は知らないのですが,もし何らかの計算で求めているとしても,その計算の過程で微妙なゴミが残るようなことはない,ということでよいのでしょうか。

    キャンセル

  • 2017/07/02 20:06

    ただし規格上の保証はないはず(IEEE754ではない環境ふくめ大丈夫だと思いますが)

    キャンセル

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

  • ただいまの回答率 90.45%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • C

    4677questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

  • C++

    4544questions

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