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

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

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

数値書式指定文字列からの変換

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

■96979 / inTopicNo.1)  数値書式指定文字列からの変換
  
□投稿者/ ゆい (26回)-(2021/03/10(Wed) 10:51:00)

分類:[VB.NET/VB2005 以降] 

超初心者ですみません。
VB2017です。

調べたのですが分かりません。
例えば "8.0355015e-03" を単精度浮動小数点型に変換する方法を教えてください。
お願いします。
引用返信 編集キー/
■96980 / inTopicNo.2)  Re[1]: 数値書式指定文字列からの変換
□投稿者/ 魔界の仮面弁士 (2999回)-(2021/03/10(Wed) 11:03:56)
No96979 (ゆい さん) に返信
> 例えば "8.0355015e-03" を単精度浮動小数点型に変換する方法を教えてください。

こうですかね。浮動小数点数なので近似値にしかならないですけど。

Dim v1 As Single = CSng("8.0355015e-03")
Dim v2 As Single = Single.Parse("8.0355015e-03")
Dim v3 As Single : Single.TryParse("8.0355015e-03", v3)

引用返信 編集キー/
■96981 / inTopicNo.3)  Re[2]: 数値書式指定文字列からの変換
□投稿者/ ゆい (27回)-(2021/03/10(Wed) 18:16:04)
No96980 (魔界の仮面弁士 さん) に返信

ありがとうございます。

"8.0355015e-03" の 03 が 05以上になれば変換は出来ないのでしょうか?
念のためSingleをDoubleに変えても同じでした。

引用返信 編集キー/
■96982 / inTopicNo.4)  Re[3]: 数値書式指定文字列からの変換
□投稿者/ Hongliang (1157回)-(2021/03/10(Wed) 19:25:22)
2021/03/10(Wed) 19:25:54 編集(投稿者)

変換は可能です。
Single/Doubleに変換後、さらにそれを表示させるなどのために文字列化する際、
e-5以上の場合に指数表記されるのは仕様ですね。

Dim s As Single = Single.Parse("8.0355015e-05")
Trace.WriteLine(s) ' 8.035501E-05
Trace.WriteLine(String.Format("{0:f13}", s)) ' 0.0000803550138
引用返信 編集キー/
■96984 / inTopicNo.5)  Re[3]: 数値書式指定文字列からの変換
□投稿者/ 魔界の仮面弁士 (3001回)-(2021/03/10(Wed) 22:40:04)
No96981 (ゆい さん) に返信
> "8.0355015e-03" の 03 が 05以上になれば変換は出来ないのでしょうか?

変換はできますが、Single 型の精度では物足りないと感じるかもしれません。


Single 型の精度においては、下記すべて同一値に変換されます。

Dim x As Single = CSng("8.0355010e-03")
Dim y As Single = CSng("8.0355015e-03")
Dim z As Single = CSng("8.0355019e-03")

上記の値は、いずれも下記の 3 の近似値に変換されることになります。
Single 型でとりえる前後の値も合わせて掲載しておきますね。

0 … 0.008035498671233654022216796875 … 約 0.008035499
1 … 0.008035499602556228637695312500 … 約 0.0080355
2 … 0.008035500533878803253173828125 … 約 0.00803550053
3 … 0.008035501465201377868652343750 … 約 0.008035501
4 … 0.008035502396523952484130859375 … 約 0.008035502
5 … 0.008035503327846527099609375000 … 約 0.008035503
6 … 0.008035504259169101715087890625 … 約 0.008035504



そもそも、『実際に必要な有効桁数』はどの程度なのでしょうか?

マラソンの距離が 42.195km だからといって、それを「42195000mm」と言い換える事は、
精度的に不自然なわけです。とはいえ、それで構わないというケースにおいては、
CDec("8.0355015e-03") を使うという選択肢もあろうかと思います。

ただし Decimal にすると、扱える最大値と最小値は Single よりも狭くなります。
そのため『有効桁数』だけでなく、『最大値と最小値はどの範囲なのか』も重要になってきます。


> 念のためSingleをDoubleに変えても同じでした。

