涼の成長記録

自らの人生に主導権を持つべく、独立を目指して2014年3月31日を持ってITエンジニアを退職。そんな23歳♂の成長記録。

我が社の新卒採用試験向けプログラミングの課題が難しい件

先日、課長から「こんな問題を出すので解答作ってー」というメールが来ました。問題を見てみると、おおよそ、以下のような感じです。

以下は乱数を生成して画面出力するプログラム例である。
このプログラム例を参考に以下の要件を満たすプログラムをC言語にて記述せよ。

#include <stdio.h>
#include <stdlib.h>
void main(void){
    printf(“%d¥n”, rand());
}

【要件】
1. 乱数を6個生成し、生成した数値を画面出力せよ。
2. 生成する数値は1~43の範囲とする。
(rand 関数は0~65535 の乱数を生成するものとする。)
3. 6個の数値は重複してはいけない。
4. 画面出力イメージは以下とする。(1 桁の数値は頭に0 を付けて2 桁表示すること)

1 番目の数値はxx
2 番目の数値はxx
3 番目の数値はxx
4 番目の数値はxx
5 番目の数値はxx
6 番目の数値はxx


制限時間は5分です。学生にやらせるのは、難しすぎるのではないかと思いました。しかし、面白そうであったため、私もやってみました。

#include <stdio.h>  // printf()用
#include <stdlib.h> // rand()用

// 問題文からの定義
#define MIN 1
#define MAX 43
#define LOOP_COUNT 6
#define MY_RAND_MAX 65535

// 範囲乱数公式
#define MY_RANDOM(min, max) ((min) + (int)(rand() * ((max) - (min) + 1.0) / (1.0 + MY_RAND_MAX)))

int main(void) {
    int i, j;
    unsigned int value[LOOP_COUNT] = {0};

    // 疑似乱数発生系列変更
    srand((unsigned)time(NULL));

    for (i = 1; i <= LOOP_COUNT; i++) {
        // 乱数取得
        value[i] = MY_RANDOM(MIN, MAX);

        // 重複チェック
        for (j = 0; j < i; j++) {
            if (value[i] == value[j]) {
                i--;
                break;
            }
        }
    }

    // まとめて出力
    for (i = 1; i <= LOOP_COUNT; i++) printf("%d番目の数値は%02d\n", i, MY_RANDOM(MIN, MAX));

    return 0;
}


これを組んでコンパイルして動かしてみるまでで、7分ちょい掛かりました。なんかいろいろ残念なコードになってしまって、やはり私はまだまだ底辺なんだなー、と感じました。少しだけ悲しくなりましたが、自分の底辺具合を思い知るのは、トレーニングの良い動機になるのでラッキーと思いましょう。面白かったしね。


物を知っているかのキモは、範囲乱数公式だと思うのです。私が知っていたのは、かの有名な"苦しんで覚えるC言語"で、WEBサイト、書籍と共に、みっちりと勉強したためです。


課長や他のグループ員は、[ (rand() % 43) + 1 ]を想定していたようですが、Wikipediaにすら書いてあるほどの問題を抱えています。
rand - Wikipedia

定の範囲で乱数を求めたいときにはa = rand() % 10とする方法も広く知られているが、線形合同法などの下位ビットの乱数としての品質が低い生成法に備えるため上記のコード例のような上位にあるビットを利用するコードが推奨されている。


この試験の目的は「直感的に短時間でどこまでロジックが思い浮かぶか」を知ることのようで、そんな話はどうだって良いと思うのですが。


いやー、プログラミングって面白いですね。
ではでは。