参考書を見ると、.NETには数値として扱える文字列を自動的に変換する機能があるが、文字列から数値への変換を行っていないと思わぬ結果を招くことがあると書いてあり、そのようにならないためにも文字列から数値への変換にはVal関数を使うと良いとなっています。
今回、台形の面積を求めるプログラムで
コード①
Private Sub Button1_Click(ByVal sender..省略) Handles Button1.Click
TextBox4.Text = (TextBox1.Text + TextBox2.Text) * TextBox3.Text / 2 End Sub
としTextBox1.Text に3,TextBox2.Textに7,TextBox3.Text に5を入れて
計算させたところ92.5となってしまいました。(正解は25)
textBox4.text以下を(Val(TextBox1.Text) +Val(TextBox2.Text)) *Val(TextBox3.Text) / 2
と書き直せば答えは25になります。
ところで
コード②
Private Sub Button1_Click(ByVal sender..省略) Handles Button1.Click
Dim a, b, c As Double
a = TextBox1.Text
b = TextBox2.Text
c = TextBox3.Text
TextBox4.Text = (a + b) * c / 2
とし、各TextBoxにコード①と同じ値をそれぞれ代入し計算させると、ここではVal関数を使っていないのですが、25と正解になります。
私は、コード②が正解を出すのは変数を宣言しているため、textBoxに入力された数字(例えば3)の文字列が変数に代入されるとき数値として認識してするのかと思いました。このような理解の仕方で宜しいのでしょうか?また、コード①では、.NETはTextBox1.TextとTextBox2.Textに入力された数字を足し算したのではなく数字をくっつけてしまい37×5÷2と計算したようです。皆様も同じような経験をされた方はいらっしゃいまっせんでしょうか?もし、ありましたら今後の参考までに教えてくださると幸いです。
> 文字列から数値への変換を行っていないと思わぬ結果を招くことがある
たとえば、
Dim d As Double
d = 11 + 11 +"11"
d ="11"+"11"+ 11
の場合、前者は 33、後者は 1122 になりますが、これが「思わぬ結果」の
一つといえるかも知れません。
# 上記を(実行せずに)正解を言い当てられる程の知識を持った人なら、
# このような曖昧なコードは書きませんしね。
> 文字列から数値への変換にはVal関数を使うと良いとなっています。
それでは、処理として甘過ぎです。Val だけ使えば済む物でもありません。
Val関数を使う前に、「数値として変換可能な文字列であるかどうか」を
判断するためのコードを書くようにしましょう。
たとえば、
d = Val("1234567890%")
d = Val("12.5&")
といったコードでは、前者はオーバーフローのエラーになりますし、
後者では型変換エラーとなってしまいます。
もし、数値のみの入力を求めるのであれば、TextBox.Text の代わりに、
NumericUpDown.Value の利用を検討してみてください。最初から数値型で
値を得る事ができますし、値の最大/最小値も定義できますから、
入力チェックの手間が省けます。
> と書き直せば答えは25になります。
「+ 演算子」の両端が『文字列型』であったため、
> (TextBox1.Text + TextBox2.Text)
というコードが、
(TextBox1.Text & TextBox2.Text)
として解釈されるためです。
# 演算子の型変換に関する資料はヘルプに幾つか書かれています。
で、こうした予期せぬ誤計算を防ぐためにも、
・「+演算子」で文字列型を繋がない。繋ぐなら「&演算子」を使う。
・「+演算子」の両端が、常に数値型になるようにする。
を守るようにすると良いでしょう。
# さらに、「+演算子」の両端を同じデータ型にしておくと、より確実。
ちなみに、このあたりの話は、VB.NET に限った事ではなく、旧バージョンの
Visual Basic に対しても言えることです。
魔界の仮面弁士さんへ>
ご指導ありがとうございました。ご指摘を受け、コードを次のように書き換えて見ました。(問題は、今までと同じ台形の面積です。)
コード③
Private Sub Button1_Click(ByVal sen...省略) Handles Button1.Click
Dim a, b, c As Double
a = zyoutei.Value
b = katei.Value
c = takasa.Value
TextBox1.Text = (a + b) * c / 2
>最初から数値型で数値を得る事ができますし、値の最大/最小値も定義で
きますから、入力チェックの手間が省けます。
今回の場合では私が以前に書いたコード②では、負の数でも可能なので厳格にするのであれば、コードに上底、下底。高さのいずれか一つでも負の数では答えが出ないというプログラムが必要になるのに対し、コード③では最小値を0にするだけで良いという利点があると理解しました。(ただ、実際にわざわざ負の数を入れて計算しようと思う人はいないと思いますが・・・)
魔界の仮面弁士さんへ>
上記のような理解の仕方でよろしいでしょうか?確認をお願い致します。
>> Val関数を使う前に、「数値として変換可能な文字列であるかどうか」を
ちなみにこれは、Val 以外の物を使って型変換した場合にも言えることです。
なお、先のエラーの件以外にも
Val("246D-1型") → 24.6
Val("&o 12 75") → 701.0
のように、予期しにくい結果を生むこともあったりします。
> 最小値を0にするだけで良いという利点があると理解しました。
そうですね。
そして NumericUpDown の最大の利点は、戻り値の型が常に「数値型」なので、
数値チェックや型変換の必要が無い点が挙げられるかと思います。
(他にも 小数点以下の桁数を指定したり、3桁ごとに「,」を打ったりもできます)
> Dim a, b, c As Double
> a = zyoutei.Value
残念ながら、これではまだ不足です。
ヘルプ等で確認していただくとわかるかと思いますが、
NumericUpDown の Value プロパティのデータ型は、
Double型 ではなく、Decimal 型となっていますので、
この場合は、変数を「As Decimal」で定義してください。
# こうした型のずれを防ぐためには、Option Strict On という機能を使います。
ちなみに Double 型は誤差を含む型なので、計算時には注意が必要です。
たとえば下記のコードを実行すると、「不一致」と表示されます。
Dim A As Double = 123.4
Dim B As Double = 123.3
If (A - B) = 0.1 Then
TextBox1.Text = "一致"
Else
TextBox1.Text = "不一致"
End If
そして、変数を Decimal 型にしている場合は、上記は「一致」と表示されます。
>(ただ、実際にわざわざ負の数を入れて計算しようと思う人はいないと思いますが・・・)
入れようとして入る事は無くても、誤操作(コピー/貼り付け時のミス、
キー操作ミス)によって入ってしまう可能性も考慮して、「念のため」に
対処しておいた方が安全です。
また負数以外にも、「極端に大きな値」「全角数字」などを拒絶する意味でも、
計算前の値チェックは必要なことと言えるでしょう。
> 魔界の仮面弁士さんへ>
う〜ん。他の人が発言(追加回答、補足など)をしにくくなってしまいますので、
名指しでの回答依頼は、できれば避けていただけるとありがたいです。(^^;
適切な指導ありがとうございます。また、先ほどは失礼致しました。今後は気をつけます。
>こうした型のずれを防ぐためには、Option Strict On という機能を使います。
この機能をつけましたらコード③が次のように書き換わりました。
コード④
Option Strict On
Public Class Form1
Inherits System.Windows.Forms.Form
(省略)
Private Sub Button1_Click(ByVal sen...省略) Handles Button1.Click
Dim a, b As Decimal
a = nudHankei.Value
b = CDec(4 * a ^ 2 * Math.PI)
TextBox1.Text = CStr(b)
TextBox2.Text = CStr(b * a / 3)
End Sub
End Class
CDec(数値から10進型の変換),CStr(数値または日付型の値から文字列型の変換)のデータ型の変換を行う関数を使う必要が出てくることが分かりました。
>ちなみに Double 型は誤差を含む型なので、計算時には注意が必要です。
たとえば下記のコードを実行すると、「不一致」と表示されます。(省略)
そして、変数を Decimal 型にしている場合は、上記は「一致」と表示されます。
VB.NETのヘルプ、Visual Basic 言語の概念 非整数型を参照することで理解出来ました。Decimal 型は誤差の許されない計算に適しているとの記載がありました。
訂正箇所があります。
コード④ですが、球の表面積と体積を求める問題のコードです。コードを間違えてしまい申し訳ありません。
Option Strict Onにしたあと、データ型の変換を行う関数を使用する必要があることを理解しました。
ツイート | ![]() |