Integer 型で「5.3」や「6.4」を保持しようとしたら、5 や 6 に丸められる事はわかりますよね。
Integer は、隣り合う数との間隔が常に 1 な型ですので、それより細かい間隔の値を
保持しようとすれば、整数という近似値に丸められることになります。


Single や Double の場合も同様です。連続した値を保持できるわけでは無く、
有効桁数から外れた値が近似値となります。しかも、その間隔は一定ではなく、
「0 に近いほど細かく」「0 から離れるほど大雑把」になる仕様です。


"8.0355015e-03" の場合、e の前の数値が 8 個あるので、この値の有効桁数は 8 桁ですが、
話を簡単にするために、ここでは「有効桁数 3 桁」の指数があったとしましょう。

1.22E3 と 1.23E3 の差は、10 ですが
1.22E7 と 1.23E7 の差は、100000 になります。

1.22E-3 と 1.23E-3 の差は、0.00001 で、
1.22E-5 と 1.23E-5 の差は、0.0000001 です。

いずれの組み合わせも、「有効桁数 3 桁」の範囲で、隣り合う 2 つの数を比べているだけですが、
E の後ろの値が大きくなるほど、隣り合う値との差が大きく「荒く」なっており、
E の後ろの値が小さくなるほど、隣り合う値との差が小さく「細かく」表現できることがわかります。

そのため、演算時に E の後ろの値(指数)が大きく異なる値同士を扱うと、
有効桁数のうち、実際に使える桁数が狭くなってしまうことに注意してください。
これは Decimal であっても同じことです。


   Byte 型の有効桁数は  8 bit なので、10進数換算で  2.40824 桁弱までの精度で扱えます。
Integer 型の有効桁数は 31 bit なので、10進数換算で  9.33193 桁弱までの精度で扱えます。
 Single 型の有効桁数は 24 bit なので、10進数換算で  7.22472 桁弱までの精度で扱えます。
 Double 型の有効桁数は 53 bit なので、10進数換算で 15.95459 桁弱までの精度で扱えます。
Decimal 型の有効桁数は 96 bit なので、10進数換算で 28.89888 桁弱までの精度で扱えます。

引用返信 編集キー/
■96985 / inTopicNo.6)  Re[4]: 数値書式指定文字列からの変換
□投稿者/ ゆい (28回)-(2021/03/10(Wed) 22:57:04)
No96982 (Hongliang さん) に返信

ありがとうございます。

String.Format("{0:f13}", s)をウオッチしますとその値は 0.00008035501とはなります。
そこでその値を s に代入しようとすればどのようにすれば良いのでしょう?


> 2021/03/10(Wed) 19:25:54 編集(投稿者)
>
> 変換は可能です。
> Single/Doubleに変換後、さらにそれを表示させるなどのために文字列化する際、
> e-5以上の場合に指数表記されるの仕様ですね。
>
> Dim s As Single = Single.Parse("8.0355015e-05")
> Trace.WriteLine(s) ' 8.035501E-05
> Trace.WriteLine(String.Format("{0:f13}", s)) ' 0.0000803550138
引用返信 編集キー/
■96986 / inTopicNo.7)  Re[4]: 数値書式指定文字列からの変換
□投稿者/ ゆい (29回)-(2021/03/10(Wed) 23:03:09)
No96984 (魔界の仮面弁士 さん) に返信

詳しくありがとうございます。

今は全体の中での割合として求めるため、精度についてはそれほどは必要とはしてないのです。
また何故このような仕様になってるかは、あるソフトの出力に因るものです。

引用返信 編集キー/
■96987 / inTopicNo.8)  Re[5]: 数値書式指定文字列からの変換
□投稿者/ 魔界の仮面弁士 (3002回)-(2021/03/10(Wed) 23:35:13)
2021/03/10(Wed) 23:36:23 編集(投稿者)

No96986 (ゆい さん) に返信
> 今は全体の中での割合として求めるため、精度についてはそれほどは必要とはしてないのです。
> また何故このような仕様になってるかは、あるソフトの出力に因るものです。

