2023年2月6日月曜日

ChatGPTでプログラマはお払い箱になるのか

ChatGPTが今後ますます精度がよくなると世の中で働くホワイトカラーの大半がAIに置き換えられるという論調を最近しばしば目にする.なかでもプログラマは失業まったなし,なんだそうだ.

しかし,本当にそうなのだろうか?まずはChatGPTの実力を知らねば話にならない.簡単なCのプログラムを書かせてみた.以下,「[私] 〜」とあるのは私がChatGPTに対して入力した文字列であり,「[ChatGPT] 〜」およびそれに続くコード例は,ChatGPTの回答である.

1回目の対話

それでは,ChatGPTの底力をみてみることにしよう.

(対話ここから)

[私] コマンドライン引数で2つの数字を受け取って足し算をした結果を表示するCのプログラムを書いてください.

[ChatGPT] 以下が、2つの数字を受け取って足し算をするCのプログラムです。

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char* argv[]) {
    if (argc != 3) {
        printf("Usage: %s [num1] [num2]\n", argv[0]);
        return 1;
    }

    int num1 = atoi(argv[1]);
    int num2 = atoi(argv[2]);
    int result = num1 + num2;

    printf("%d + %d = %d\n", num1, num2, result);
    return 0;
}

このプログラムをコンパイルして実行すると、例えば以下のように使用できます。

$ gcc program.c -o program
$ ./program 1 2 1 + 2 = 3

(対話ここまで)

教科書に出てきそうなプログラムが出てきた.プログラミング入門コースの課題に対する回答であればこれで十分かもしれない.プログラミングを教える先生方は大変だな.課題を出すほうも今後はひと工夫が要りそうだ.

引数が2つじゃないとエラーメッセージを吐くようにしている点は,気が利いている.しかし,「数字」と指定したのに勝手に整数を仮定してしまっている点が,やや気にいらない.atoi() 関数は,文字列を整数に変換するものである.その他のエラー処理も一切考えられていないので,実際に現場で使えるプログラムには,ほど遠い.

2回目の対話

次は,条件を細かく指摘してみた.

(対話ここから)

[私] コマンドライン引数で2つの数字を受け取って足し算をした結果を表示するCのプログラムを書いてください.ただし,その引数は数字であれば実数であっても分数であってもよく,数字でない場合はエラーメッセージを出して数字を入力することをユーザーに促すこと.

[ChatGPT] 以下が、2つの数字を受け取って足し算をするCのプログラムです。

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <math.h>
#include <string.h>

int main(int argc, char* argv[]) {
    if (argc != 3) {
        printf("Usage: %s [num1] [num2]\n", argv[0]);
        return 1;
    }

    double num1, num2;
    char* end1, *end2;

    errno = 0;
    num1 = strtod(argv[1], &end1);
    if (errno != 0 || end1 == argv[1] || *end1 != '\0') {
        printf("Invalid argument: %s\n", argv[1]);
        return 1;
    }

    errno = 0;
    num2 = strtod(argv[2], &end2);
    if (errno != 0 || end2 == argv[2] || *end2 != '\0') {
        printf("Invalid argument: %s\n", argv[2]);
        return 1;
    }

    double result = num1 + num2;

    printf("%.7g + %.7g = %.7g\n", num1, num2, result);
    return 0;
}

このプログラムをコンパイルして実行すると、例えば以下のように使用できます。

$ gcc program.c -o program
$ ./program 1 2 1 + 2 = 3 $ ./program 1.2 3.4 1.2 + 3.4 = 4.6 $ ./program foo bar Invalid argument: foo
Invalid argument: bar

(対話ここまで)

小数も扱えるようなプログラムが出てきた.利用例もきちんと示されていて,丁寧である.strtod() なんて知らなかったので調べてみた.なるほどなー.しかし…… 分数には対応してないぞ?

3回目の対話

「分数であってもよく」という点が無視されたので,分数をきちんと受け取れるようにすることと念をおしてみよう.ついでにフォーマットも明示する.

(対話ここから)

