31

私はこれが少し仮説的であることを知っていますが、なぜ私が知っている言語がそれをしないのか疑問に思っています.

たとえば、1/3 を格納します。プログラマーに 1/3 として指定するオプションを与え、1 と 3 を保存します。

struct float {
    int numerator;
    int denominator;
};

有理数の計算が本当に簡単になり、かなり正確になります!

これにより、浮動小数点数の精度とストレージの制限に関連する非常に多くの問題が解決され、新しい問題が発生することはないと思います!

したがって、私の質問:有理数が実装され、情報の損失がゼロの分数として格納されないのはなぜですか?


Joe が尋ねたように、他の人も指摘するかもしれませんが、これは既存のシステムを置き換えることを意味するのではなく、それを補完することを意味します。

Q: どのように保管しpiますか?

A: 多くの場合、私は単に保管1/3しているだけで、保管していませんpi。古い方法と新しい方法piで保管できます。1/3

4

8 に答える 8

17

デフォルトでこのように格納されない理由は、固定されたビット セットに収まる有効な値の範囲が小さいためです。クラスには、1/ MAXINTfloatから MAXINT (プラスまたはマイナス) までの数値を格納できます。AC/C++floatは、1E+37 ~ 1E-37 (プラスまたはマイナス) の数値を表すことができます。言い換えれば、標準floatは、半分のビット数を使用しているにもかかわらず、26 桁大きい値と 26 桁小さい値を表すことができます。一般に、完全に正確であるよりも、非常に大きな値と非常に小さな値を表現できる方が便利です。これは、丸めによって 1/3 のような小さな分数で正しい答えが得られる傾向があるため、特に当てはまります。g++ では、次は 1 を返します。

std::cout << ((1.0/3.0) * 3.0) << std::endl; 

C++ の型のビット単位は固定サイズであることに注意してください。したがって、32 ビットのデータ型には最大でも MAX_UINT 値があります。表現方法を変更すると、正確に表現できる値を変更するだけで、値を増やすことはできません。これ以上詰め込むことはできないため、「より正確」にすることはできません。5.4235E+25 のように、1/3 を正確に表すことができる代わりに、他の値を正確に表すことができません。

float1E-9 と 1E+9 (32 ビット整数を想定) の間の値をより正確に表現できることは事実ですが、この範囲外の値を完全に表現することはできません。さらに悪いことに、標準floatの精度は常に 6 桁ですfloatが、値がゼロにどれだけ近いかによって精度が異なります。(そして、2 倍のビットを使用していることに注意してくださいfloat。)

(私は 32 ビットints を想定しています。同じ引数が 64 ビットints に適用されます。)

編集float:また、人々がs を使用するほとんどのデータは正確ではないことに注意してください。センサーからデータを読み取っている場合、すでに不正確になっているため、値を「完全に」表現しようとしても意味がありません。あらゆる種類のコンピューティング コンテキストでを使用している場合float、それは問題になりません。画面の 1/3 の位置にテキストを表示することが目的である場合、「1/3」を完全に記述しても意味がありません。

完全な精度を本当に必要とするのは数学者だけであり、彼らは通常、これを実現するソフトウェアを持っています。与える以上の精度を必要とする人はほとんどいませんdouble

于 2012-05-27T03:49:05.327 に答える
10

実数演算が本当に簡単になり、かなり正確になります!

いいえ、そうではありません。あなたが記述した構造体は、分数として表現できる有理数のみを扱います。実数の集合には、有理数と無理数の両方が含まれます。実世界の計算のほとんどは実数を使用して行われるため、有理数に限定してすべてがうまくいくと期待することはできません。

私が知っている言語がなぜそれをしないのか疑問に思っています。

私が考えることができる言語のほとんどは、あなたが説明したことを正確に行うことを可能にします. C では、分子と分母を含む構造体を作成でき、そのような構造体を操作する一連の関数を定義できます。C++ は、クラスとそのクラスに対する操作を定義できるようにすることで、物事を非常に簡単にします。同じ考え方、より優れた構文などです。実際、OO 言語ではさまざまな数のセットが例としてよく使用されます。有理数クラスを作成し、それを拡張して虚数などを含めます。

正確な型の組み込みサポートを備えた言語がこれ以上ない理由は、おそらくプロセッサがそのような操作を直接サポートしていないという事実に関係していると思います。最新のプロセッサには、浮動小数点型の算術演算を実装する命令が含まれているため、どの言語にも簡単に組み込むことができます。正確な型をサポートすることは、数学ライブラリを言語に組み込むことを意味し、数学ライブラリを言語から除外して、それを必要とする人がソフトウェアに組み込むことができるようにする方が、おそらくいくつかのレベルで優れています。

