■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 に変換される結果になりますね。
■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」という値で計算されてしまい、本来の値から微減してしまうわけです。
- Child Tree -