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

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

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

指数表記する方法

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

■85804 / inTopicNo.1)  指数表記する方法
  
□投稿者/ ちゃんころ (1回)-(2017/11/26(Sun) 08:55:06)

分類:[.NET 全般] 

Public Const diele As Single = 8.85418782E-12

と入力すると、自動で

Public Const diele As Single = 0.00000000000885418782

と置き換わってしまいます。
指数表記のままで表示したいのですが
どうすれば良いですか?

Public Const diele As Single = 8.85418782 * 10 ^ (-12)

というようにするしかないですか?
 
引用返信 編集キー/
■85805 / inTopicNo.2)  Re[1]: 指数表記する方法
□投稿者/ ちゃんころ (2回)-(2017/11/26(Sun) 08:59:24)
すいません、


Public Const diele As Single = 8.854188E-12!

とすることで解決しました。
しかしこの方法だと
Public Const diele As Single = 8.85418782E-12!

のように長い桁数を入力できないのですが
どうすれば良いですか?
 
引用返信 編集キー/
■85806 / inTopicNo.3)  Re[2]: 指数表記する方法
□投稿者/ Hongliang (574回)-(2017/11/26(Sun) 10:02:52)
Single型だと7桁までしか有効ではありません。
https://msdn.microsoft.com/ja-jp/library/system.single(v=vs.100).aspx
それ以上の桁数が欲しいなら、Double型あるいはDecimal型で扱う必要があります。
引用返信 編集キー/
■85807 / inTopicNo.4)  Re[3]: 指数表記する方法
□投稿者/ ちゃんころ (4回)-(2017/11/26(Sun) 11:44:19)
No85806 (Hongliang さん) に返信


Doubleでも試してみたのですが
Public Const diele As Single = 8.85418782E-12#

というのが

Public Const diele As Single = 0.00000000000885418782

というのに変わってしまいます。

どうすれば良いですか?
 
引用返信 編集キー/
■85811 / inTopicNo.5)  Re[4]: 指数表記する方法
□投稿者/ 魔界の仮面弁士 (1477回)-(2017/11/26(Sun) 19:36:47)
No85807 (ちゃんころ さん) に返信
> Public Const diele As Single = 8.85418782E-12#
> というのが
> Public Const diele As Single = 0.00000000000885418782
> というのに変わってしまいます。

VB のエディタは、極力、小数表記で記述しようとするためです。
その境目となるのは、おそらく指数部の桁数でしょう。

Double 型リテラルの場合、E+14〜E-16 の範囲は小数表記、その範囲外が指数表記になり、
Single 型リテラルの場合、E+6〜E-8 の範囲が小数表記、その範囲外が指数表記になります。
Decimal 型リテラルはの場合は、すべて小数表記にフォーマットされます。


> どうすれば良いですか?

今回の「8.85418782E-12」という表現からして、有効桁数 9 桁の値を表現したいようですが、
Hongliang さんから指摘のあるとおり、Single 型ではこの精度の値を扱うことはそもそも出来ません。
どう修正すべきかは、求める要件によって変わりますが、有効桁数 9 桁が本当に必要なら、
As Double にするか、As Decimal にする必要があるでしょう。

より正確に言えば、
Double 型の仮数部の幅は、53+1ビット≒15.95 桁分であるのに対し、
Single 型の仮数部の幅は、23+1ビット≒7.225 桁分しかないということです。
ちなみに Decimal 型の場合は 96 ビット幅なので、約 28.89888 桁です。

有効桁数 9 桁の値を Single 型で管理するには有効桁数が不足してしまい、
どうあっても、格納時には近似値に丸められることになるでしょう。

確認のため、「8.85418782E-12」相当の近似値を Single 型で表現してみましょうか。
先に言っておくと、誤差が最小になるのは 3 番です。

《Single のバイナリ表現》
1: 0b00101101000110111100001110110110
2: 0b00101101000110111100001110110111
3: 0b00101101000110111100001110111000
4: 0b00101101000110111100001110111001
5: 0b00101101000110111100001110111010

《上記を 10進小数で表現した値》
1: 0.00000000000885418648122193729932405403815209865570068359375
2: 0.000000000008854187348583675287727601244114339351654052734375
3: 0.000000000008854188215945413276131148450076580047607421875
4: 0.000000000008854189083307151264534695656038820743560791015625
5: 0.00000000000885418995066888925293824286200106143951416015625


ちなみに上記を diele.ToString("R") でラウンドトリップ出力した場合、
1: 8.85418648E-12
2: 8.854187E-12
3: 8.854188E-12
4: 8.854189E-12
5: 8.85419E-12
となります。

いずれも E-8 を下回る指数表現であるため、この場合は自動変換が起こりません。
 Public Const Sample1 As Single = 8.85418648E-12F
 Public Const Sample2 As Single = 8.854187E-12F
 Public Const Sample3 As Single = 8.854188E-12F
 Public Const Sample4 As Single = 8.854189E-12F
 Public Const Sample5 As Single = 8.85419E-12F

