10進数では表現できないが、2進数では表現できる数値はありますか?


42

C#基数10での正確な表現が必要な数値に使用されるdecimalを持ちます。たとえば0.1、基数2(floatおよびなどdouble)で表現することはできず、これらの型の変数に格納されると常に近似値になります。

逆の事実も可能かどうか疑問に思っていました。10進数では表現できないが、2進数では表現できる数字がありますか(この場合floatdecimalそれらを処理するためにaの代わりにa を使用します)。


14
質問に+1しますが、c#タグは本当にここで適用できますか?他の言語にも10進数型があります。
パトリックM 14

1
@Max:演習として、ベース2の数値を手でベース10に変換することを想像することをお勧めします。たとえば、の値を計算するには0.11_b2、と記述し0.5 + 0.5 * 0.5ます。失敗したり、小数が繰り返される可能性のあるステップはありますか?個人的には、この演習は、基数2の数値に関する直感を理解するのに非常に役立ちます。さらに一歩進んで、この演習を建設による証明に変えることができると思います。
ブライアン14

ああ、でもあなたは間違っています。1/1010-
ザビエルJ

3
@Ramhoundメモリの制限を考えると、バイナリは0.0999999....998..正確に表現できますが、完全な数ではありません0.1-最も近い数百に丸めるような近似0.100は、すべての数字を表示せずに代わりに丸めることを伴う実装上の懸念です。
イズカタ14

1
さて、「0.1」を正確に表現できるFPエンコーディングメカニズムを考え出すことは可能です。このようなエンコーディングは、表現できない、または表現できないよりも、FP番号範囲のセットを移動するだけです。
マーティンジェームズ14

回答:


104

ここにあなたの苦境への鍵です:10の産物である25。基数10の10進数で、k * 1/2 n * 1/5 mの任意の数値を正確に表すことができます。ここknおよびmは整数です。

別の言い方をnすると-1 / nの数値に基数の因子の一部ではない因子が含まれている場合、その数値はその2進数/ 10進数/何でも展開の固定桁数で正確に表すことができません番号-繰り返し部分があります。たとえば、1/15 = 0.0666666666 ....は3(15 = 3 * 5)が10の因数ではないためです。

したがって、基数2で正確に表現できるもの(k * 1/2 n)は、基数10で正確に表現できます。

それ以外にも、数字を表すために何桁/ビットを使用しているのかという問題があります。いくつかの基数で正確に表現できる数がありますが、それは数桁以上のビット/ビットを必要とします。


2進数では、10進数で0.1が便利な1/10という数値は、2進数の固定ビット数で表現できる数値として表現することはできません。代わりに、数値は0.00011001100110011 ... 2です(0011部分は永久に繰り返されます)。

数1を見てみましょう2 /1010 2ビットより密接に。

          ____                  
       0.00011                  
     + ---------                 
1010 | 1.00000                  
       0                        
       -                       
       1 0                      
         0                      
       ----                     
       1 00 --------- +          
          0 |          
       ----- |          
       1 000 |          
           0 |          
       ------ | 繰り返す
       1 0000 | ブロック    
         1010 |          
       ------ |          
          1100 |          
          1010 |          
          ---- |          
            100 ---- +          

これは、1/3の長い除算を行おうとしたときに得られるものとまったく同じタイプです。

1/10、因数分解されたときは1 /(2 1 * 5 1)。ベース10(または10の倍数)のために、この数は終了し、として知られている定期的な数。繰り返される10進数の拡張は、繰り返し10進数と呼ばれ、繰り返しなくても永久に続く数字は無理数です。

この背後にある数学は、フェルマーの小さな定理を掘り下げます...そして、フェルマーまたは定理と言い始めると、それはMath.SEの質問になります。

10進数では表現できないが、2進数では表現できる数値はありますか?

答えはノーです'。

したがって、この時点で、有理数のすべての固定長のバイナリ展開は、固定長の10進展開として表現できることを明確にする必要があります。


ことができますC#で小数点以下でより密接に見てに私たちをリード.NETで10進浮動小数点と著者を与え、私はそれがどのように動作するかというのthatsを受け入れるだろう。

decimal型には、他の浮動小数点数と同じコンポーネントがあります:仮数、指数、および符号。いつものように、符号は1ビットだけですが、仮数の96ビットと指数の5ビットがあります。ただし、すべての指数の組み合わせが有効なわけではありません。値0〜28のみが機能し、それらは事実上すべて負です。数値はです。これは、そのタイプの最大値と最小値が+/-(2 96 -1)であり、絶対値での非ゼロの最小値が10 -28であることを意味します。sign * mantissa / 10exponent

すぐに指摘しますが、この実装のために、double型には表現できない数字がありますdecimal-範囲外の数字です。 Double.Epsilon4.94065645841247e-324で表すことができないdecimalではなく、缶double

ただし、decimalが表現できる範囲内では、他のネイティブ型よりも精度が高く、エラーなく表現できます。

他にもいくつかの種類があります。C#には、任意の大きな整数を表すことができるBigIntegerがあります。JavaのBigDecimal(最大2 32桁の長さの数字を表すことができる-これはかなりの範囲です)相当するものはありません。ただし、少し調べてみると、手巻きの実装を見つけることができます。

