C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

長い桁数の定数を使用する方法

[トピック内 8 記事 (1 - 8 表示)]  << 0 >>

■91729 / inTopicNo.1)  長い桁数の定数を使用する方法
  
□投稿者/ kozue (1回)-(2019/07/26(Fri) 12:41:48)

分類:[.NET 全般] 


例えば、
Dim kbs As Single = 3.14159265358979312384626433
Dim kbd As Double = 3.14159265358979312384626433

というコードをコピペで貼り付けても
桁数が丸められて以下のようになってしまいます。

Dim kbs As Single = 3.1415926535897931
Dim kbd As Double = 3.1415926535897931
SingleでもDoubleでも有効数字が変わらないのはなぜなのでしょうか?

どうすれば、もっと長い桁数の定数を使用することができますか?

引用返信 編集キー/
■91730 / inTopicNo.2)  Re[1]: 長い桁数の定数を使用する方法
□投稿者/ KOZ (7回)-(2019/07/26(Fri) 13:10:20)
No91729 (kozue さん) に返信
> Dim kbs As Single = 3.1415926535897931
> Dim kbd As Double = 3.1415926535897931
> SingleでもDoubleでも有効数字が変わらないのはなぜなのでしょうか?

それぞれ ToString() してみると

Debug.Print(kbs.ToString("G28"))
Debug.Print(kbd.ToString("G28"))
3.14159274
3.1415926535897931

有効桁は違います。

> どうすれば、もっと長い桁数の定数を使用することができますか?

そのような型を定義します。
たとえば、ODP.NET の OracleDecimal 構造体は 38 桁まで扱えるので

Dim od1 As New OracleDecimal("3.14159265358979312384626433")
Dim od2 As New OracleDecimal("3.14159265358979312384626433")
Dim od3 As OracleDecimal = od1 + od2
Debug.Print("{0}", od3.ToString())

結果:
6.28318530717958624769252866

と、キレイに計算できます。


引用返信 編集キー/
■91731 / inTopicNo.3)  Re[2]: 長い桁数の定数を使用する方法
□投稿者/ KOZ (8回)-(2019/07/26(Fri) 13:29:16)
System.Data.SqlTypes 名前空間の SqlDecimal でもいけました。

Dim sd1 As SqlDecimal = SqlDecimal.Parse("3.14159265358979312384626433")
Dim sd2 As SqlDecimal = SqlDecimal.Parse("3.14159265358979312384626433")
Dim sd3 As SqlDecimal = sd1 + sd2
Debug.Print("{0}", sd3.ToString())

結果:
6.28318530717958624769252866

引用返信 編集キー/
■91732 / inTopicNo.4)  Re[3]: 長い桁数の定数を使用する方法
□投稿者/ kozue (2回)-(2019/07/26(Fri) 13:38:12)
ありがとうございます。

singleとdoubleの桁数を勘違いしていました。

ちなみに
https://www.cc.kyoto-su.ac.jp/~yamada/programming/float.html
Singleは7桁doubleは15桁と書かれてありますが。
3.14159274
3.1415926535897931

はそれぞれ9桁と17桁になっています
なぜこのような違い見られるのでしょうか?

引用返信 編集キー/
■91735 / inTopicNo.5)  Re[4]: 長い桁数の定数を使用する方法
□投稿者/ 魔界の仮面弁士 (2262回)-(2019/07/26(Fri) 14:16:53)
No91732 (kozue さん) に返信
> https://www.cc.kyoto-su.ac.jp/~yamada/programming/float.html
> Singleは7桁doubleは15桁と書かれてありますが。
> 3.14159274
> 3.1415926535897931
> はそれぞれ9桁と17桁になっています
ラウンドトリップ文字列と「有効桁数」は別物ですよ。

> なぜこのような違い見られるのでしょうか?
Decimal 型が、その名前の通り「10進数」相当の管理を行っているのに対して、
Single や Double は「2 進数」管理の小数であることはご存知でしょうか。

Single の有効桁数は、2 進表現で 23+1 桁なので、
10 進表現では「7.2247198959…桁」にあたります。

Double の有効桁数は、2 進表現で 52+1 桁なので、
10 進表現では「15.954589770…桁」にあたります。


> 3.14159274
Single の 3.14159274 は、内部的には
 0b0_10000000_10010010000111111101000
に相当するバイナリとして保持されています。
これは 10 進数では 3.1415958404541015625 相当の値です。

要するに、
 (2^1 +2^0 +2^-3 +2^-6 +2^-11 +2^-12 +2^-13 +2^-14 +2^-15 +2^-16 +2^-17 +2^-19)