もともと扱おうとしていた「8.85418782E-12F」という値は、
2 番と 3 番の間になり、Single の精度では表現しきれません。
そのため、より近い値である 3 番の表記に変換されたということです。
(有効桁数ってそういうものですよね)


> Doubleでも試してみたのですが

同様に、「8.85418782E-12」の Double 値による近似値表現を見てみます。
こちらの場合は、3 番が同一値となります。(格納誤差はありません)


《Double のバイナリ表現》
1: 0b0011110110100011011110000111011011110001011001000110011010111010
2: 0b0011110110100011011110000111011011110001011001000110011010111011
3: 0b0011110110100011011110000111011011110001011001000110011010111100
4: 0b0011110110100011011110000111011011110001011001000110011010111101
5: 0b0011110110100011011110000111011011110001011001000110011010111110

《上記を 10進小数で表現した値》
1: 0.0000000000088541878199999971451928483766392647021092887626991796423681080341339111328125
2: 0.00000000000885418781999999876077998226927144218532939046184537801309488713741302490234375
3: 0.000000000008854187820000000376367116161903619668549492160991576383821666240692138671875
4: 0.00000000000885418782000000199195425005453579715176959386013777475454844534397125244140625
5: 0.0000000000088541878200000036075413839471679746349896955592839731252752244472503662109375

《R 書式によるラウンドトリップ出力》
1: 8.8541878199999971E-12
2: 8.8541878199999988E-12
3: 8.85418782E-12
4: 8.854187820000002E-12
5: 8.8541878200000036E-12


そして先述した通り、Double 型で E-12 の範囲は小数表記されるため、
 Public Const Sample1 As Double = 8.8541878199999971E-12R
 Public Const Sample2 As Double = 8.8541878199999988E-12R
 Public Const Sample3 As Double = 8.85418782E-12R
 Public Const Sample4 As Double = 8.854187820000002E-12R
 Public Const Sample5 As Double = 8.8541878200000036E-12R
と書いても
 Public Const Sample1 As Double = 0.0000000000088541878199999971R
 Public Const Sample2 As Double = 0.0000000000088541878199999988R
 Public Const Sample3 As Double = 0.00000000000885418782R
 Public Const Sample4 As Double = 0.000000000008854187820000002R
 Public Const Sample5 As Double = 0.0000000000088541878200000036R
に変換される結果になりますね。

引用返信 編集キー/
■85812 / inTopicNo.6)  Re[2]: 指数表記する方法
□投稿者/ 魔界の仮面弁士 (1478回)-(2017/11/26(Sun) 20:22:30)
No85805 (ちゃんころ さん) に返信
> Public Const diele As Single = 8.854188E-12!
VB.NET 的には
 Public Const diele As Single = 8.854188E-12F
とも書けますね。

既にご存知かもしれませんが、
接尾辞 F または型宣言文字 ! が Single / 単精度浮動小数点型で
接尾辞 R または型宣言文字 # が Double / 倍精度浮動小数点型で
接尾辞 D または型宣言文字 @ が Decimal / 10進型となっています。
型宣言文字は古い VB や BASIC でも使われていた記号ですが、現在でも有効ですね。


C# だと、下記のように微妙に違うので、相互書き換えの際にはご注意を…。
接尾辞 F または f が float / System.Single で
接尾辞 D または d が double / System.Double で
接尾辞 M または m が decimal / System.Decimal です。



■No85804 (ちゃんころ さん) に返信
> Public Const diele As Single = 8.85418782E-12
> と入力すると、自動で
> Public Const diele As Single = 0.00000000000885418782
> と置き換わってしまいます。

これが VBA だとその逆で、
 8.85418782E-12
に統一されてしまうみたいですね。

No85811 で示した
>> Double 型リテラルの場合、E+14〜E-16 の範囲は小数表記、その範囲外が指数表記になり、
>> Single 型リテラルの場合、E+6〜E-8 の範囲が小数表記、その範囲外が指数表記になります。
に合わせて言えば、VBA で小数表記になるリテラル範囲は、
Double 型が E+14〜E-16 の範囲で、Single 型が E+06〜E-07 の範囲のようです。


> 指数表記のままで表示したいのですが
> どうすれば良いですか?

Visual Studio のオプション設定で、「コードの再フォーマット」を Off にすれば
一応置き換わらなくはなります。

といっても、[編集]-[詳細]-[ドキュメントのフォーマット] などによって
容易に置き換えられてしまうので、一時凌ぎにしかなりませんが。


コードの表現上、指数表記を好むのであれば、Const の代わりに
ReadOnly なフィールド変数かプロパティで代用するのはどうでしょう。
 Public Shared ReadOnly diele As Single = CSng("8.541882E-12")

Const でないと都合が悪いなら、コメントで補足しておくとか…。
 Public Const diele As Single = 0.00000000000885418782   ' = 8.85418782E-12


