単位換算プログラム~PPコンバータ~


はじめに

皆さんはじめまして。
化学を専門に勉強している学生がプログラミングに手を出してみました。

今回作成したプログラムは科学分野で広く"濃度"の単位として用いられている"Parts Par表記の相互換算を行うプログラムです。

Parts Par 表記とは

Parts Par表記は厳密には"無次元数"と呼ばれる単位で、全体に対して目的としている物がどの程度の割合で存在しているかを表しています。

存在している割合が
百万分の一ならparts par million(ppm)
十億分の一ならparts par billion(ppb)
一兆分の一ならparts par trillion(ppt)
千兆分の一ならparts par quadrillion(ppq)
になります。

作成した背景

同級生に単位換算が苦手な学生がおり、検算を頼まれた時に「これ、プログラムにしてしまえば手っ取り早いのでは?」と思ったため。

ただし、パソコンが近くにない場合やパソコンが起動していない場合だと余計な手間がかかってしまうのが問題ですね。

今回の作成環境

Microsoft Visual Studio
VisualBasic Windows フォームアプリケーション(.NET Framework)

フォームデザインと使い方

フォームデザイン

使い方

1.いずれかのテキストボックスに数値を入力
2.コンボボックスから変換元の濃度を指定
3.コンバートボタンで変換を実行
4.他のテキストボックスへ結果を出力

ソースコードの解説

各種定義部

・具体的な値を処理する変数では、桁数の大きい小数を取り扱うのでDouble(倍精度浮動小数型)で定義しました。
・String(文字列型)で濃度の名前(4つ分)とエラーメッセージを取り扱う変数をそれぞれ定義しました。
・変換元のデータの判定結果を格納する"ric"とエラー時に利用するための"conti"を定義します。これらに入る数値は整数なのでInteger(整数型)で定義。
(以降まとめて話す場合には"管理用変数"と表記します。)
・メッセージボックスの書式を決定するためのStyle_crをMsgBoxStyleで定義しました。

初期化操作用のSubプロシージャ

Text All ClearなのでTACL()という名前になっています。

Form1ロード時の処理

初期化用のSubプロシージャをTACL()で呼び出して、各テキストボックスを空欄にして、管理用変数を0にします。

次に、濃度の名前を配列"concentration"にそれぞれ入力します。

配列に入れた濃度名をFor文を使ってコンボボックスに登録していきます。
この方法は複数のコンボボックスに同じ内容を登録する際に重宝します。

メッセージボックスの書式設定では次の内容を規定しています。
・クリティカル(赤い×印のアイコンのメッセージボックス)
・アプリケーションモーダル(ユーザーがメッセージボックスに何らかのリアクションをしない限り、前の画面に戻らせないようにする)
・メッセージボックスセットフォアグラウンド(表示するメッセージボックスを最前面に表示せよ)
・システムモーダル(ユーザーがメッセージボックスに何らかのリアクションをしない限り、プログラムの処理を再開させないようにする)

ボタン1(コンバートボタン)での処理

この部分で、コンボボックスの中身をSelect Caseを用いて判断しています。

以下、指定の濃度別に計算処理を行っていきます。

ppmでの計算を例に解説します。

まずはじめにcalにテキストボックス1の文字列をVal(数値)として取り込みます。

次に正規化処理を行い、0~9と小数以外の文字列の有無を判定します。
規定文字列以外が含まれている場合、0以下の数値の場合には
"適切な数値を入力してください。"
"エラー内容:未入力、非数値、0以下の数値の入力"
のメッセージを表示し、contiの値を0にします。

入力された文字列に問題がない場合には、contiを1とし、計算用Subプロシージャに飛びます。

計算処理用のSubプロシージャ

CalculationなのでCA()という名前になっています。

入力された値がconに格納されています。

If文を用いて、conの値が10以上であるか、1以下であるかを判定します。
これは、科学的な計算のルールである有効数字というものを考慮するための処理です。

