ログイン新規登録

Qiitaにログインして、便利な機能を使ってみませんか?

あなたにマッチした記事をお届けします

便利な情報をあとから読み返せます

34
23

面接官「0.1 + 0.2 == 0.3 が成立しない理由を説明せよ」

最終更新日 投稿日 2024年05月23日

面接官「0.1 + 0.2 == 0.3 が成立しない理由を説明せよ」

という質問がきたらどう答えるだろうか。

0.3にはならない

Javascript

適当なブラウザから以下のようなJavascript実行した。結果「0.1+0.2==0.3」は「false」となった。

0.1+0.2==0.3
//false
0.1+0.2===0.3
//false

image.png

ちなみに以下のような先頭に0をつけなくても、小数点として解釈される。

.1+.2==.3
//false

Python

バージョン3.10.11で検証する。同様に「0.1+0.2==0.3」は「false」となった。

>>> 0.1+0.2==0.3
False

なぜか

これは、機械語が2進数へ変換される際に、浮動小数点数の誤差が発生するためです。小数点以下の数値は多くの場合、無限小数となります。

小数点以下の数値→2進数へ変換する方法

CSを修めていればご存知方と思いますが、復習します。

  1. 小数点以下の数値を2倍する
  2. 結果の整数部分を取り出し、それを2進数の桁として記録する
  3. 小数部分だけを次のステップに持ち越す
  4. 小数部分が0になるか、所定の精度に達するまで1〜3を繰り返す

0.1 × 2 = 0.2
整数部分: 0
小数部分: 0.2

0.2 × 2 = 0.4
整数部分: 0
小数部分: 0.4

0.4 × 2 = 0.8
整数部分: 0
小数部分: 0.8

0.8 × 2 = 1.6
整数部分: 1
小数部分: 0.6

(以下省略)

最終的に0.1は0.0001100110011001100110011....となる。

まとめ

この問題の本質は、コンピュータが浮動小数点数を扱う際の誤差にあります。浮動小数点数の精度と表現方法を理解しておくことが重要です。

(追記)
言語仕様によるよ!
どういった仕様で実装されているか本質的な部分にも関心向ける機会ってあんまりなですよね。

34
23
9

新規登録して、もっと便利にQiitaを使ってみよう

  1. あなたにマッチした記事をお届けします
  2. 便利な情報をあとで効率的に読み返せます
  3. ダークテーマを利用できます
ログインすると使える機能について
mlab

@mlab

この記事は以下の記事からリンクされています

コメント

juner
@juner(jun maeda)

double だとそうですが、float だと誤差が収まってしまう為 true になるんですよね

具体例
using System;
{
    const double v = 0.2d + 0.1d;
    Console.WriteLine($"const {v.GetType()} {v == 0.3d}");
}
{
    var v1 = 0.2d;
    var v2 = 0.1d;
    var v3 = 0.3d;
    Console.WriteLine($"var {v1.GetType()} {(v1 + v2) == v3}");
}
{
    const float v = 0.2f + 0.1f;
    Console.WriteLine($"const {v.GetType()} {v == 0.3f}");
}
{
    var v1 = 0.2f;
    var v2 = 0.1f;
    var v3 = 0.3f;
    Console.WriteLine($"var {v1.GetType()} {(v1 + v2) == v3}");
}
{
    const decimal v = 0.2m + 0.1m;
    Console.WriteLine($"const {v.GetType()} {v == 0.3m}");
}
{
    var v1 = 0.2m;
    var v2 = 0.1m;
    var v3 = 0.3m;
    Console.WriteLine($"var {v1.GetType()} {(v1 + v2) == v3}");
}
output
const System.Double False
var System.Double False
const System.Single True
var System.Single True
const System.Decimal True
var System.Decimal True

playground

※ const と var 両方でやっているのは const は コンパイル段階で計算してしまう為比較用

2
mlab
@mlab

@juner 動的言語は人類には過ぎた技術だったようです。

1
juner
@juner(jun maeda)
(編集済み)