> Public Const diele As Single = 8.85418782 * 10 ^ (-12)
> というようにするしかないですか?

個人的にはあまり好きな表現ではないですが、
本来求める結果と同じ結果となるのであれば、
そのような書き換えをするという手もありだと思いますよ。

ちなみに、
 Public Const diele1 As Single = 0.00000000000885418782  '8.85418782E-12
 Public Const diele2 As Single = 8.854188E-12F           '8.85418782E-12F
 Public Const diele3 As Single = 8.85418782 * 10 ^ (-12) '8.85418782 * 10 ^ (-12)
 Public Const diele4 As Single = 885418782 * 1.0E-20R    '885418782 * 1.0E-20R
 Public Const diele5 As Single = 885418782 * 1.0E-20F    '885418782 * 1.0E-20F
の場合、個人的には diele2 の記述を推奨しています。

diele1 と diele2 は、単一の値が VB によって自動整形されただけであり、
それによって結果が異なることは無いと言えるからです。

加えて、右辺の数式としては、1、3、4 が Double 型の結果になる式で、
2, 5 が Single となる式です。

そのため、結果が Single になることを重視して、私は diele2 のリテラル表記で
宣言しています。diele3 は、「^ 演算子」によるものなので、
結果が Double になるのが個人的には好みでは無いので。
結果的には同一なのですけれどね。


diele4 は、diele3 の計算を「整数 × 10^n」形式にしたものですが、
今回のケースでは、分かり難くなるだけでメリットが無いですね。

そして diele5 は、diele4 を Single に統一しようとしたものですが、
これは悪手というか、『間違った対処方法』であることに注意が必要です。

何が問題かといえば、diele5 だけ、diele1〜diele4 とは異なる結果になってしまうという点です。
これは、Visual Basic の仕様において、「Integer * Single」の演算が
「CSng(Integer) * Single」相当の処理になってしまうためです。
(正確な表現ではないですが、あくまでイメージとして)

今回は有効数字 9 桁であり、そもそも Single では表せない値ですから、
「885418782.0F」という値は Single 値で表現しきれません。そのため、近似値である
「885418752.0F」という値で計算されてしまい、本来の値から微減してしまうわけです。

引用返信 編集キー/
■85814 / inTopicNo.7)  Re[5]: 指数表記する方法
□投稿者/ 魔界の仮面弁士 (1480回)-(2017/11/26(Sun) 21:20:37)
No85811 (魔界の仮面弁士) に追記
> Double 型の仮数部の幅は、53+1ビット≒15.95 桁分であるのに対し、
> Single 型の仮数部の幅は、23+1ビット≒7.225 桁分しかないということです。
> ちなみに Decimal 型の場合は 96 ビット幅なので、約 28.89888 桁です。

間違い訂正。

Double の仮数部のビット数が間違っていました。
Double は 53+1 ビット ではなく、52+1 ビット でしたね。

1bitで表せる範囲は 0〜1 で、0.30103 桁相当
2bitで表せる範囲は 0〜3 で、0.60205 桁相当
3bitで表せる範囲は 0〜7 で、0.90308 桁相当
4bitで表せる範囲は 0〜15で、1.20412 桁相当
5bitで表せる範囲は 0〜31で、1.50515 桁相当
6bitで表せる範囲は 0〜63で、1.80618 桁相当
7bitで表せる範囲は0〜127で、2.10721 桁相当
8bitで表せる範囲は0〜255で、2.40824 桁相当

23+1bit なら、7.22472 桁相当
52+1bit なら 15.95459 桁相当
引用返信 編集キー/
■85815 / inTopicNo.8)  Re[1]: 指数表記する方法
□投稿者/ shu (1070回)-(2017/11/27(Mon) 08:57:56)
No85804 (ちゃんころ さん) に返信
> Public Const diele As Single = 8.85418782E-12
>
> と入力すると、自動で
>
> Public Const diele As Single = 0.00000000000885418782
>
> と置き換わってしまいます。
> 指数表記のままで表示したいのですが
> どうすれば良いですか?
>
> Public Const diele As Single = 8.85418782 * 10 ^ (-12)
>
> というようにするしかないですか?
>  

@ Public Const diele As Single = 8.85418782E-12 を入力してエンター
A CTRL+Z

で一応可能です。
または
そのソースを閉じた状態で外部エディタで編集して開きなおす。

いづれにしてもその行に対しチェックがかかると同じ状態は発生してしまいます。


引用返信 編集キー/
■85928 / inTopicNo.9)  Re[2]: 指数表記する方法
□投稿者/ ちゃんころ (5回)-(2017/12/03(Sun) 15:59:01)
みなさん、ご回答ありがとうございます。

VBの仕様だと、
パーフェクトな方法は存在しないことが理解できました 
解決済み
引用返信 編集キー/

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


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

このトピックに書きこむ