非専門的シンギュラリティー研究所

無限に動き続けるシステムを表す方法を AI なども使って考えていきます。

かけ算・わり算計算機コマンド版(1)

「かけ算・わり算計算機」の説明: 数学とソフトウェアのメモ2」・「かけ算とわり算」のコマンド版を ChatGPT を使って作っていきます。

以下の仕様の、シフトによって乗算・除算を行う様子を表示するプログラムを C++ で書いてください:
数値は  r 進数( r 2 から  10)  n 桁の自然数とします。

乗算を行うときは  x_0 * y_0 と入力します。( x_0 y_0 は数値)
  •  x = x_0 y = y_0 z = 0 とおきます。
    •  x y z が表示されます。
  • 「右シフト(上位の位へ)」を入力すると、 x の最下位の位(1の位)と  y の積が  z に加算され、 x z が右シフトされます。 x y は小数点以下はありませんが、 z は小数点以下も  n 桁あるとします。( x の小数点以下は消えますが、 z の小数点以下は残ります)
    •  x y z が表示されます。
    •  x_0 * y_0 = (x * y + z) * r が成り立っています。
  • 「右シフト(上位の位へ)」を入力した後は「左シフト(下位の位へ)」を入力することができます。
  • 「左シフト(下位の位へ)」を入力すると、「右シフト(上位の位へ)」と逆のことが行われ、元に戻ります。
  • このようにして「右シフト(上位の位へ)」を繰り返して入力していきます。
    • 毎回  x y z が表示されます。
    • そのとき  x_0 * y_0 = (x * y + z) * r^e が成り立っています。( e は「右シフト(上位の位へ)」の回数、 r^e r e 乗)
    •  e = n まで繰り返すと  x = 0 となって  x_0 * y_0 = z * r^n が成り立っています。ここから乗算の結果がわかります。
除算を行うときは  z_0 / y_0 と入力します。( z_0 y_0 は数値)
  •  x = 0 y = y_0 z = z_0 * r^{(-n)} とおきます。
    •  x y z が表示されます。
  • この後、乗算と同様に「右シフト(上位の位へ)」、「左シフト(下位の位へ)」を入力することができます。
  • 「左シフト(下位の位へ)」の処理は乗算の場合と同様ですが、結果( x に加算される値)は除算の商(最大の自然数)とします。
  • 「左シフト(下位の位へ)」の入力を  n 回繰り返すと、 z_0 = x * y_0 + z が成り立っています。ここから除算の商と余りがわかります。

と ChatGPT で入力するとプログラムを作ってくれましたが、そのままでは動かなかったのでさらに指摘していきました。

以下のように実行したとき、right を実行した後、 z は 15 を右にシフトしたものになるので 1.5 になります。この点を修正してください。また、 z は整数部分  n 桁、小数点以下  n 桁で表示されるようにしてください:

進数 r (2-10) を入力してください: 10
桁数 n を入力してください: 5
モードを選択してください(mul: 乗算, div: 除算): mul
x0 を入力してください: 5
y0 を入力してください: 3
------------------------
Exponent e = 0
x = 00005
y = 00003
z = .00000
コマンド (right: 右シフト, left: 左シフト, quit: 終了) > right
------------------------
Exponent e = 1
x = 00000
y = 00003
z = 0.00150
コマンド (right: 右シフト, left: 左シフト, quit: 終了) >

と ChatGPT で入力すると  z の表示は直してくれましたが、計算は相変わらず間違っていました。これは自力で直すことにします。

次に以下のように入力しました。

以下のように書き直してください:
コマンドは「r」のように途中まで入力しても受け付けるようにしてください。
モードの入力ではなく
「数値 * 数値」を入力すると乗算
「数値 / 数値」を入力すると除算
になるようにしてください。

コマンドを省略して入力することができるようにしてほしかったのですが、これはできていなかったので自力で修正しました。

