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

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

新規登録して質問してみよう
ただいま回答率
85.48%
コンパイラ

コンパイラは、プログラミング言語で記述したソースコードを、コンピュータの実行形式であるオブジェクトコードに変換するプログラムです。

データ構造

データ構造とは、データの集まりをコンピュータの中で効果的に扱うために、一定の形式に系統立てて格納する形式を指します。(配列/連想配列/木構造など)

Q&A

7回答

3345閲覧

浮動小数点数の誤差

mightyMask

総合スコア143

コンパイラ

コンパイラは、プログラミング言語で記述したソースコードを、コンピュータの実行形式であるオブジェクトコードに変換するプログラムです。

データ構造

データ構造とは、データの集まりをコンピュータの中で効果的に扱うために、一定の形式に系統立てて格納する形式を指します。(配列/連想配列/木構造など)

1グッド

4クリップ

投稿2017/04/29 18:55

浮動小数点数で桁数の大きな数を扱うと誤差が出てしまいますね。
これは仕方の無い事です。

私はプログラミング初学者のため、いろいろ解説サイトを見て回る訳ですが、この誤差に対する問題に対処するのが相当難しいように説明されています。
銀行などでは誤差を小さくするために、~~の様な仕組みを使っているといった様な解説も見かけました。
以下の様なデータ構造なら、多少の誤差で大問題になりかねない場合、処理速度より精度を優先させたい場合、誤差を気にせずプログラムを書きたい場合等には有用なデータ構造だと思うのですが、なぜこの様に実装する例が無いのでしょうか。

#誤差の出ないデータ構造
・有理数クラス
実数クラスを継承しています。
浮動小数点型は使用せず、分子(整数)と分母(自然数)の2つのメンバを持つクラスです。

・実数クラス
無理数を扱いたい場合は、内部では人間が計算するときと同じように、円周率などは3.14...という定数ではなくπという状態を保持し、∛4 なども有理数に変換させず、そのままの形で保持しておきます。

累乗根, 円周率, ネイピア数 等 以外の、人間にも解釈できないような無理数を扱うことは不可能ですが、それが原因で問題が起きる事はないような気がします。
少なくとも有理数に関しては、誤差が出ない事を保証できると思います。

marimom7👍を押しています

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

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

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

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

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

guest

回答7

0

例は多くはないのですが、質問者さんがおっしゃるようなシステムは存在します。

・有理数クラス

比較的、我々に身近なものは計算機言語ということになりますが、有理数を標準で扱うことのできる言語の一つとしてCommon Lispがあります。質問者さんがおっしゃるとおりの方法、分母と分子を任意精度整数(※)で表現することにより厳密な有理数を表現しています。

(※:もちろん任意精度整数は無限精度ではありません。満足できる程度の「巨大な有限」を任意精度と表現しています。)

・円周率をπで、・・・
・累乗根, 円周率, ネイピア数 等...

初等関数などを誤差付きの浮動小数点数で計算してしまわず、その意味を保存したまま代数的な演算を行えるというイメージを持たれたのだと思います。そうした計算を目的とした数式処理システムが存在します。例えばMathematicaなどの例があります。

なぜこの様に実装する例が無いのでしょうか。

前述のように実際に存在しているのですが、計算機を用いる応用としてポピュラーとは言えません。そこには理由があり、計算機での計算は数式を厳密に扱うことが主要な目的ではなく、現実の問題を解決することが主要な目的だからと言えると思います。任意の計算問題は厳密さと計算速度や計算機リソースとのバランスにより方法論の優劣が検討されます。

銀行の利率計算に有理数を用いて厳密解を出したとしても円(銭?)未満の厳密さは現実には必要性は低いと考えられるでしょう。またロケットを発射する際の軌道計算をいくら厳密にしても装置の機構・加工精度や気象などの不確定要因などを全て厳密に計算に盛り込むのは不可能ですね。あるいは人間の感覚で識別できる程度の精度を狙って、音声波形を16bit程度に離散化して沢山の楽曲をコンパクトな携帯機器に記録したり、映像の画素単位を24bit程度の数値で扱い特定の電波帯域で多数のチャンネルで配送したりといった具合に、データ量を小さくすることを主眼に考えられている場面も多いです。

多くの応用で計算が一定の誤差を許容した前提で行われるのはこうした背景があるからと言えるでしょう。

投稿2017/04/29 23:11

編集2017/04/29 23:43
KSwordOfHaste

総合スコア18394

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

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

0

有理数型または有理数クラスは多くの言語で標準またはライブラリとして既にあります。

####組み込み

####標準ライブラリ

####外部ライブラリ


