【AutoIt】割引計算と、元の値段の逆引きができる計算機を作る

お店での買い物で「15% 引き」と書かれている時、実際の値段はいくらになるのか?あるいは、割引後の値段を見て「元の値段はいくらだったんだろう?」と気になることはありませんか?

今回は、AutoIt を使って、これら2つの日常的な計算を簡単に行える、便利な割引計算ツールの作り方を解説します。

割引計算機
割引計算機
目次

完成したスクリプトの全コード(基本編)

#include <GUIConstantsEx.au3>

; ### GUIの定義 ###
Local $hGUI = GUICreate("割引計算機", 340, 260)

; --- 割引後の値段を計算するグループ ---
GUICtrlCreateGroup("「X円のY%引き」を計算", 10, 10, 320, 110)
GUICtrlCreateLabel("元の値段:", 20, 35, 80, 20)
Local $idInput_Original = GUICtrlCreateInput("", 100, 30, 120, 25)
GUICtrlCreateLabel("割引率 (%):", 20, 65, 80, 20)
Local $idInput_Discount1 = GUICtrlCreateInput("15", 100, 60, 50, 25)
Local $idBtn_CalcDiscount = GUICtrlCreateButton("計算", 160, 60, 60, 25)
Local $idInput_Result1 = GUICtrlCreateInput("", 230, 30, 90, 55)
GUICtrlSetFont(-1, 12, 800)
GUICtrlSetState(-1, $GUI_DISABLE) ; 結果表示欄は編集不可に
GUICtrlCreateGroup("", -99, -99, 1, 1)

; --- 元の値段を計算するグループ ---
GUICtrlCreateGroup("「X%引きでY円」の元の値段を計算", 10, 130, 320, 110)
GUICtrlCreateLabel("割引後の値段:", 20, 155, 80, 20)
Local $idInput_Discounted = GUICtrlCreateInput("", 100, 150, 120, 25)
GUICtrlCreateLabel("割引率 (%):", 20, 185, 80, 20)
Local $idInput_Discount2 = GUICtrlCreateInput("15", 100, 180, 50, 25)
Local $idBtn_CalcOriginal = GUICtrlCreateButton("計算", 160, 180, 60, 25)
Local $idInput_Result2 = GUICtrlCreateInput("", 230, 150, 90, 55)
GUICtrlSetFont(-1, 12, 800)
GUICtrlSetState(-1, $GUI_DISABLE)
GUICtrlCreateGroup("", -99, -99, 1, 1)

GUISetState(@SW_SHOW)

; ### メインループ ###
While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            ExitLoop

        Case $idBtn_CalcDiscount ; 「Y%引きはいくら?」の計算
            Local $fOriginal = Number(GUICtrlRead($idInput_Original))
            Local $fDiscount = Number(GUICtrlRead($idInput_Discount1))
            If $fOriginal > 0 And $fDiscount > 0 Then
                Local $fResult = $fOriginal * (1 - ($fDiscount / 100))
                GUICtrlSetData($idInput_Result1, Round($fResult))
            EndIf

        Case $idBtn_CalcOriginal ; 「元の値段はいくら?」の計算
            Local $fDiscounted = Number(GUICtrlRead($idInput_Discounted))
            Local $fDiscount = Number(GUICtrlRead($idInput_Discount2))
            If $fDiscounted > 0 And $fDiscount > 0 And $fDiscount < 100 Then
                Local $fResult = $fDiscounted / (1 - ($fDiscount / 100))
                GUICtrlSetData($idInput_Result2, Round($fResult))
            EndIf

    EndSwitch
WEnd

コードの詳しい解説

GUIのレイアウト作成

このツールは、2つの異なる計算機を一つのウィンドウにまとめた構造になっています。GUICtrlCreateGroup を使い、「『X円の Y% 引き』を計算」と「『X% 引きで Y円』の元の値段を計算」という 2つのセクションに分けています。

各セクションには、数値を入力するためのGUICtrlCreateInput、計算を開始するための GUICtrlCreateButton、そして結果を表示するための編集不可な GUICtrlCreateInput が配置されています。

割引後の値段を計算する

上のセクションの「計算」ボタンが押されると、以下の計算が実行されます。

計算式: 割引後の値段 = 元の値段 * (1 – (割引率 / 100))

例えば、1000円の 15% 引きなら、1000 * (1 – 0.15) = 850 となります。GUICtrlRead で入力された値を取得し、計算結果をGUICtrlSetData で結果表示欄に書き込んでいます。

割引前の元の値段を計算する

下のセクションの「計算」ボタンが押されると、先ほどの式の逆の計算(逆引き)を行います。

計算式: 元の値段 = 割引後の値段 / (1 – (割引率 / 100))

例えば、15% 引きで 850円なら、850 / (1 – 0.15) = 1000 となり、元の値段が求められます。

はい、承知いたしました。

これまでの基本機能に、「単位切り替え」と「入力制限」の機能を追加する「アップグレード版」として、記事を作成します。

【アップグレード編】割引計算機に「単位切り替え」と「入力制限」機能を追加