モードの入力ではなく式の形で入力できるようにしてもらいました。仕様ではそう書いていたのにそうなっていませんでしたが、これはちゃんと直してくれました。

次に除算の左シフトの処理が間違っていたので直してもらいました。

divisionShiftLeft の中の以下の部分の borrow の処理を正しく書き直してください。(新しいバージョンでは z は zInt と考えてください)

    // 2. 商を計算して x[0] に入れる
    int quotient = 0;
    while (true) {
        bool enough = true;
        int borrow = 0;
        for (int i = 0; i < n; ++i) {
            int diff = z[i] - (y[i] + borrow);
            if (diff < 0) {
                enough = false;
                break;
            }
            if (diff >= r) diff -= r;
        }
        if (!enough) break;

        // z -= y
        int carry = 0;
        for (int i = 0; i < n; ++i) {
            int diff = z[i] - y[i] - carry;
            if (diff < 0) {
                diff += r;
                carry = 1;
            }
            else {
                carry = 0;
            }
            z[i] = diff;
        }
        ++quotient;
    }
    x[0] = quotient;

と入力すると、直してくれました。本来は乗算と除算の左シフトの処理は統一する仕様にしたつもりですが、これを指摘するのは難しいのでその部分は自力で修正しました。

そのほか関係式の表示や入力チェックなどを追加しました。

以下のように修正しました。このプログラムの仕様と使い方を書いてください:
(修正したプログラム)

と入力すると、以下のような結果が返されました。

素晴らしいプログラムですね!
以下に 仕様使い方 をまとめました。

📖 プログラムの仕様

このプログラムは、任意の基数(2進数から10進数)と桁数(1桁から32桁)を指定して、多桁の数同士の「乗算」と「除算の筆算シミュレーション」を行うものです。ユーザーは、乗算や除算の式を入力し、その筆算をステップごとに左右にシフトしながら計算の進み具合を確認できます。

🛠️ 主な機能

乗算モード(*)

  • `数値 * 数値` の形式で入力。
  • 例: `13 * 7`
  • `x` と `y` を初期化し、右シフトで積を順次加算。

除算モード(/)

  • `数値 / 数値` の形式で入力。
  • 例: `125 / 7`
  • `z`(被除数)から `y`(除数)を引きながら商を計算。左シフトで筆算の計算ステップを進める。

進数設定

  • 2進数から10進数までの任意の基数で計算可能。

桁数設定

  • 1桁から32桁まで対応。

ステップ実行

  • `right` または `r` で右シフト(積の加算または商の計算)
  • `left` または `l` で左シフト(除算の繰り下がりまたは積の繰り上がり)
  • 各シフトごとに途中経過を表示。

途中終了・再入力

  • `new` または `n` で新しい式を入力。
  • `quit` または `q` で終了。

🖥️ 使い方

1. プログラムを起動すると、基数(r)と桁数(n)の入力を求められます。
例:

   進数 r (2-10) を入力してください: 10
   桁数 n (1以上32以下) を入力してください: 4

2. 計算式を入力します。

  • 乗算: `数値 * 数値` 形式(例: `13 * 7`)
  • 除算: `数値 / 数値` 形式(例: `125 / 7`)

3. 筆算状態が表示され、計算ステップを選べます。

   コマンド (right: 右シフト, left: 左シフト, new: 新しい式, quit: 終了) 

4. コマンドは途中まで入力しても認識されます(例: `r`, `ri`, `right`)。

5. 結果を確認しながら `right` や `left` を繰り返して計算を進められます。

6. `new` で新しい式を計算できます。
`quit` で終了します。

🚨 注意事項

⚠️ 除算では被除数を分数形式で初期化するので、商を求めるには `left` を繰り返す必要があります。
⚠️ 計算式の解析が簡易的なので、正しい形式(`数値 * 数値` または `数値 / 数値`)で入力してください。

もしマニュアルの補足や使い方の例がもっと必要でしたら、お気軽にお声がけくださいね!