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

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

新規登録して質問してみよう
ただいま回答率
85.35%
bash

bash(Bourne-again-Shell)は sh(Bourne Shell)のインプリメンテーションに様々な機能が追加されたシェルです。LinuxやMac OS XではBashはデフォルトで導入されています。

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

3回答

5294閲覧

言語別?計算誤差に関して

退会済みユーザー

退会済みユーザー

総合スコア0

bash

bash(Bourne-again-Shell)は sh(Bourne Shell)のインプリメンテーションに様々な機能が追加されたシェルです。LinuxやMac OS XではBashはデフォルトで導入されています。

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

1グッド

0クリップ

投稿2016/06/11 12:53

言語別の計算誤差に関して、興味が出たのでご教示下さい。

もともとは、別の質問の回答で、小数点以下の誤差が気になり、少し検証してみました。

別の質問

簡単に言うと、ruby で (33.1 + 34.2) / 2 を計算すると誤差がでるということです。

ruby

1$ irb 2irb(main):001:0> (33.1 + 34.2) / 2 3=> 33.650000000000006

自前の環境で簡単に確認できるモノで試してみました。

bash

1echo "scale=20; (33.1 + 34.2) / 2 " |bc 233.65000000000000000000

php

1php -r "echo ((33.1 + 34.2) / 2);" 233.65

win7標準の電卓アプリ
(33.1 + 34.2) / 2 = 33.65

言語によって、誤差が出るものなのでしょうか?

と質問しようと思って、少し続けて検証してみたところ

php

1php -r "echo number_format((33.1 + 34.2) / 2,20,null,'');" 233.65000000000000568434

javascript

1console.log(((33.1 + 34.2) / 2)); 233.650000000000006

と出ました^^;

各言語の計算で、標準で使う変数の型が違うということなんですかね?
詳しい方、コメントいただければ幸いです。

kei344👍を押しています

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

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

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

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

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

guest

回答3

0

ほとんどの言語において「浮動小数点数」がどのような形式なのかは処理系依存です。ですが、ほぼ全ての環境において、IEEE 754のbinary64(倍精度)が使われます。C言語のdoubleがこれに相当します。多くの実装系がC言語に依存しており、実際の計算はC言語におけるdouble、つまり、IEEE 754 binary64を使用していると考えて問題ありません。
※ C言語のdoubleがIEEE 754 binary64であると仕様で決められているわけではありません。しかし、ほとんどのCPUの浮動小数点数についての各命令がIEEE 754に基づいているため、それ以外の形式が使われる処理系を私は知りません。
※ C言語のfloatのように言語によってはbinary32(単精度)も用意されています。また、追加のライブラリ等で十進や拡張倍精度等の他のIEEE 754が別途用意されている場合もあります。
※ Javaなど一部の言語ではIEEE 754 binary64であることが仕様として定められている場合があります。

さて、このbaniray64ですが、内部表現がニ進数表記です。どういう意味かというとニ進数の小数点数は正確に表せますが、十進数は一部の数字を除いて正確に表現できません。たとえば0.50b0.1になりますが、0.10b0.000110011001100...と循環小数になっており、有限のビットでは表現不可能です。
※ 0bをつけている場合はニ進数表記であることを表します。

つまり、33.1は正確は十進数の33.1という数字では決して無く、実際は"33.10000000000000142108547152..."という33.1の近似値になります。そう、33.1というリテラルは33.1ではありません。33.1に近い別の何かです。ニ進数で循環小数にならない一部を除き、十進数の小数点数は誤差が常につきまいといます。

では、計算結果でなぜ誤差の分が出るときと出ないと時があるかというと、浮動小数点数はどこまでが正しいのかを記録しないからです。33.1は33.10まで正しいのか33.1000まで正しいのかがわかりません。他の数を足したりした場合の結果も、どの精度まで正しいのかわかりません。そのため、通常、浮動小数点数を出力するときは、精度を指定(printfで"%.2f"などにする等)するか、デフォルトでどこまでの精度を表示するかが決まっています。足し算や掛け算によって誤差は大きくなり、信頼できる精度は小さくなりますので、デフォルトで表現する精度(どこまで出すかは言語による)をこえたときに端数のような数字が現れます。
※ 十進数->ニ進数、ニ進数->十進数で丸め処理が行われます。丸め方は実装依存です。処理系により異なる可能性があります。
※ 質問のPHPの例は単にデフォルトで表示する精度がRubyよりも少ないため、表示が異なるだけかと思います。精度を合わせれば同じ結果になるでしょう。

ここまではC言語およびC言語のdoubleをそのまま使うような言語(Python、Ruby、JavaScriptなど)の話です。この動作はCPUへの命令をそのまま使うため高速であり、C言語での演算と同じ結果が得られるという利点があります。そもそもの測定値に誤差があるような通常の演算において、精度は後から決めれば良いため、この方法でも問題がありません。しかしそうはいかない場合があります。