ならば、「あるソフト」側が Single 精度ならば Single を使えばよいですし、
Double 精度ならば Double を使えば良いということになります。
それを超える桁は誤差の範囲ですね。


また、ウォッチで見える表現は、内部値を表現するための見え方の一つに過ぎないので、
書式と実際の値は分けて考えてましょう。


下記はそれぞれ、10進数、16進数、8進数で代入していますが、
実際に代入される値は、いずれも同じ値です。

Dim a As Integer = 123
Dim b As Integer = &H7B
Dim c As Integer = &O173


同じ値であっても、書式指定で
10進数にしたり指数表記にしたりできます。

Dim s1 As String = a.ToString("N0")
Dim s2 As String = a.ToString("E2")


Single や Double も同様に、String.Format や ToString を使って書式指定できます。
使用可能な書式はリファレンスで確認してみてください。
(書式指定が間違っていると、実行時にエラーになります)

Dim d As Single = …
Dim s1 As String = d.ToString("N20")
Dim s2 As String = d.ToString("F20")
Dim s3 As String = d.ToString("R")
Dim s4 As String = d.ToString("G")
Dim s5 As String = d.ToString("0.0000E+00")


VB2015 以降では、 $ で始まる「補間文字列」での記述もできます。
https://docs.microsoft.com/ja-jp/dotnet/visual-basic/programming-guide/language-features/strings/interpolated-strings

Dim d As Single = …
Dim x1 As String = $"{d:N20}"
Dim x2 As String = $"{d:F20}"
Dim x3 As String = $"{d:R}"
Dim x4 As String = $"{d:G}"
Dim x5 As String = $"{d:0.0000E+00}"
引用返信 編集キー/
■96988 / inTopicNo.9)  Re[6]: 数値書式指定文字列からの変換
□投稿者/ ゆい (30回)-(2021/03/11(Thu) 01:05:43)
No96987 (魔界の仮面弁士 さん) に返信

ありがとうございます。

色々あるのですね。
解決しました

解決済み
引用返信 編集キー/
■96989 / inTopicNo.10)  Re[6]: 数値書式指定文字列からの変換
□投稿者/ ゆい (31回)-(2021/03/11(Thu) 10:01:37)
No96987 (魔界の仮面弁士 さん) に返信

すみません、解決済みにはしてしまいましたが・・
下のように事前に作って於いた配列t(0)に代入は出来ないのですね?

Dim t(10) As Single
Dim d As Single = "4.2444972e-07"
Dim s1 As String = d.ToString("N20")
t(0) = s1
引用返信 編集キー/
■96990 / inTopicNo.11)  Re[7]: 数値書式指定文字列からの変換
□投稿者/ shu (1245回)-(2021/03/11(Thu) 11:10:59)
No96989 (ゆい さん) に返信
> ■No96987 (魔界の仮面弁士 さん) に返信
>
> すみません、解決済みにはしてしまいましたが・・
> 下のように事前に作って於いた配列t(0)に代入は出来ないのですね?
>
> Dim t(10) As Single
> Dim d As Single = "4.2444972e-07"
> Dim s1 As String = d.ToString("N20")
> t(0) = s1
コンパイルの設定によってはこのまま記述も可能ですが
Dim d As Single = CSng("4.2444972e-07")
Dim s1 As String = d.ToString("N20")
t(0) = CSng(s1)
とSingleに変換することを明記した方が良いです。
この場合
t(0) = d
とした方が誤差の発生を軽減することができます。


引用返信 編集キー/
■96991 / inTopicNo.12)  Re[8]: 数値書式指定文字列からの変換
□投稿者/ ゆい (32回)-(2021/03/11(Thu) 11:46:53)
No96990 (shu さん) に返信

ありがとうございます。

> Dim d As Single = CSng("4.2444972e-07")
> Dim s1 As String = d.ToString("N20")
> t(0) = CSng(s1)
このようにしても t(0)の値は4.244497E-07にはなりませんか?
"0.00000042444970000000"にしたいのです。