なお、有理数の処理は、途中で無理数になるような計算が無い限り、誤差は全くありませんが、Zuishinさんが言う通りかなり重い処理です。また、doubleでの誤差が問題になるような約数が大きな数の処理では多倍長整数を扱えないとオーバーフローしてしまうので意味がありません。Scheme、Ruby、Haskell、Pythonはそもそも多倍長整数があります。boostのrationalはboostのmultiprecisionと一緒に使うべきでしょう。

また、十進数表記での誤差の範囲がわかっている場合は任意精度浮動小数点数(Rubyのbigdecimal、Pythonのdecimal、C++のMultiprecision - boost等)を使った方が良い場合があります。

投稿2017/04/29 22:57

raccy

総合スコア21735

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

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

0

多少の誤差で大問題になりかねない場合

と言うもの自体が、そうそう存在しないのではないかと考えています。

たとえば、機械設計では必要な強度に対して安全率を見て設計しますし、計算を丸める場合も「より安全な方」へ丸めるようにするだけで、実用上の問題は発生しません。それに、実際の機械加工の精度にも限界があります。

銀行などの通貨計算の場合、通貨には最低単位が決まっていますので、それより下の位については、結局丸めるしかありません。少し下の位で固定小数点数として計算すれば無視できます。

また、整数に関しては多倍長整数の技術は比較的安定して存在しますので、メモリや実行時間が許す限り問題なく計算できます。

結局問題になりそうなのは、「円周率を○桁求める」とか「無理数の性質を吟味するために、細かい桁まできっちり出す」というような、ごく特殊な状況しかないのではないかと考えています。

投稿2017/04/30 00:22

maisumakun

総合スコア145184

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

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

0

数式をあつかうことができるシステムもあります。

参考情報

  • 数式処理システムとしてのプログラミング言語Egisonの紹介

https://codeiq.jp/magazine/2016/11/46444/

  • オープンソースの数式処理システムMaxima

http://ritsuan.com/blog/5398/

  • Sympy+Jupyterで最強の電卓環境を作る

http://qiita.com/pashango2/items/500d23c8f43784b54315

投稿2017/04/29 22:58

katoy

総合スコア22324

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

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

0

double は内部では 10 進数でないため、大きな数でなくても 10 進数への変換によって誤差が出ます。そのため誤差が大きな問題となる場合には decimal が使われます。

分数クラスは実装されている言語も多いと思いますが、約分・通分に時間がかかるために概数より重くなります。そのため用途が限られ、double の上位互換とはなりません。
例えば 1/2 + 2/3 を計算するのに乗算が二回必要で、結果を約分するのには因数分解も必要になります。これは何万回もループするような場合、大きな差になります。約分しなければ計算するたびに大きな数になってすぐにオーバーフローして破綻します。

定数を展開せず定数のまま扱えるクラスというものは私は知りませんが、探せばあるかもしれません。ただしこれも用途が限られてくると思います。

投稿2017/04/29 22:13

編集2017/04/29 22:38
Zuishin

総合スコア28660

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

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

0

・有理数クラス
分数として表現できない数はどうするのでしょうか?
・実数クラス
2/3+√4という答えのままにするのでしょうか?
計算しないままそのままの形で表現するのに必要な記憶エリアはどのくらいでしょう。

2/3+√4なら2と3,4で3つ要りますね。
2/3+√4と2/5+√7はどちらが大きいと判断するのでしょうか?

誤差は出ませんが計算しないことで処理ができなくなってしまいますね。

投稿2017/04/29 20:46

maiko0318

総合スコア876

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

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

0

・有理数クラス

{ x[0] = 2/3, x[k+1]= x[k] * x[k] }
という漸化式を逐次計算するプログラムを考えます。

x[1] = 4 / 9
x[2] = 16 / 81
x[3] = 256 / 6561
x[4] = 65536 / 43046721
x[5] = 4294967296 / 1853020188851841
x[6] = 18446744073709551616 / 3433683820292512484657849089281

6回目の計算で64ビット整数で表現できる値を超えました。

  • 計算によっては、約分によって分子・分母が小さくなることがあるが、稀なケースであり、分子・分母が大きくなるケースが多い。
  • 一般には、計算に伴って分子・分母が大きくなる可能性が高いので、整数がオーバーフローする可能性を除去できない。

ということで、分子・分母がある一定の数値を超えない特殊な計算を除く、一般的な有理数クラスは現実的ではないと思います。

・実数クラス

  • 計算によっては、式が簡単になることがあるが、稀なケースであり、式が複雑になるケースが多い。
  • 一般には、計算に伴って式が複雑になる可能性が高く、式の複雑さに比例してデータ構造が複雑になる。
  • データ構造の複雑さに伴って、計算時間が長くなり、メモリ消費量も大きくなるので、実時間で計算が終了しない可能性、メモリ不足になる可能性を除去できない。

ということで、式がある一定の複雑さを超えない特殊な計算を除く、一般的な実数クラスは現実的ではないと思います。

投稿2017/04/30 00:08

naomi3

総合スコア1105

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問