c语言随机生成签名的int并填充数组,检查dupes,挂起32768

时间:2015-01-19 22:04:54

标签: c arrays

首先,一点背景。我是一名电子工程专业的学生,​​在compsci学习,我几乎完全是自学成才,只有很少的严格的编程培训,所以很可能会有不符合标准的东西。在我的下面的代码中。

这个小程序只是一个生成任意大小数据文件的实用程序,该文件填充了随机生成的signed int值,用作赋值的输入。我已经完成了作业并且工作正常。这是一个关于这个程序中发生的奇怪的事情(对我而言)的问题,这个问题只是在我添加代码部分以处理重复检查的时候才开始发生。在此之前,它只是将整数直接转储到文件中,每行一个。然后,我意识到这并不是教授数据的格式化方式,因此我更改了它以防止重复,每行添加多个int,并添加额外的空白分隔符(空格,制表符,换行)。

好的,只要我将MAX_NUMBERS保持在32k或更低的水平,所有这些都说明了这一点。如果我把它设得更高,它会很快显示计数,直到大约32k左右,然后它慢下来几百左右然后突然挂在32768.由于这个数字,我认为它可能要做使用int的大小(使用带有ming编译器的代码块),但sizeof(int)显示它是4个字节,因此不应该导致它。也许我认为可能是因为在它没有使用数组之前我对数组上的索引数量达到了最大限制。我的研究表明,这不应该是原因。我知道它会慢下来,因为必须检查重复项的值的数量会增加,但我很困惑为什么它会突然停止。

最后,我确实尝试修改它以使用更大的C99数据类型而不是int,就像实验一样,但是没有做任何事情。

如果有人碰巧看到任何愚蠢的东西,除了使用阵列哈哈,请告诉我!这让我有点疯狂。

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


int main()
{
    const int MAX_NUMBERS = 32000; // don't go higher than about 32000
    int* arr;
    // arr is used for duplicate checking, a log of everything put into the file is recorded
    // in arr and checked against to ensure uniqueness.

    const int ALLOW_NEG = 1; // switch to choose whether to allow negative numbers or not.

    int x = 0; // the random number that was generated
    int index = 0; // main loop control
    int index2 = 0; // dupe check loop control
    int hpos = 1; // used to select which type of whitespace to add
    int uniNum = 1; // uniqueness flag
    FILE *f = fopen("nums.txt", "w"); // open the file for writing. creates it if it's not there.

    arr = calloc(MAX_NUMBERS, sizeof(int)); // allocate space for the array

    for (index = 0; index < MAX_NUMBERS; index++) // arr init loop
        arr[index] = 999999999; // init the array to an invalid value. initially was 0, but caused 0 to be omitted by the dupe checker


    if (f == NULL){ // sanity check for the file
        printf("Error: Unable to open file. Program aborting.\n");
        exit(1);
    }

    printf("Generating data file...\n");

    srand(time(NULL)); // seed the random number generator

    fprintf(f, "%d\n", MAX_NUMBERS); // write the first line, the total number of ints in the file

    for (index = 0; index < MAX_NUMBERS; index++) { // main loop
        printf("\r%d", index); // just a display of the indices as the loops running, useless for small counts, semi-useful for very large amounts (100k+)
        do { // check for unique number
            uniNum = 1; // set uniqueness flag
            if (ALLOW_NEG == 1) { // executed if negatives are allowed
                  // This will allow 0, which makes sens if the
                  // range includes negative and positive.
                x = (rand() % MAX_NUMBERS+1) -((MAX_NUMBERS+1)/2); // generate a random number between (-max_nums/2) and (max_nums/2), totaling max_nums. the +1 is a bug fix, ask if curious
            } else { // no negs allowed!
                 // +1 makes the range from 1 to MAX_NUMBERS + 1,
                 // change to zero or remove to range from 0 to MAX_NUMBERS
                x = (rand() % MAX_NUMBERS+1) + 1; // generate random number of only positive ints and 0.
            }

            for (index2 = 0;index2 <= index; index2++){ // check currently generated numbers for dupes
                if (x == arr[index2]) { // dupe found!
                    uniNum = 0; // clear uniqueness flag
                    break; // end the for loop on a dupe, no sense in continuing
                }
            }
        } while(uniNum != 1); // repeat if the number wasn't unique
        arr[index] = x; // log the number

        if (hpos > 4) { // check to see if the horizontal position indicator is greater than 4
            fprintf(f, "%d\n", x); // write to the 5th position horizontally with a newline
            hpos = 1; // reset the horizontal position to the first. this gives me 5 numbers
                      //per line, with differing types of whitespace, just to test the reading
                      //and storing function. see a2.txt
        } else {
            switch (hpos) { // select based on which position we are in
                case 1 :
                    fprintf(f, "%d ", x); // first, space
                    hpos++;
                break;
                case 2 :
                    fprintf(f, "%d\t", x); // second, a tab character
                    hpos++;
                break;
                case 3 :
                    fprintf(f, "%d ", x); // third, another space
                    hpos++;
                break;
                case 4 :
                    fprintf(f, "%d\t", x);// fourth, another tab.. fifth is a newline
                    hpos++;
                break;
            }
        }
    }
    printf("\n%d numbers generated", index); // eh, print it out. why not?

    return 0;
}

1 个答案:

答案 0 :(得分:4)

do循环中的逻辑是:

  • 选择随机数
  • 浏览以前接受的号码列表,看看它是否存在
    • 如果是这样,请返回并选择另一个随机数
    • 如果没有,请退出此循环

根据评论中的建议,您的系统可能有RAND_MAX == 32767,因此只有32768个可能的随机数。所以一旦你选择了每一个,那么这个循环就变成了一个无限循环。

它似乎在接近结束时放慢速度的原因是它会在do循环(它不会显示任何内容)之间进行大量迭代,它会在找到新数字的时间之间进行

如果您将printf("\r%d", index);移到do循环内(并且每次迭代都有不断变化的显示),您应该看到这一点。


要获得更大范围的随机数,我会使用Mersenne Twister(mt19937)的免费实现,或see here用于其他选项。

此外,生成唯一随机数列表的算法效率极低(对现有列表的搜索过多),see here需要进行改进。