ということです。

バイナリの 0b0_10000000_10010010000111111101000 を
1 増やして 0b0_10000000_10010010000111111101001 にすると、
10 進数で 3.1415960788726806640625 相当になります。

1 減らして 0b0_10000000_10010010000111111100111 にすると、
10 進数で 3.1415956020355224609375 相当です。

これら隣り合う三つの値を並べてみると、
 3.1415956020355224609375
 3.1415958404541015625
 3.1415960788726806640625
となりますよね。なので、元データの有効桁数が 24 bit あっても、
10進小数としてラウンドトリップする場合、この数値域においては
 3.14159274
の桁数まであれば、十分に元の Single 値を表現できるというわけです。
引用返信 編集キー/
■91736 / inTopicNo.6)  Re[4]: 長い桁数の定数を使用する方法
□投稿者/ 魔界の仮面弁士 (2263回)-(2019/07/26(Fri) 14:28:09)
No91732 (kozue さん) に返信
> 3.1415926535897931
ついでに Double の近似値についても。

上記は 0b0_10000000000_1001001000011111101101010100010001000010110100011000 であり、

= (2^1 +2^0 +2^-3 +2^-6 +2^-11 +2^-12 +2^-13 +2^-14 +2^-15
+2^-16 +2^-17 +2^-20 +2^-21 +2^-22 +2^-23 +2^-26 +2^-28
+2^-33 +2^-37 +2^-38 +2^-40 +2^-41 +2^-45 +2^-46 +2^-51)

相当なので、そのまま復元すると、
 3.141595740000000080982545114238746464252471923828125
に相当します。


内部バイナリを 1 bit ずつずらして近似値を作ると
 -2: 0b0_10000000000_1001001000011111101101010100010001000010110100010110
 -1: 0b0_10000000000_1001001000011111101101010100010001000010110100010111
 =0: 0b0_10000000000_1001001000011111101101010100010001000010110100011000
 +1: 0b0_10000000000_1001001000011111101101010100010001000010110100011001
 +2: 0b0_10000000000_1001001000011111101101010100010001000010110100011010
になるので、これを 10 進小数に戻すと
 -2: 3.14159265358979222781954376841895282268524169921875
 -1: 3.141592653589792671908753618481568992137908935546875
 =0: 3.141592653589793115997963468544185161590576171875
 +1: 3.141592653589793560087173318606801331043243408203125
 +2: 3.14159265358979400417638316866941750049591064453125
になります。

なので、実運用上の表現形式では
 =0: 3.1415926535897931
の桁数まで表現すれば、前後の近似値と区別できますね。
引用返信 編集キー/
■91737 / inTopicNo.7)  Re[5]: 長い桁数の定数を使用する方法
□投稿者/ KOZ (10回)-(2019/07/26(Fri) 14:34:49)
No91735 (魔界の仮面弁士 さん) に返信

フォローありがとうございます。
こういうのがサクっと書けるのは流石。

元ネタですが Decimal でOKでした・・・

Dim dec As Decimal = 3.14159265358979312384626433D

引用返信 編集キー/
■91738 / inTopicNo.8)  Re[1]: 長い桁数の定数を使用する方法
□投稿者/ 魔界の仮面弁士 (2264回)-(2019/07/26(Fri) 15:00:20)
No91729 (kozue さん) に返信
>  Dim kbs As Single = 3.14159265358979312384626433
>  Dim kbd As Double = 3.14159265358979312384626433

「3.14159265358979312384626433」表記だと、Double 型と認識されます。
https://docs.microsoft.com/ja-jp/dotnet/visual-basic/programming-guide/language-features/data-types/type-characters


型を明示するには、
 Dim sng1 As Single = 3.14159265358979312384626433F
 Dim sng2 As Single = 3.14159265358979312384626433!

 Dim dbl1 As Double = 3.14159265358979312384626433R
 Dim dbl2 As Double = 3.14159265358979312384626433#

 Dim dec1 As Decimal= 3.14159265358979312384626433D
 Dim dec2 As Decimal= 3.14159265358979312384626433@
のようにします。


ただし、表現しきれない桁部分は自動的に削がれるので、上記が
 Dim sng1 As Single = 3.14159274F
 Dim sng2 As Single = 3.14159274!

 Dim dbl1 As Double = 3.1415926535897931R
 Dim dbl2 As Double = 3.1415926535897931#

 Dim dec1 As Decimal = 3.14159265358979312384626433D
 Dim dec2 As Decimal = 3.14159265358979312384626433@
などに書き換わる点については変わりありません。
引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