正確な結果を得るためにあらゆる苦労をするつもりなら、おそらく合理的なものだけに限定したくないので、例として挙げた構造体はそれをカットしません。無理数が最初に現れたときに不正確な結果に戻る場合、有理数で正確な計算を行うことができてもあまり役に立ちません。幸いなことに、世の中には洗練された数学システムがあります。Mathematicaはよく知られている例の 1 つです。

于 2012-05-27T03:28:06.850 に答える
8

C++ には、少なくともコンパイル時の有理数演算ライブラリが含まれています。次に例を示します。

#include <ratio>
#include <iostream>

int main() {
    using a = std::ratio<3,5>;
    using b = std::ratio<7,6>;

    using c = std::ratio_multiply<a,b>::type;

    std::cout << c::num << '/' << c::den << '\n'; // prints 7/10
}

ここでは、3/5 に 7/6 を掛けて、7/10 を取得します。

于 2012-05-27T05:38:45.787 に答える
6

ヘルメットをかぶってください。ここで理論的な話を始めようとしています。

数学の学部生なら誰でも、実数の非可算カーディナリティのカントールの証明について簡単に説明できるでしょう。より長い説明については、こちらを参照してください。

しかし、カレブが指摘したように、実数フィールドには有理数と無理数の両方が含まれます。これは、実数フィールドの一部のサブセットが分子/分母のペアとして表現できないことを意味します。このサブセットの大きさは? 結局のところ、有理数の集合は可算であるため、ほとんどの実数は無理数です。

ここにオチがあります: 実数値関数のほとんどの出力は分子と分母として格納できないため、この方法で数値を格納するのは非常にばかげています。

これは信じがたいかもしれませんが、sin、cos、log などの一般的な超越関数について考えてみてください。これらの関数のほとんどの出力は合理的ではなく、IEEE 754 やその他の初期の FP を書いた人たちはこれを知っていました。彼らは、実数フィールドのはるかに大きな部分を表現する可能性と引き換えに少量のエラーを処理することは、設計上の優れたトレードオフであると考えました。

于 2012-05-27T03:55:46.870 に答える
5

多くの CPU は浮動小数点を特別に処理しており ( Wikipedia を参照) float、言語のデータ型により、プログラムは FPU を簡単に利用できます。一方、特別なアセンブラー命令で分数を処理できる CPU を知りません。そのため、分数をライブラリ内で簡単かつ効率的に実装でき、言語機能である必要はありません。C++ で分数を使用する場合は、Boost.Rationalを使用できます。

最新の CPU が分数を処理する代わりに浮動小数点演算を実装する理由は、浮動小数点をはるかに簡単に実装できるからです。基本的な操作を実装するには、基本float的に、整数の加算、減算、乗算、除算、およびビット シフトを実行できる必要があります。一方、分数と比較するには、2 つの int の最大公約数を見つける必要があり、これをハードウェアに実装するのははるかに困難です。

于 2012-05-27T03:38:21.473 に答える
4

あなたが得た多くの答えとは対照的に、あなたのアイデアは多くの種類の問題に適しています。特に、キャンセルが多いことがわかっているこのような問題では、正確な答えが必要です。 このため、Python にはfractionsモジュールがあり、@bames53 が指摘するように、C++ には<ratio>.

于 2012-05-27T07:03:35.933 に答える
2

「したがって、私の質問: 有理数が実装され、情報の損失がゼロの分数として格納されないのはなぜですか?」

C++ 標準ライブラリには、他の言語やライブラリが提供する実際に必要な型が多くありません。Boost ライブラリはすでに有理数の実装を提供しています。また、通貨量を処理するためなど、提案された decimal 型もまもなく提供されるようです。

なぜこれらの型が欠けているのかというと、C++ 標準ライブラリは一般に、基本的な一般的なビルディング ブロックを提供するだけであり、それらのブロックを使って構築するより実用的なものを提供するものではありません。つまりミニマルです。Boost ライブラリはミニマルではありません。たとえば、Poco ライブラリは、他の言語のより機能的に豊富な標準ライブラリに似ています。

于 2012-05-27T03:52:21.150 に答える
1

いくつかの理由があります:
- 一般的なアーキテクチャからのサポートがない。分数には常に単純化が伴う必要があるため、これは理解できます。これは、ハードウェアレベルで実装するのは簡単ではありません。むしろ、あまり適用されない命令になります。
- 非常に大きな数または非常に小さな数を処理できない。または、BigInteger が関与する必要があります。また、非常に大きな数または非常に小さな数の場合、通常、指定された精度のほとんどは必要ありません。
- これが言語レベルでサポートされている型である場合、他の数値型との変換をサポートする必要があります。内部表現の精度が固定されている場合 (乗算の場合)、いつ浮動小数点型を返すかを決定する必要があります。

言語では、何かをサポートするかどうかの決定は、通常、そのアプリケーション (または言語の論理的根拠) によって決定されます。アプリケーションが小さい場合、サポートされる可能性は低くなります。

于 2012-05-27T03:52:31.327 に答える