FormatPercent関数とSelect Case

タグの編集
投稿者 もも  (学生) 投稿日時 2011/11/19 10:02:24
成績をつけるプログラムを作成しています。
合計点数と満点をで割合を求め、FormatPercent関数でパーセントに変換させた後Select Caseでそれぞれ成績を振り分けるのですが、どうも思うように行きません。
まずコードを記載します。
      Dim Grade As Decimal
            Dim Total As Integer
            Dim Totalpossiblepoint As Integer = 800
            Dim FinalGrade As String
            Grade = (Total / Totalpossiblepoint)
Dim percentage As String
            percentage = FormatPercent(Grade, 0)
            MsgBox(percentage)←これはただの確認用です。

           ' 90%以上ならA、80-89%ならB、70-79%ならC、60-69%ならDに
            Select Case percentage
                Case Is >= 90
                    FinalGrade = "A"
                    PassAtoC()
                Case 80 To 89
                    FinalGrade = "B"
                    PassAtoC()
                Case 70 To 79
                    FinalGrade = "C"
                    PassAtoC()
                Case 60 To 69
                    FinalGrade = "D"
                    PassD()
                Case Else
                    FinalGrade = "F"
                    Failed()
            End Select

点数の割合が各成績の間に位置すると、「その他」としてF表示になるのです。
例えば得点が715点、満点が800点だとすると、89.37%になり、整数に四捨五入すると89%になりますが、Fが表示されます。これが88%ならば普通にBになるのですが。
いろいろ試したところ、
100%=F
99%=A
90%=A
89%=F
80%=B
79%=F
となりました。

80 To 89は80<>89を意味しているのかと思いましたが、そうでもない? それともこれは80>=, <89となっているのでしょうか?
どうしてこうなっているのか、どうすればよいのか教えてください。
投稿者 るきお  (社会人) 投稿日時 2011/11/19 12:09:44
第一印象では端数がうまく処理できていないのかなと思いました。
たとえば、89.5など。

値の確認方法は確認用のMsgBoxでしょうか?であれば「%」はつかないと思います。細かい指摘のように思うかもしれませんが、細かい値の話をしているので重要です。
また、percentageは何型でしょうか?

ちゃんと考えるには情報が足りないです。

すぐに実行して試せるコードを載せてもらうのが一番回答しやすいです。
長くなるようであればできるだけ短くしてみてください。(そして、この短くする過程で原因に自分で気が付くこともよくあります。)

>80 To 89は80<>89を意味しているのかと思いましたが、そうでもない?
80<>89の意味が正確にわかりません。80 To 89は「80以上かつ89以下」という意味です。
投稿者 もも  (学生) 投稿日時 2011/11/19 13:06:49
回答有難うございます。
るきおさん
>80<>89の意味が正確にわかりません。80 To 89は「80以上かつ89以下」という意味です。
ごめんなさい。80から89の間だけど80と89は含まず、という意味です。つまり80.1から88.9の間が適用範囲なのか、と思ったのですが、80(%)ではきちんとB判定が出ました。この80も80.00と、80ちょうどのものです。ですので、「80>=, <89」つまり80.0を含んだ80.0から88.9が範囲なのか?と思いました。でもそんなことはない・・・ですよね。

>値の確認方法は確認用のMsgBoxでしょうか?であれば「%」はつかないと思います。
はい。値の確認用ですが、「であれば「%」はつかないと思います。」とはどういった意味でしょうか?
メッセージに%がつかない、という意味であれば、一応きちんと「%」はついてます。
それとも、メッセージにはきちんと「%」で表示されているけれど、厳密に言えば何かが違うのでしょうか?

>また、percentageは何型でしょうか?
最初は GradeがDecimal型でもあるためDecimal型として宣言していたのですが、InvalidCastExceptionエラーが出るためStringにしています。
私が見たFormatPercent関数を扱っているサイトの全てがStringで宣言していたのですが、FormatPercent関数は文字列にしか出来ないのでしょうか?


投稿者 もも  (学生) 投稿日時 2011/11/19 13:18:33
コード忘れてました。 使用するものはテキストボックス8個とラベル1個とボタン1個です。

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        'Declare i, Item(Socores),Grade Total, Totalpossiblepoint, and FinalGrade
        Dim Item() As Integer = {Textbox1.Text, Textbox2.Text, Textbox3.Text, Textbox4.Text, Textbox5.Text, Textbox6.Text, MidExam.Text, FinalExam.Text}
        Dim Grade As Decimal
        Dim Total As Integer
        Dim Totalpossiblepoint As Integer = 800
        Dim FinalGrade As String
        Dim i As Integer
        'Culculate the Scores
        For i = 0 To 7
            Total += Item(i)
        Next

        Grade = (Total / Totalpossiblepoint)

        ' Convert to Percentage
        Dim percentage As Integer
        percentage = FormatPercent(Grade, 0)
        MsgBox(percentage)
        'Define the Final Grade
        Select Case percentage
            Case Is >= 90%
                FinalGrade = "A"
                PassAtoC()
            Case 80% To 89%
                FinalGrade = "B"
                PassAtoC()
            Case 70% To 79%
                FinalGrade = "C"
                PassAtoC()
            Case 60% To 69%
                FinalGrade = "D"
                PassD()
            Case Else
                FinalGrade = "F"
                Failed()
        End Select
        Gradelbl.Text = FinalGrade

    End Sub

 Private Sub PassAtoC()
        'If FinalGrade is A to C, color is Green
        Gradelbl.ForeColor = Color.Green
    End Sub
    Private Sub PassD()
        'If FinalGrade is D, color is Orenge
        Gradelbl.ForeColor = Color.Orange
    End Sub
    Private Sub Failed()
        'If FinalGrade is F, color is red
        Gradelbl.ForeColor = Color.Red
    End Sub