0以上1以下の数字の部分(係数)と10の累乗の形で表記することで、何桁目までが正確な値かが分かります。
(例:120.3 cmのロープを10 cm刻みの定規で測ると1.2×10^2 cmとなり、1 cm刻みの定規ではかると1.203×10^2 cmとなります)

calc(1)に10の何乗か(指数)を格納します。
conの値が10以上ならば、10で割って、指数を+1します。
conの値が1未満ならば、10を掛けて、指数を-1します。

また、calc(2)に係数を格納します。

ボタン1(コンバートボタン)での処理(続き)

次にそれぞれの濃度になるように指数部分を調整します。
ppm=10^(-6)、ppb=10^(-9)、よってppmからppbへは10^(3)大きな値になります。そのためcalc(1)に3を足します。

それぞれ指数の調整が完了したら、係数と指数を掛け合わせて各テキストボックスへ出力します。

また、contiが0の場合には、テキストボックス1~4に"Error"と出力するように以下のSubプロシージャを呼び出しています。

ボタン1(コンバートボタン)での処理(続き)

以下同様に各濃度での処理を行っていきます。


なお、変換元のデータが規定されていない場合には、次のプログラムでエラーメッセージを出力します。

ボタン2(クリアボタン)での処理

初期化SubプロシージャをTACL()で呼び出しています。

ボタン3(終了ボタン)での処理

Me.Close()でプログラムを終了しています。

ソースコード全体

Public Class Form1

Dim con, calc(2) As Double 'データ引き込み用と計算用の入れ物
Dim concentration(3), er_msg As String '濃度指定の入れ物とエラーメッセージの入れ物
Dim ric, conti As Integer '行動管理用の入れ物
Dim style_cr As MsgBoxStyle 'メッセージ用の設定

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

    Select Case ComboBox1.Text '変換元のデータ指定

        Case concentration(0) 'ppm

            ric = 1

        Case concentration(1) 'ppb

            ric = 2

        Case concentration(2) 'ppt

            ric = 3

        Case concentration(3) 'ppq

            ric = 4

    End Select

    If ric = 1 Then 'ppm

        con = Val(TextBox1.Text)

        If Not (System.Text.RegularExpressions.Regex.IsMatch(TextBox1.Text, "[^0-9.]")) And con > 0 Then

            conti = 1

        Else

            conti = 0
            MsgBox(er_msg, style_cr, "処理不能な値")

        End If

        CA()

        TextBox2.Text = calc(2) * 10 ^ (calc(1) + 3) 'ppm => ppb
        TextBox3.Text = calc(2) * 10 ^ (calc(1) + 6) 'ppm => ppt
        TextBox4.Text = calc(2) * 10 ^ (calc(1) + 9) 'ppm => ppq
        con = 0

        If conti = 0 Then 'エラー時にエラーと表示させる

            ABAL()

        End If

    ElseIf ric = 2 Then 'ppb

        con = Val(TextBox2.Text)

        If Not (System.Text.RegularExpressions.Regex.IsMatch(TextBox2.Text, "[^0-9.]")) And con > 0 Then

            conti = 1

        Else

            conti = 0
            MsgBox(er_msg, style_cr, "処理不能な値")

        End If

        CA()

        TextBox1.Text = calc(2) * 10 ^ (calc(1) - 3) 'ppb => ppm
        TextBox3.Text = calc(2) * 10 ^ (calc(1) + 3) 'ppb => ppt
        TextBox4.Text = calc(2) * 10 ^ (calc(1) + 6) 'ppb => ppq
        con = 0

        If conti = 0 Then 'エラー時にエラーと表示させる

            ABAL()

        End If

    ElseIf ric = 3 Then 'ppt

        con = Val(TextBox3.Text)

        If Not (System.Text.RegularExpressions.Regex.IsMatch(TextBox3.Text, "[^0-9.]")) And con > 0 Then

            conti = 1

        Else

            conti = 0
            MsgBox(er_msg, style_cr, "処理不能な値")

        End If

        CA()

        TextBox1.Text = calc(2) * 10 ^ (calc(1) - 6) 'ppt => ppb
        TextBox2.Text = calc(2) * 10 ^ (calc(1) - 3) 'ppt => ppm
        TextBox4.Text = calc(2) * 10 ^ (calc(1) + 3) 'ppt => ppq
        con = 0

        If conti = 0 Then 'エラー時にエラーと表示させる

            ABAL()

        End If

    ElseIf ric = 4 Then 'ppq

        con = Val(TextBox4.Text)

        If Not (System.Text.RegularExpressions.Regex.IsMatch(TextBox4.Text, "[^0-9.]")) And con > 0 Then

            conti = 1

        Else

            conti = 0
            MsgBox(er_msg, style_cr, "処理不能な値")

        End If

        CA()

        TextBox1.Text = calc(2) * 10 ^ (calc(1) - 9) 'ppq => ppb
        TextBox2.Text = calc(2) * 10 ^ (calc(1) - 6) 'ppq => ppm
        TextBox3.Text = calc(2) * 10 ^ (calc(1) - 3) 'ppq => ppt
        con = 0

        If conti = 0 Then 'エラー時にエラーと表示させる

            ABAL()

        End If

    Else 'ric=0 つまり未選択

        MsgBox("変換元のデータが指定されていません", style_cr, "変換元不明")
        Exit Sub

    End If