> この場合
> t(0) = d
> とした方が誤差の発生を軽減することができます。
これは t(0) = CSng(s1)を t(0) = dに変えるとのことでしょうか?
引用返信 編集キー/
■96992 / inTopicNo.13)  Re[7]: 数値書式指定文字列からの変換
□投稿者/ 魔界の仮面弁士 (3003回)-(2021/03/11(Thu) 11:55:42)
No96989 (ゆい さん) に返信
> Dim t(10) As Single
> Dim d As Single = "4.2444972e-07"
> Dim s1 As String = d.ToString("N20")
> t(0) = s1

t(0) = CSng(s1)
とすれば格納できますが、計算の途中で数値と文字列を相互変換すると誤差が累積します。

数値は数値のまま扱ってください。
t(0) = d


たとえば下記の場合、x と z は異なる値になってしまいます。

Dim x As Single = CSng("4.2444972e-07")
Dim y As String = x.ToString("N20")
Dim z As Single = CSng(y)


データの表示が目的なのではなく、データの保持が目的なのであれば、
 Dim y As String = x.ToString("R")
のように書くことができます。
"R" 書式で出力した文字列であれば、その後で数値に戻した時に、
元の値に完全に復元できることが保証されています。

上記の "R" 書式は、
Single 型では "G9" 書式に相当し、
Double 型では "G17" 書式に相当します。

"G" 書式は、固定小数点表記または指数表記のうち、
いずれかのより簡潔な形式で出力される仕様なので、
実際の値によって表記法が揺れます。

そのため、"R" や "G" は文字列化して保存するためには適していますが、
人間に読ませるために使うにはあまり適していません。

"N" や "E" はその逆で、書式が固定されるので読みやすいですが、
値としては不正確になります。
引用返信 編集キー/
■96993 / inTopicNo.14)  Re[9]: 数値書式指定文字列からの変換
□投稿者/ 魔界の仮面弁士 (3004回)-(2021/03/11(Thu) 12:03:40)
No96991 (ゆい さん) に返信
>>Dim d As Single = CSng("4.2444972e-07")
>>Dim s1 As String = d.ToString("N20")
>>t(0) = CSng(s1)
> このようにしても t(0)の値は4.244497E-07にはなりませんか?
> "0.00000042444970000000"にしたいのです。

数値と数字を混同していませんか?


先にも述べましたが、「実際に保存されている数値」と
「それを書式化して文字列化した表現」は別です。

たとえば今日の日付を「令和3年」と表記したり、「2021年」と表記したりできますが、
実際の日付値が変わるわけでは無いですよね。


文字列として表示されているそれは、内部値を表現するための見え方の一つに過ぎません。


そもそも、Single や Double は 二進小数として管理されていますので、
十進小数との完全な相互変換ができるわけではありません。

たとえば、10 進数の 0.1 (1÷10)という値は、2 進数では無限小数になってしまい、
有限の桁数では表記しきれず、打切り誤差が生まれます。


もしも、10進数としての
 "0.00000042444970000000"
であることを保証したいのであれば、 No96984 でも示したように
Decimal 型の利用を検討してみてください。
Decimal は 2 進小数ではなく 10 進小数として管理されるデータ型です。
引用返信 編集キー/
■96994 / inTopicNo.15)  Re[9]: 数値書式指定文字列からの変換
□投稿者/ 魔界の仮面弁士 (3005回)-(2021/03/11(Thu) 12:32:48)
No96991 (ゆい さん) に返信
>>Dim d As Single = CSng("4.2444972e-07")
>>Dim s1 As String = d.ToString("N20")
>>t(0) = CSng(s1)
> このようにしても t(0)の値は4.244497E-07にはなりませんか?
> "0.00000042444970000000"にしたいのです。

デバッガで見えている表現は、先の R 書式相当の見え方です。

そもそも Single 型では「0.00000042444970000000」と
完全に一致する値を作り出すことができません。Decimal なら可能ですが。

Single にとって、4.244497E-07 というのはあくまで近似値であり、実際には
 0.00000042444970000000
ではなく、内部的にはそれよりもほんの少し小さな
 0.0000004244496949468157254159450531005859375
に相当する値となります。