精度を保持したまま十進数で計算したい場合があります。電卓のような計算がまさしくそれです。そのような場合に備えて、任意精度の十進数浮動小数点数が用意されています。Rubyのbigdecimalが良い例でしょう。C言語のdoubleとは違い、精度自体が記憶されており、その精度において正確な計算ができるようになっています。また、内部表現が十進数のため、33.1を正確に33.1とすることができます。bcコマンドはこの方式を使っています。ですので、bashでbcコマンドを使った場合は十進数が正確に計算できます。また、高機能な電卓の実装でもこの方式を採用している場合が多いです。(Windowsの電卓も任意精度のようです。参考: SO(ja) | windowsの電卓の内部変数の型について)

もう一つ正確な計算方法があります。それは有理数を使う方法です。Perl6はデフォルトが有理数になっていますし、Rubyであればrをつけることで簡単に有理数にできます。Rubyで((33.1r + 34.2r) / 2).to_f.to_sは"33.65"となるはずです。計算はかなり遅いですが、四則演算であれば精度が落ちる事はありません。(平方根など無理数になる場合は浮動小数点数になってしまい、精度が落ちる場合があります)

投稿2016/06/11 18:25

raccy

総合スコア21739

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

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

退会済みユーザー

退会済みユーザー

2016/06/11 21:02

今まで有効桁数を気にしなければいけないような計算をしなかったので、調べる機会がなかったのですが、全く知らないままだと、ハマりそうな箇所ですね。 33.1の例は非常に分かりやすかったです。 今回の質問の回答は【そのため、通常、浮動小数点数を出力するときは、精度を指定(printfで"%.2f"などにする等)するか、デフォルトでどこまでの精度を表示するかが決まっています。】ですね。これを知らないがゆえの質問でした。 質問して良かったです。ありがとうございました。
guest

0

ベストアンサー

各言語の計算で、標準で使う変数の型が違うということなんですかね?

基本的には同じだと思います。「IEEE 754」という浮動小数点に関する標準規格がありまして、ほとんどの処理系(CPUやFPU)はその規格に準拠しています。そうなると、そのCPU上で動くプログラミング言語もその規格に合わせるのが自然です。C#やJavaなど、言語によっては仕様として明確にIEEE 754準拠としているものもあります。

では、同じ結果のはずなのに表示結果が異なるのはどういうことかというと、「表示のさせ方が違う」のです。

多くの場合、実数の計算に64bit浮動小数点を使っていますが、10進表記における有効桁数は15桁です。ご質問の中で誤差が出ている表示は、どれも15桁を超えています。そうすると、超えた部分を無理矢理表示しようとして誤差も含めて表示されてしまうのです。

win7標準の電卓アプリ

これは特殊です。アプリケーションの仕様として、内部的には確か128bitで計算しています。そのため64bitよりも有効桁数が多いです。

投稿2016/06/11 13:25

編集2016/06/11 13:34
catsforepaw

総合スコア5944

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

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

退会済みユーザー

退会済みユーザー

2016/06/11 13:43

「IEEE 754」なんてあったんですね。知りませんでした。 学習のキーとなりました。ありがとうございます。 丸め誤差の最大に関しても、理解できる説明を見つけることが出来ました。 ありがとうございます。
guest

0

循環小数という言葉を聞いたことがありますか?

例えば、10進数浮動小数点数で、1/3を表そうとすると、0.33333.... と3を永遠に続けるしか1/3を表現することはできません。(このように、小数点以下の数字が一定のパターン(1/3の例では3が繰り返される)で永遠に続くのを循環小数と言います)

残念ながら、計算機には無限の桁数を表現できるだけのメモリがありませんから、循環小数点数は、どこかの桁以下を近似する(切り捨てる、切り捨てする桁の値で四捨五入する等の処理をする)事で計算機のメモリに数値を保持しています。どこかの桁以下を近似しているので、計算機の中の値は近似値にしかなりません。

このように計算機が数値の表現に使えるデータ(桁数)に限りかあることから、数値を近似せざるを得ず、その近似と正しい値との違いを「近似誤差」「丸めのJ誤差」などと呼びます。

丸目の誤差は、1つの浮動小数点数を2ビットで表現する計算機システムと、64ビットで表現する計算機システムでは異なります。

質問の中で、値が一致しない理由は、この丸目の誤差にあります。

投稿2016/06/11 13:12

coco_bauer

総合スコア6915

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

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

退会済みユーザー

退会済みユーザー

2016/06/11 13:21

今回の誤差の差は、2ビットで表現する計算機システムと、64ビットで表現する計算機システムの差ということでしょうか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問