[私] コマンドライン引数で2つの数字を受け取って足し算をした結果を表示するCのプログラムを書いてください.ただし,その引数は数字であれば実数であっても分数であってもよく,数字でない場合はエラーメッセージを出して数字を入力することをユーザーに促すこと.引数として分数も受け取れるようにすること.分数は,整数/整数,という形式で表現するものとする.

[ChatGPT] 以下が、2つの数字を受け取って足し算をするCのプログラムです。引数として分数を受け取ることもできます。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main(int argc, char* argv[]) {
    if (argc != 3) {
        printf("Usage: %s [num1] [num2]\n", argv[0]);
        return 1;
    }

    char *end1, *end2;
    double num1, num2;
    int numerator1, numerator2, denominator1, denominator2;

    errno = 0;
    numerator1 = strtol(argv[1], &end1, 10);
    if (errno == 0 && *end1 == '/') {
        denominator1 = strtol(end1 + 1, &end1, 10);
        if (errno == 0 && *end1 == '\0') {
            num1 = (double)numerator1 / denominator1;
        } else {
            printf("Invalid argument: %s\n", argv[1]);
            return 1;
        }
    } else {
        num1 = strtod(argv[1], &end1);
        if (errno != 0 || end1 == argv[1] || *end1 != '\0') {
            printf("Invalid argument: %s\n", argv[1]);
            return 1;
        }
    }

    errno = 0;
    numerator2 = strtol(argv[2], &end2, 10);
    if (errno == 0 && *end2 == '/') {
        denominator2 = strtol(end2 + 1, &end2, 10);
        if (errno == 0 && *end2 == '\0') {
            num2 = (double)numerator2 / denominator2;
        } else {
            printf("Invalid argument: %s\n", argv[2]);
            return 1;
        }
    } else {
        num2 = strtod(argv[2], &end2);
        if (errno != 0 || end2 == argv[2] || *end2 != '\0') {
            printf("Invalid argument: %s\n", argv[2]);
            return 1;
        }
    }

    double result = num1 + num2;
    printf("%.7g + %.7g = %.7g\n", num1, num2, result);
    return 0;
}

このプログラムをコンパイルして実行すると、例えば以下のように使用できます。

$ gcc program.c -o program
$ ./program 1 2
1 + 2 = 3
$ ./program 1.2 3.4
1.2 + 3.4 = 4.6

(対話ここまで)

分数も扱えるようなプログラムに修正された.ChatGPT,なかなかやるじゃん.しかし,利用例には分数の例が出ていない.たしかにプログラムを読めば分数も処理できるようになっているように読める.そこで,端末で実際に処理してみて,適切に動作することを確認した.

ところで,このプログラム,いささか冗長である.最初の引数と次の引数を処理するコードは,まとめてしまえるのではなかろうか?ていうか,私なら関数にまとめる.

4回目の対話

というわけで,その部分をきちんとせよと,さらに要件を追加した.

(対話ここから)

[私] コマンドライン引数で2つの数字を受け取って足し算をした結果を表示するCのプログラムを書いてください.ただし,その引数は数字であれば実数であっても分数であってもよく,数字でない場合はエラーメッセージを出して数字を入力することをユーザーに促すこと.引数として分数も受け取れるようにすること.分数は,整数/整数,という形式で表現するものとする.引数の有効性をチェックする部分は一つの関数として括り出し,mainはコンパクトな関数にしてください.

[ChatGPT] 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>

double parse_arg(const char *str) {
    char *endptr;
    double num = strtod(str, &endptr);
    if (*endptr == '\0') {
        return num;
    }
    int numerator = strtol(str, &endptr, 10);
    if (*endptr != '/') {
        printf("Invalid argument: %s\n", str);
        exit(1);
    }
    int denominator = strtol(endptr + 1, &endptr, 10);
    if (*endptr != '\0') {
        printf("Invalid argument: %s\n", str);
        exit(1);
    }
    return (double)numerator / denominator;
}

int main(int argc, char *argv[]) {
    if (argc != 3) {
        printf("Usage: %s NUMBER NUMBER\n", argv[0]);
        return 1;
    }
    double a = parse_arg(argv[1]);
    double b = parse_arg(argv[2]);
    printf("%.6g\n", a + b);
    return 0;
}

(対話ここまで)