投稿者 るきお  (社会人) 投稿日時 2011/11/19 13:23:38
だいたい状況がわかりました。
percentageが文字列というところがポイントです。

値の後ろについている「%」にはVBとしては特別な意味はなく、「A」や「B」などと同じ文字列の一つとみなされます。つまり、ももさんのやりかたでは数値としての比較はされていなくて文字列としての比較が行われています。

つまり、どんな理屈が働いているか例を挙げながら説明すると、
・A < B → True
・A < AA → True (辞書に載るとしたら A は AA より前に載るという発想)
・A < A% → True (同上。% は A や B と同じ何の意味もない文字)
・10 < 10% → True

この発想だと、
100%=F → 「1」から始まる項目は「90」よりもかなり前に載ります。(辞書の先頭の方に載ります。)
99%=A →「99%」は「90」より後ろに載ります。
90%=A→「90%」は「90」より後ろに載ります。
89%=F→「89%」は「90」より前に載ります。「89」よりは後ろに載ります。該当がないのでElseに行きます。
という具合です。

数値比較をする場合はIntegerやDecimalなど数値型で扱うようにするのが良いです。
「%」をつけたりというのは見かけ上の要望で合って、見かけが問題になるのは画面に表示したり印刷したりするときだけです。つまり、画面表示の時や印刷の時に % をつけるべきで、それ以前の計算や比較・判定のロジックの中で % がついているのはむしろ邪魔になります。

投稿者 るきお  (社会人) 投稿日時 2011/11/19 13:28:36
書き込み中にコードが投稿されましたので、前の私の書き込みはコードを見る以前の情報で書いています。

理屈は変わりませんが、
コードではpercentageがIntegerになっていますね。
>InvalidCastExceptionエラーが出るためStringにしています。
とありますが、コードの方がなにかの間違いでしょうか?
投稿者 もも  (学生) 投稿日時 2011/11/19 14:47:57
るきおさん、またしてもごめんなさい。
確認するためIntegerに変えてエラーを確認後、それを投稿してしまったようです。
本来はStringです。

つまりSelect Case内に書いてある「%」は消したほうがいいということですね。
また、よく考えてみるとこのプログラムに限って言えば101%など100以上になることはありえないので、A判定の部分の上限を決めてしまえばよかったですよね。
判定の部分のコードをFormatPercent関数を使わず下のようにしてみるときちんと判定されることを確認しました。

  Grade = (Total / Totalpossiblepoint) * 100

            ' Convert to Percentage
             Grade = Convert.ToInt16(Grade)
            MsgBox(Grade)

            'Define the Final Grade
            Select Case Grade
                Case 90 To 100
                    FinalGrade = "A"
                    PassAtoC()
                Case 80 To 89
                    FinalGrade = "B"
                    PassAtoC()
                Case 70 To 79
                    FinalGrade = "C"
                    PassAtoC()
                Case 60 To 69
                    FinalGrade = "D"
                    PassD()
                Case Else
                    FinalGrade = "F"
                    Failed()
            End Select

Grade = (Total / Totalpossiblepoint) * 100
のように100倍して整数に変換すれば、その後のSelect Caseでもきちんと動くようになってくれました。
余談ですが、「整数」といいましたが、Integerが選択可能項目なかったのでInt16を使用しましたが、Int16はIntegerの一種でしたでしょうか?結果的に動いてるわけですが・・・。

しかしFormatPercent関数を使用した場合も気になるのでもう少しお付き合い願います。
投稿者 shu  (社会人) 投稿日時 2011/11/21 08:05:55
Int16は整数の一種ですが16ビットなので-32768~32767の範囲になります。
IntegerはInt32と同じになります。


> しかしFormatPercent関数を使用した場合も気になるのでもう少しお付き合い願います。
この関数は文字列として書式化するためのものなのでここではあまり有効ではないです。
投稿者 もも  (学生) 投稿日時 2011/11/29 12:49:04
shuさん
お返事遅くなりました。
>この関数は文字列として書式化するためのものなのでここではあまり有効ではないです
そうだったんですか。わかりました、有難うございました。