基本版スクリプトの課題

以前作成した割引計算機は、パーセント(%)での計算にしか対応していませんでした。しかし、日本では「割」という単位もよく使われるため、% しか使えないのは不便です。

また、100% を超える割引率など、ありえない数値を入力できてしまうという問題もありました。

そこで今回は、この計算機をアップグレードし、ラジオボタンによる単位切り替え機能と、入力値をチェックするバリデーション機能を追加して、より使いやすく、より安全なツールに仕上げます。

完成したアップグレード版コード

#include <GUIConstantsEx.au3>

; ### GUIの定義 ###
Local $hGUI = GUICreate("割引計算機(%・割 対応)", 360, 290)

; --- 割引後の値段を計算するグループ ---
GUICtrlCreateGroup("「X円のY ___ 引き」を計算", 10, 10, 340, 125)
GUICtrlCreateLabel("元の値段:", 20, 35, 80, 20)
Local $idInput_Original = GUICtrlCreateInput("", 100, 30, 140, 25)
GUICtrlCreateLabel("割引:", 20, 65, 80, 20)
Local $idInput_Discount1 = GUICtrlCreateInput("15", 100, 60, 60, 25)
; ラジオボタンで単位を選択
Local $idRadio_Percent1 = GUICtrlCreateRadio("%", 170, 65, 40, 20)
GUICtrlSetState(-1, $GUI_CHECKED) ; %をデフォルトに
Local $idRadio_Wari1 = GUICtrlCreateRadio("割", 220, 65, 40, 20)
Local $idBtn_CalcDiscount = GUICtrlCreateButton("計算", 20, 90, 220, 30)
Local $idInput_Result1 = GUICtrlCreateInput("", 250, 30, 90, 90)
GUICtrlSetFont(-1, 14, 800)
GUICtrlSetState(-1, $GUI_DISABLE)
GUICtrlCreateGroup("", -99, -99, 1, 1)

; --- 元の値段を計算するグループ ---
GUICtrlCreateGroup("「X ___ 引きでY円」の元の値段を計算", 10, 145, 340, 125)
GUICtrlCreateLabel("割引後の値段:", 20, 170, 80, 20)
Local $idInput_Discounted = GUICtrlCreateInput("", 100, 165, 140, 25)
GUICtrlCreateLabel("割引:", 20, 200, 80, 20)
Local $idInput_Discount2 = GUICtrlCreateInput("1.5", 100, 195, 60, 25)
; ラジオボタンで単位を選択
Local $idRadio_Percent2 = GUICtrlCreateRadio("%", 170, 200, 40, 20)
Local $idRadio_Wari2 = GUICtrlCreateRadio("割", 220, 200, 40, 20)
GUICtrlSetState(-1, $GUI_CHECKED) ; %をデフォルトに
Local $idBtn_CalcOriginal = GUICtrlCreateButton("計算", 20, 225, 220, 30)
Local $idInput_Result2 = GUICtrlCreateInput("", 250, 165, 90, 90)
GUICtrlSetFont(-1, 14, 800)
GUICtrlSetState(-1, $GUI_DISABLE)
GUICtrlCreateGroup("", -99, -99, 1, 1)

GUISetState(@SW_SHOW)

; ### メインループ ###
While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            ExitLoop
        Case $idBtn_CalcDiscount
            Local $fOriginal = Number(GUICtrlRead($idInput_Original))
            Local $fDiscount = Number(GUICtrlRead($idInput_Discount1))
            If $fOriginal <= 0 Or $fDiscount <= 0 Then ContinueLoop

            If GUICtrlRead($idRadio_Wari1) = $GUI_CHECKED Then
                ; 「割」が選択されている場合の入力値チェック
                If $fDiscount > 10 Then
                    MsgBox(16, "入力エラー", "「割」での割引は10を超えることはできません。")
                    ContinueLoop
                EndIf
                $fDiscount *= 10 ; 割をパーセントに変換
            Else
                ; 「%」が選択されている場合の入力値チェック
                If $fDiscount > 100 Then
                    MsgBox(16, "入力エラー", "「%」での割引は100を超えることはできません。")
                    ContinueLoop
                EndIf
            EndIf

            Local $fResult = $fOriginal * (1 - ($fDiscount / 100))
            GUICtrlSetData($idInput_Result1, Round($fResult))

        Case $idBtn_CalcOriginal
            Local $fDiscounted = Number(GUICtrlRead($idInput_Discounted))
            Local $fDiscount = Number(GUICtrlRead($idInput_Discount2))
            If $fDiscounted <= 0 Or $fDiscount <= 0 Then ContinueLoop

            If GUICtrlRead($idRadio_Wari2) = $GUI_CHECKED Then
                ; 「割」が選択されている場合の入力値チェック
                If $fDiscount >= 10 Then
                    MsgBox(16, "入力エラー", "「割」での割引は10未満でなければなりません。")
                    ContinueLoop
                EndIf
                $fDiscount *= 10 ; 割をパーセントに変換
            Else
                ; 「%」が選択されている場合の入力値チェック
                If $fDiscount >= 100 Then
                    MsgBox(16, "入力エラー", "「%」での割引は100未満でなければなりません。")
                    ContinueLoop
                EndIf
            EndIf

            Local $fResult = $fDiscounted / (1 - ($fDiscount / 100))
            GUICtrlSetData($idInput_Result2, Round($fResult))
    EndSwitch
