スタッフブログ

STAFF BLOG

アプリ開発日誌

2020.11.06

プログラミング上、何故0.1+0.2=0.3じゃないかを検証してみる

学校で習ってた算数の頭で普通に考えると、0.1+0.2 は絶対に0.3ですよね!

計算機でもそうなるハズ。

でもプログラミングで考えると、ちょっと結果が違ってきます。

Flutterエンジニアになった僕が、この謎について検証してみました。

void main() {

  double x = 0.1;

  double y = 0.2;

  print(x + y == 0.3);

}

結果は false でした (・_・)!!

Stack-overflow で検索したらFlutterのDartだけではなく、プログラミング言語では同様の結果が出てくるはず。

そこで原因を僕なりに探ってみました・・・。

似たような結果を出す計算式は他にもあります。

0.1 + 0.2 = 0.3ですが、コンピュータでは0.30000000000000004と表示され

6 * 0.1 = 0.6ですが、コンピュータでは0.6000000000000001と表示され

0.11 + 0.12 = 0.23ですが、コンピュータでは0.22999999999999998と表示します

実に面白い!

10進数の場合、基数の素因数を使用する分数しか表現できません。

10の素因数は2と5です。

したがって、分母はすべて10の素因数を使用するため、1 / 2、1 / 4、1 / 5、1 / 8、および1/10はすべてきれいに表現できます。

1 / 3、1 / 6、1 / 7、および1/9は、分母が3または7の素因数を使用するため、すべて循環小数です。

2進数の場合では、素因数は2のみであるため、分母が2のみを素因数として持つ分数のみをきれいに表現できます。

2進数では、1 / 2、1 / 4、1 / 8はすべて小数としてきれいに表現され、1/5または1/10は分数を繰り返します。したがって、0.1と0.2(1/10と1/5)は、基数10システムでは小数をクリーンにしますが、コンピュータが使用する基数2システムでは循環小数になってしまう。

これらの繰り返し分数で数学を実行すると、コンピュータの2進数を人間が読める10進数表現に変換するときに持ち越される残り物が発生します。

ここで、0.125のような標準の小数を考えます。これは次のように表すことができます。

1 * 10 ^ -1 + 2 * 10 ^ -2 + 5 * 10 ^ -3。

基本的に、上記の数値を基数10の表記で記述しています。ここで、上記の小数を2進数に変換する場合、最初に数値に2の累乗を掛けて、整数にする必要があります。この場合

0.125 * 8 = 1

これは事実上

0.125 * 2 ^ 3 = 1

ここで、1を実質的に同じバイナリに変換します。

そして私たちが分割するとき

1/2 ^ 3同じ結果が得られます。

ここでの問題は、すべての小数が2進分数として正確に表現できるわけではないということです。

したがって、ほとんどの場合、小数を入力すると、コンピューターに表示されるのはおおよその2進数であり、正確な値ではありません。

ここで、10進数の分数0.1と0.2を2進数の分数に変換すると、無限に繰り返される分数になります。

1/10 = .0001100110011001100110

そして

1/5 = .0011001100110011001100

システムが0.1と0.2を受け入れると、それらを近似のバイナリ形式に、最も近い丸められた値に変換します。この場合、0.1と0.2を加算すると、システムが実行しているのは2つのバイナリ値を加算することです。

.0001100110011001100110 + .0011001100110011001100

ここで、システムが上記の2つのバイナリ値の実際の10進形式を表示するとすると、次のようになります。

0.09999990463256835937 + 0.19999980926513671875

これは正直なところエンドユーザーには意味がないため、プログラミング言語が通常表示するのは、2つを超える数値を四捨五入した値です。したがって事実上

0.1 +0.2 は次のような結果になる、という事になります。

0.30000000000000004

ほとんどの計算機では、それがコンピューティングデバイスであるにもかかわらず、0.1 + 0.2 = 0.3 と人間が勝手に決めた“忖度”が発生しています。

理由は、最後の数ビットを四捨五入することによって、この欠点を回避するために追加の「Guard Digits」を使用する、だからだそうな。

ムムム、難解ですね(笑)。

BACK

お問合せ

イーディーエーに興味をお持ちいただいて
ありがとうございます!
スマホアプリに関するご相談、
お見積りや弊社へのご質問など、
お気軽にお問い合わせください。
担当者より折り返しご連絡させていただきます。

    お名前必須
    会社名
    メールアドレス必須
    電話番号必須
    お問合わせ種別必須
    お問合わせ内容必須

    アンケートにご協力ください。
    弊社サイトへはどのようにしてアクセスされましたか?

    個人情報のお取扱いに関する同意事項

    1.事業者の氏名又は名称

    株式会社イーディーエー

    2.個人情報保護管理者の氏名又は職名、所属及び連絡先

    個人情報保護管理者 小宮 保人
    Mail:[email protected]

    3.取得した個人情報の利用目的

    当フォームで取得した個人情報は、お問い合わせに関する回答のために利用し、目的外利用はいたしません。

    4.弊社が取得した個人情報の第三者への委託、提供について

    弊社は、ご本人に関する情報をご本人の同意なしに第三者に委託または提供することはありません。

    5.個人情報保護のための安全管理

    弊社は、ご本人の個人情報を保護するための規程類を定め、従業者全員に周知・徹底と啓発・教育を図るとともに、その遵守状況の監査を定期的に実施いたします。
    また、ご本人の個人情報を保護するために必要な安全管理措置の維持・向上に努めてまいります。

    6.個人情報の開示・訂正・利用停止等の手続

    ご本人が、弊社が保有するご自身の個人情報の、利用目的の通知、開示、内容の訂正、追加又は削除、利用の停止、消去及び第三者への提供の停止を求める場合には、下記に連絡を頂くことで、対応致します。

    株式会社イーディーエー 個人情報お問合せ窓口
    〒106-0032 東京都港区六本木7丁目14番23 ラウンドクロス六本木4F
    TEL:03-5422-7524 FAX:03-5422-7534
    Mail:[email protected]

    7.ご提供いただく情報の任意性

    個人情報のご提供は任意ですが、同意を頂けない場合には、第3項にあります利用目的が達成できない事をご了承いただくこととなります。

    8.弊社Webサイトの運営について

    弊社サイトでは、ご本人が弊社Webサイトを再度訪問されたときなどに、より便利に閲覧して頂けるよう「クッキー(Cookie)」という技術を使用することがあります。これは、ご本人のコンピュータが弊社Webサイトのどのページに訪れたかを記録しますが、ご本人が弊社Webサイトにおいてご自身の個人情報を入力されない限りご本人ご自身を特定、識別することはできません。
    クッキーの使用を希望されない場合は、ご本人のブラウザの設定を変更することにより、クッキーの使用を拒否することができます。その場合、一部または全部のサービスがご利用できなくなることがあります。