おや,とうとう説明なしでコードだけになってしまったぞ?しかし,コードとしては,だいぶ洗練されたものになってきた.ところで,ctype.h と stdbool.h,使ってる?不要じゃないのかな.

5回目の対話

ほぼ完成,と思いきや,最後の出力が簡略化されてしまっている.最後のところは,以前と同様のものが望ましい.その要件を追加した.

(対話ここから)

[私] コマンドライン引数で2つの数字を受け取って足し算をした結果を表示するCのプログラムを書いてください.ただし,その引数は数字であれば実数であっても分数であってもよく,数字でない場合はエラーメッセージを出して数字を入力することをユーザーに促すこと.引数として分数も受け取れるようにすること.分数は,整数/整数,という形式で表現するものとする.引数の有効性をチェックする部分は一つの関数として括り出し,mainはコンパクトな関数にしてください.最後の出力は,printf("%.7g + %.7g = %.7g\n", a, b, a+b); としてください.

[ChatGPT] 以下は、要件に合ったCのプログラムです。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

bool is_valid_number(const char *str, double *num) {
    char *endptr;
    *num = strtod(str, &endptr);
    if (str == endptr)
        return false;
    if (*endptr != '\0') {
        // Check if it's a fraction
        char *slash = strchr(str, '/');
        if (slash == NULL)
            return false;
        int numerator = strtol(str, &endptr, 10);
        if (endptr != slash)
            return false;
        int denominator = strtol(slash + 1, &endptr, 10);
        if (*endptr != '\0')
            return false;
        *num = (double) numerator / denominator;
    }
    return true;
}

int main(int argc, char *argv[]) {
    if (argc != 3) {
        printf("Usage: %s num1 num2\n", argv[0]);
        return 1;
    }

    double a, b;
    if (!is_valid_number(argv[1], &a) || !is_valid_number(argv[2], &b)) {
        printf("Error: Both arguments should be numbers\n");
        return 1;
    }

    printf("%.7g + %.7g = %.7g\n", a, b, a + b);
    return 0;
}

(対話ここまで)

対話を終えて

ここまで,皆さんはどうお感じになっただろうか.私は「ChatGPT,なかなかやるやんけ」という印象を持った.さて,プログラマは本当に失業してしまうのだろうか?

問題は,素人が下記の要件を簡単に書けるだろうか,という点である.

コマンドライン引数で2つの数字を受け取って足し算をした結果を表示するCのプログラムを書いてください.ただし,その引数は数字であれば実数であっても分数であってもよく,数字でない場合はエラーメッセージを出して数字を入力することをユーザーに促すこと.引数として分数も受け取れるようにすること.分数は,整数/整数,という形式で表現するものとする.引数の有効性をチェックする部分は一つの関数として括り出し,mainはコンパクトな関数にしてください.最後の出力は,printf("%.7g + %.7g = %.7g\n", a, b, a+b); としてください.

さらに,出てきたコードが正しいものであることをきちんとチェックできるか,という観点もある.テストコードがあればいい?そのテストコードは誰が書くのだろうか.ChatGPTが書く?ほなそのテストコードの仕様は誰が書くのか.

2個の数字を足してその結果を表示するだけ,という,とてつもなくシンプルなコードでこれである.プログラマ失業説を唱える方々には,「現実の情報処理システムに関して,ChatGPTにどうやって訊く?」と問いたい.

ChatGPTも使いよう

いくらAIが進化しようとも,AIだけで完結することはないのではなかろうか.経営者が経営に関するシステムを必要としたとして,その経営者には,システムの仕様を適切に記述したり,出てきたコードの正当性をチェックしたりという能力も時間もなかろう.やはり,翻訳者は必要になるのだ.

プログラマがChatGPTをうまく利用して,プログラミングの作業効率を上げる,生産性を上げるということは十分に考えられる.ちょっとした使い方を知る,聞いてみる,サンプルコードを出してもらうというような使い方としてはとても便利なツールになるのではなかろうか.

ところで,最後に,ずばり本人に聞いてみた.プログラマを取り替えることはないってさ.