End Sub

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

    TACL() '初期化操作

    concentration(0) = "ppm"
    concentration(1) = "ppb"
    concentration(2) = "ppt"
    concentration(3) = "ppq"

    For i = 0 To 3 Step 1 'コンボボックスにアイテムを追加する

        ComboBox1.Items.Add(concentration(i))

    Next i

    'メッセージボックスのスタイル設定
    style_cr = MsgBoxStyle.Critical Or MsgBoxStyle.ApplicationModal Or MsgBoxStyle.MsgBoxSetForeground Or MsgBoxStyle.SystemModal
    er_msg = "適切な数値を入力してください。" & vbCrLf & "エラー内容:未入力、非数値、0以下の数値の入力"

End Sub

Private Sub Button3_Click_1(sender As Object, e As EventArgs) Handles Button3.Click '終了ボタン

    Me.Close()

End Sub

Private Sub TACL() '初期化操作部

    TextBox1.Text = ""
    TextBox2.Text = ""
    TextBox3.Text = ""
    TextBox4.Text = ""
    ComboBox1.Text = "変換元の濃度を指定"

    con = 0
    ric = 0
    conti = 0

End Sub

Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click '初期化ボタン

    TACL()

End Sub

Private Sub CA() '計算処理部

    If con > 0 Then '桁数判断

        While con > 10 '10より大きいならば10で割って指数+1

            con /= 10
            calc(1) += 1

        End While

    Else

        While con >= 1 '1以下ならば10倍して指数-1

            con *= 10
            calc(1) -= 1

        End While

    End If

    calc(2) = con / 10 ^ (calc(1)) '係数の算出

End Sub

Private Sub ABAL() 'すべてのTextBoxにエラーと表示せよ

    TextBox1.Text = "Error"
    TextBox2.Text = "Error"
    TextBox3.Text = "Error"
    TextBox4.Text = "Error"

End Sub

End Class

最後に

久しぶりのプログラミングだったので、「あれ?ここのコードってどうやって書くんだったっけ?」となりました。

やっぱり書かないと忘れますね。特に正規化のあたりとか。

次回は規定濃度の溶液をこの量作るためには原液が何mL必要かを計算するプログラムや何倍希釈・濃縮なのかを計算するようなプログラムを作ろうかなと考えています。

このプログラムがいつの日か、どこかの誰かの役に立つといいな。