@mlab 動的言語だからというよりも IEEE 754 の倍精度 64ビットバイナリー形式 (CやC#でいう double) だからですね。

JavaScript の数値 (Number) 型は IEEE 754 の倍精度 64ビットバイナリー形式であり、 Java や C# の double のようなものです。

数値型には 3 種類あります: 整数 、 浮動小数点数 、 複素数 です。さらに、ブール型は整数のサブタイプです。整数には精度の制限がありません。浮動小数点型はたいていは C の double を使って実装されています

32ビット浮動小数点(CやC# でいう float) も 今回のケースでは運がよかっただけです。

4
fujitanozomu
@fujitanozomu(藤田 望)
(編集済み)

面接官「0.1 + 0.2 == 0.3 が成立しない理由を説明せよ」

という質問がきたらどう答えるだろうか。

「0.1 + 0.2 == 0.3 が成立しないかは言語にもよる話ですがこの質問は前提条件が足りないと思います」

Go
package main

import (
    "fmt"
)

func main() {
    fmt.Println(0.1 + 0.2 == 0.3)
}
実行結果
true

0
mlab
@mlab

@fujitanozomu

「0.1 + 0.2 == 0.3 が成立しないかは言語にもよる話ですがこの質問は前提条件が足りないと思います」

成立しない前提で、何を問われているか理解するの難しいですよね。わかります。

1
fujitanozomu
@fujitanozomu(藤田 望)
(編集済み)

@mlabさん、

0.1 + 0.2 == 0.3 が成立しないかは言語にもよる話なので「実行する言語を間違えた」という回答は自分的にはアリだと思います。

Raku
if (0.1 + 0.2 == 0.3) {
    print "0.1 + 0.2 == 0.3";
} else {
    print "0.1 + 0.2 != 0.3";
}
実行結果
0.1 + 0.2 == 0.3

bc
if (0.1 + 0.2 == 0.3) {
    print "0.1 + 0.2 == 0.3";
} else {
    print "0.1 + 0.2 != 0.3";
}
実行結果
0.1 + 0.2 == 0.3

Groovy
if (0.1 + 0.2 == 0.3) {
    print "0.1 + 0.2 == 0.3";
} else {
    print "0.1 + 0.2 != 0.3";
}
実行結果
0.1 + 0.2 == 0.3

Perl
if (0.1 + 0.2 == 0.3) {
    print "0.1 + 0.2 == 0.3";
} else {
    print "0.1 + 0.2 != 0.3";
}
実行結果
0.1 + 0.2 != 0.3

あるいは「使用したコンピュータのソフトかハードに異常があった」という回答も可能でしょう。
このような回答は、0.1 + 0.2 == 0.3 が成立しない前提でこの質問を出してる面接官的にはどうなのだろうかと思いました。

0
ymsk_CM
@ymsk_CM(t yamasaki)

「(JavaScript なら)実行可能なので成立します!」

1
TomoDote
@TomoDote

そもそも浮動小数を等号で比較するのはよくありません。例えば、pythonであれば、math.isclose() を使って比較しましょう。また、roundなどで丸めてから比較するのもよいでしょう。
浮動小数ではなく、分数で表現するなどの工夫が必要かもしれません。

0
fujitanozomu
@fujitanozomu(藤田 望)

@mlabさん、

なぜか

これは、機械語が2進数へ変換される際に、

機械語は関係ないですね。

浮動小数点数の誤差が発生するためです。小数点以下の数値は多くの場合、無限小数となります。

IEEE 754のbinary640.1等が正確に表せられないことは「0.1 + 0.2 == 0.3が成立しない」理由のひとつではありますが、0.1 + 0.1 == 0.20.1 + 0.3 == 0.4が成立する例を見ると0.1 + 0.2 == 0.3が成立しないことの理由はもう少し踏み込んだ説明が必要と言えますね。

1

いいね以上の気持ちはコメントで

記事投稿キャンペーン開催中

アクセシビリティの知見を発信しよう!

~
詳細を見る
34
23

ログインして続ける

ソーシャルアカウントでログイン・新規登録

メールアドレスでログイン・新規登録