有理数を正確に表すことができる合理的なデータ型を持つ言語もあります(したがって、1/3は実際には1/3になります)。


特にC#とフロートまたは有理数の選択については、.NETのDecimalフローティングパイントからJon Skeetに従うことにします

ほとんどのビジネスアプリケーションでは、おそらくfloatまたはdoubleではなく10進数を使用する必要があります。私の経験則では、通貨などの人工の値は通常、10進浮動小数点でより適切に表されます。たとえば、正確に1.25ドルの概念は完全に合理的です。長さや重みなど、自然界の値の場合、バイナリ浮動小数点型はより意味があります。理論的には「正確に1.25メートル」ありますが、実際には決して発生しません。正確な長さを測定することは絶対に不可能であり、原子レベルで存在することはほとんどありません。私たちは、特定の許容範囲が関係していることに慣れています。


明確で簡潔な数学的説明のために+1。そして、タイトルで提起された質問のより一般的なバージョンに答えるために、基数10で表現できない数の例は1/3です。
ドーバル14

@Doval私の推論や説明には、より数学志向の人が指摘できる不具合があるのではないかと疑っています...

この場合の「比較的素数」とは、「要因ではない」という意味ですよね?私が見逃しているより深い数学的な関係はありますか?
パトリックM 14

1
ああ、私はそれを理解し、などn = 15b = 10されない互いに素彼らが要因として5を共有しているため(「1以外共通のプラス要因(約数)を共有しません」)。重要な点は、15のすべての要因(5 3)が10の要因でもないということです(それ以外に、すべての共通の要因を共有する、または共有しない数値を示す言葉はありますか?)あなたのk, n, m方程式に包まれましたが、本当に私の頭を包むには、3Dプロットを見る必要があります。とにかく、あなたに+1するに値する。
パトリックM 14

1
@PatrickM:「脇:行うか、すべての共通因子を共有していない番号を示すために単語がある」:任意の整数のすべての要因そうであれば、それ自体の係数であるMはの要因であるN、それは些細なことになりますmnの係数です。これを表す用語の1つは、ご存じのとおり、factorです。もう1つは除数です。
ruakh

6

許容値の範囲外になったら、答えはイエスです。とは言っても、範囲内のほとんどすべてに表現があります。C#10進数の参照仕様には記載されていませんが、無理数は正確に表現できません(e 1、pi、2の平方根など)。

decimalキーワードは、128ビットのデータ型を示します。浮動小数点型と比較して、decimal型は精度が高く範囲が狭いため、財務計算および通貨計算に適しています。10進タイプのおよその範囲と精度を次の表に示します。

精度:28-29有効数字

1別の無理数を思い出させてくれたMichaelTに感謝します。


2
@Magusは無理数e(2.71 ...)を考慮します。自然対数-ln(x)は対数底eです。したがって、非合理的な基盤が存在し、有用です。base piの特定の有用性についてはわかりませんが、それがどこかで使用されないという意味ではありません。

6
@Max数学の質問にどんどん迷い込んでいます。あなたは見つけること数はベース10に不合理である場合、それは他の塩基に不合理なのですか?有用な読み物であり、より多くの数論の質問の出発点になるように。

2
1/3は非合理的ではありません。
アダムザッカーマン14

2
OPは10進数(10)について尋ねました。数値システムのベースを何でもベースにすることで、何でも10として表現できます。ウィキペディアの記事に基づくと、無理数をベースとして使用しても合理的ではありません。有理数は、分子と分母の両方の整数、10進数の数字の繰り返し、または10進数の数字の有限終了として表現できます。
アダムザッカーマン14

5
@FrustratedWithFormsDesigner不合理性は、ベースとは何の関係もありません。まあ、それは誇張ですが、それはさまざまな基数での数値表現に影響を与える非合理性です(たとえば、無限の非反復数字があるかどうか)。:上記にリンクされているmath.se質問読むmath.stackexchange.com/questions/625473/...

1

基数2の浮動小数点型は、同じサイズの基数10の型ではできなかった多くの値を正確に表すことができます。あるサイズのベース2タイプで正確に表現できる値は、十分なサイズのベース10タイプで正確に表現できます。2進浮動小数点数のすべての値を表すために純粋に10進型に必要なサイズは、2進型の指数範囲によって異なります。aに対して数百ビットfloat、またはa に対して数千ビットdouble

そうは言っても、このDecimal型は十分に大きいため、他の数値プリミティブの値を保持できる「ユニバーサル」型として使用可能にし、他にいくつかの追加機能を提供することができます(他の場合は1ビットを使用します)格納された値がaの変換結果であるかどうかを示しdouble、そのビットが設定されている場合は、64ビットを使用して問題の値を保持します)。ただし、Microsoftはそうしないことを選択しました。結果としての変換doubleにはDecimal、大きな値のために完全に失敗する小さな値は、最も近い1E-28に四捨五入されます。さらに、ダイナミックレンジ内でもdecimal、変換方法は「往復」しません。たとえば、1.0 / 3.0をdoubleとして評価すると0.3333333333333333148になりますが、10進数に変換すると0.333333333333333mになり、それを再びdoubleに変換すると0.3333333333333329818になります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.