9 件のコメント:

  1. 確かに答えはNoです。なぜなら少なくともChatGPTを開発しているプログラマがいるからです。
    しかしそれはAll or Nothingではないと思います。
    私達は歴史に学ぶことができます。AI翻訳が台頭してきても、プロの翻訳者は完全に駆逐されませんでした。しかしその市場は縮小しました。
    映画や書籍の翻訳は依然としてプロに依頼する必要がありますが、かんたんなウェブサイトはそうではありません。
    またスクラッチからの翻訳という時間のかかるスタイルではなく、AI翻訳からの修正という速いスタイルに移り、必要な翻訳者の数が減りました。
    プログラミングの世界でも同じようなことが起こりうるでしょう。そしてそれは、シナリオ、イラスト、作曲、さまざまな世界で起こりうります。

    返信削除
  2. 現状はまだまだプログラマは必要でしょうが、近年のAIの進歩をみていると、AIが大多数の平凡なプログラマの能力を凌駕する日は、そお遠くはないという気がしてきました。いずれは天才プログラマも...

    返信削除
  3. 現在のChatGPT では自然言語でプログラミングしていることと変わらない。ある処理したいデータセットを元にAIがアプリケーションの作成と評価を行ってエンドユーザーが最終評価を行うことでアプリケーションが自動生成されるシステムができない限りはまだまだプログラマーの仕事は残り続けるだろう。

    返信削除
  4. AIが優れたコードを出力できたとして、それをプログラマーなしにどのように品質をチェックするんだろうという疑問はあるんですよね。品質もAIがチェックできたとして、その結果を盲信するのかどうか。要は開発リソースを組織外に丸投げして自身は内容を理解できていない、某銀行システムの管理体制みたいな状況を想像してしまうのです。

    返信削除
  5. 皆様コメントありがとうございます.上記のコメント,いずれもご指摘のとおりですね.多くのアクセスをいただいて嬉しい限りです.たくさんのブコメやTwitterでの反応などもいただき楽しく拝見しておりますが,「ところで,ctype.h と stdbool.h,使ってる?不要じゃないのかな.」に対するツッコミというか,言及が,それらのなかに未だになく,その点は,なんとなくモヤモヤしたものを感じております(欲張りすぎ?)

    返信削除
  6. プログラマそのものの人数は減りそう

    返信削除
  7. PC歴40年の現役40代プログラマです。
    ChatGPTやAI Programmerにコードを吐かせてみた印象では、出力された物が正しいのか、特定条件下で問題なく動くのかを人間が判断しなくてはならず、指示を文章で試行錯誤させて出力させるより、自分で直接書いたほうが早い上、たまにしれっと尤もらしいトンデモコードを返すこともあるのでまだ10年くらいは安泰かなと思います。

    ただ、コアとなるロジックを考えた後にAIにさっと出力させて、それをスケルトンとして肉付けするのには便利かもと感じました。

    また、簡単なロジックは問題なく記述されることが多いですがそもそも全体を俯瞰した設計は出来ない上、これを全て文章で指示するのも現実的でないので、このような工程は全ての人間の作業が代行可能な汎用型AIが出現するまで無くならないと考えています。まあこれが出来たらベーシックインカムあたりが導入されて誰も仕事をしなくてよい世界になりそうですが。

    返信削除
    返信
    1. 今回の件でも,「ところで,ctype.h と stdbool.h,使ってる?不要じゃないのかな」っていうあたり,おかしなコードですよね(誰も指摘してくれないけど……)

      削除
  8. 返信ありがとうございます。指摘されている不要なincludeに関して私も含め何故皆スルーなのかと考えてみたのですが、当初関数を使用する際に必要だった物が、その関数を使うのを止めた際に不要になった事に気付かず残ったままにしてしまうこと、逆に外すと他の関数でも必要でエラーになってしまうことがあること、基本的には関数宣言とdefineしかないので残っていてもコンパイルが気持ち遅くなる以外はほぼ影響ない事など、コンパイルエラー時とリファクタリング時に見るものと思い込んでいて無意識にincludeを見ていない事に気付きました。
    chatGPTもそんな私たちが書いたcodeを学習してしまったと思うと、妙な親近感を覚えます。

    返信削除