Single 型の内部バイナリ表現            画面上の表示例   バイナリ表現を精度桁で打ち切らず算出した結果
------------------------------------   --------------   --------------------------------------------
[0 01101001 11000111101111111101011]   4.24449667E-07   4.24449666525106295011937618255615234375e-7
[0 01101001 11000111101111111101100]   4.244497E-07     4.244496949468157254159450531005859375e-7
[0 01101001 11000111101111111101101]   4.24449723E-07   4.24449723368525155819952487945556640625e-7

引用返信 編集キー/
■96995 / inTopicNo.16)  Re[10]: 数値書式指定文字列からの変換
□投稿者/ 魔界の仮面弁士 (3006回)-(2021/03/11(Thu) 12:40:36)
2021/03/11(Thu) 12:49:13 編集(投稿者)

No96994 (魔界の仮面弁士) に追記

Single や Double は「2 進小数」なので、
「1 ÷ 2」(0.50) や
「1 ÷ 4」(0.25) であれば、正確に表せます。

しかし「1 ÷ 3」や「1 ÷ 10」などについては、
二進小数として十分な桁数が確保できず、
近似値として保持されることになります。


No96984No96994 では、それらの 2進小数を
10進小数表現に置き換えて見せていますが、
それぞれの小数部の末尾部分が、00 / 25 / 50 / 75 の
いずれかになっていますよね。元が2進数だったからです。


繰り返しになりますが、10 進小数として扱うことに
主眼を置くのであれば、Decimal 型を使いましょう。

Decimal であっても、格納誤差や演算誤差の発生は避けきれませんが、
少なくとも 10進小数表現との変換差異を防ぐことはできます。
引用返信 編集キー/
■96996 / inTopicNo.17)  Re[11]: 数値書式指定文字列からの変換
□投稿者/ 774RR (861回)-(2021/03/11(Thu) 13:06:24)
んでもって Decimal は double より圧倒的に演算速度が遅いので
・そもそもの文字列表記した値が測定値などであって原理的に誤差を含んでいる
のであれば Decimal を使う理由が1つもないのには注意

金額などで1銭でもずれが生じたらまずい場合などに限定して Decimal を使いたい
引用返信 編集キー/
■96997 / inTopicNo.18)  Re[9]: 数値書式指定文字列からの変換
□投稿者/ 大谷刑部 (135回)-(2021/03/11(Thu) 14:34:46)
No96991 (ゆい さん) に返信
> ■No96990 (shu さん) に返信
>
> ありがとうございます。
>
>>Dim d As Single = CSng("4.2444972e-07")
>>Dim s1 As String = d.ToString("N20")
>>t(0) = CSng(s1)
> このようにしても t(0)の値は4.244497E-07にはなりませんか?
> "0.00000042444970000000"にしたいのです。

そもそも小数部に精度をもとめるならDecimal一択ですよ。
弁さんがおっしゃっているように、SingleもDoubleも2進数で保持してるので誤差が起こるのは必然です。
ただし、演算速度はSingle,Doubleの方が速いです。
なので地図の座標、それを応用した軍事目的の標的特定などは2進数で計算するのが適してますね。細部の精度より速度重視なので。
対して金融システムの計算は2進数型の使用は本来ご法度ですね。
現実の金融システムでSEの無知によりDoubleが多用されているのは案外見かけますが。

引用返信 編集キー/
■96998 / inTopicNo.19)  Re[11]: 数値書式指定文字列からの変換
□投稿者/ ゆい (33回)-(2021/03/11(Thu) 23:33:55)
No96995 (魔界の仮面弁士 さん) に返信

ありがとうございます。
まだ試せてないのもあるのですが今度こそ解決もしましたのでホントうれしいです。
また教えてくださいね。
お願いします。

解決済み
引用返信 編集キー/
■96999 / inTopicNo.20)  Re[12]: 数値書式指定文字列からの変換
 
□投稿者/ ゆい (34回)-(2021/03/11(Thu) 23:36:33)
No96996 (774RR さん) に返信

ありがとうございます。


解決済み
引用返信 編集キー/

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

次の20件>
トピック内ページ移動 / << 0 | 1 >>

管理者用

- Child Tree -