WEnd

アップグレード内容の詳しい解説

ラジオボタンによる単位切り替え

GUICtrlCreateRadioを使い、「%」と「割」のどちらか一方しか選択できないラジオボタンを、各計算セクションに配置しています。

計算ロジックの中では、GUICtrlReadでどちらのラジオボタンがチェックされているかを判定し、もし「割」が選択されていれば、入力された割引の値を10倍してパーセントに換算してから計算を実行します。

入力値のバリデーション(検証)

計算を実行する前に、入力された割引率が妥当な範囲内にあるかをチェックする If 文を追加しました。

「割」の場合は 0~10、「%」の場合は 0~100 の範囲を超えた数値が入力されている場合、エラーメッセージを表示して計算を中断します。これにより、ありえない計算結果が表示されるのを防ぎ、ツールの信頼性を高めています。

なぜ “「X _ 引きでY円」の元の値段を計算” で「割」のときに「10」が指定できないんですか?

10割引きは、ゼロ除算というエラーを引き起こしてしまうためです。

10割引きの意味:
「10割引き」は、元の値段の100%を割り引く、つまり無料(0円)にするという意味です。

「元の値段を計算する」機能は、「割引後の値段」から逆算します。
もし、割引後の値段が「0円ではない何か」(例えば100円)で、それが『10割引きされた後の値段だ』と言われると、計算上、矛盾が生じます。

無料になったはずのものの値段を逆算することはできないため、プログラムはエラーを防ぐために10割の入力を禁止しているのです。

計算式での問点:
この機能で使われている計算式は以下の通りです。

元の値段 = 割引後の値段 / (1 – (割引率 / 100))

もし割引率に「10割」(つまり100%)を入れると、計算式は以下のようになります。

元の値段 = 割引後の値段 / (1 – (100 / 100))

元の値段 = 割引後の値段 / (1 – 1)

元の値段 = 割引後の値段 / 0

コンピュータの世界では、0で割り算をすることは禁止されているため、エラーが発生します。スクリプトのIf $fDiscount >= 10 Thenという行は、このエラーを未然に防ぐための安全装置なのです。

10割で計算できるようにして「1000」を入力して計算してみると、「9223372036854775807」と表示されます。

「0で割り算をするとエラーになる」と説明しましたが、AutoIt のより正確な動作は、エラーでクラッシュする代わりに、「無限大」という特殊な値を返す、というものです。

なぜこの数字が表示されるのか?

ゼロ除算の発生:
10割引き(100%引き)の元の値段を計算すると、計算式は「1000 ÷ 0」というゼロ除算になります。

「無限大」への変換:
AutoIt は、このゼロ除算の結果を「無限大 (Infinity)」という、数値としては扱えない特別な状態として処理します。

整数での表現限界:
そして、その「無限大」という概念を、Round() 関数などで無理やり整数として表示しようとすると、そのデータ型で表現できる限界の最大値(15桁)、つまり「9223372036854775807」に変換(丸め込まれ)てしまうのです。

これは、車のスピードメーターの針が、あまりの速さに振り切れてしまい、最大値に張り付いてしまうのと似ています。本当の速度は「測定不能なほど速い(無限大)」のですが、メーターが表示できるのはその限界値までなのです。

スクリプトにあったIf $fDiscount >= 10 Thenという安全装置は、まさにこの「メーターが振り切れてしまう」という、数学的に無意味な結果をユーザーに表示させないために存在していた、というわけです。

10割で計算できるようにして「1000」を入力して計算してみると、結果は「-10000」になります。

その計算結果は、数式上は正しいものです。

これは「11割引き」という割引が、現実ではありえないことを示しています。

「10割を超える割引」の意味:
10割引き (100%引き) は、商品の値段が 0円になる(無料になる)ことを意味します。

11割引き (110%引き) は、商品が無料になるだけでなく、さらにお店の人があなたにお金を支払わなければならない、という状況を意味します。

計算式が示すこと:
元の値段 = 割引後の値段 / (1 – (割引率 / 100))

この式に、割引後の値段「1000円」、割引率「11割(110%)」を入れると、以下のようになります。

元の値段 = 1000 / (1 – 1.1)

元の値段 = 1000 / -0.1

元の値段 = -10000

この「-10000円」という結果は、「もし元の値段が-10000円だったら、11割引きすると、あなたは1000円を受け取れます」という、計算上は成り立つものの、現実の買い物では意味をなさない値です。

まさに、このような奇妙な結果を防ぐために、スクリプトには「割」の入力は 10未満、「%」の入力は 100未満に制限する安全装置が入っているのです。

  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

CAPTCHA


目次