【问题标题】:Printing a positional numeric system in C在 C 中打印位置数字系统
【发布时间】:2016-03-12 11:38:30
【问题描述】:

我正在尝试编写一个函数来打印具有给定基数和位数的位置数字系统。例如,当 Base = 2 和 nDigits = 3 时,输出必须是这样的:

000
001
010
011
...
111

现在,我尝试做某事,但我只是失败了。考虑到我不能存储数字,我只需要打印它们,这就是我使用“支持”数组的动态分配的原因。这就是我到目前为止尝试做的事情,显然没有做它打算做的事情......我认为唯一正确的部分是打印 Base^nDigits 的所有组合。 (b=base,n=nDigits)。

void printNumeration(int b, int n){
    int i, j=0;
    int *array = calloc(n, sizeof(int));

    if (array == NULL){
        printf("Allocation failed.\n");
        exit(0);
    }


    for (i=0; i<pow(b, n); i++){
        for (j=0; j<n; j++){
            printf("%d", array[j]);
            array[j]++;
            if (array[j] == n){
                array[j] = 0;
            }
        }
        printf("\n");
    }
}

如果我的完全错误,您还可以提供一些关于更好解决方案的提示。

【问题讨论】:

  • 你有什么问题?
  • 您增加内部循环中的每个数字。您可以连续增加最后一位数字(并计算进位),直到第一个数字换行(想想里程表),或者您可以使用通常的代码打印 i 以打印每次通过的铈基整数。
  • @MOehm 你说的 80% 的内容我都听不懂……抱歉哈哈
  • @2501 也许是做我想做的事情的正确方法......?

标签: c printing


【解决方案1】:

首先,不要将pow 用于整数。 - 至少不能不四舍五入pow 使用不精确的浮点算法进行求幂。上周刚刚出现了一个问题,因为pow(10, 2) was 99.9999999... which truncated to int was 99.

也就是说,很可能有一个平台,在您的示例中,pow(2, 3) 的结果为7.999999...;由于仅通过 截断 小数将双精度数转换为整数,这意味着您的代码运行 7 个循环而不是 8 个! double 比较仍然如此; 8.0 仍然大于 7.999999999999999。因此,我们使用round 来确保结果数字正确四舍五入到最接近的整数值(在本例中为 8.0)。

您还需要事先计算这个数字,而不是每次循环迭代。

我们有 2 个内部循环。首先打印数字,第二个向后工作 - 如果 kth 数字等于 b,我们将其设置为 0,我们将 k 减 1,现在将 kth 数字增加 1,然后重复。

最后,记得释放 calloc 分配的内存。

void printNumeration(int b, int n) {
    int *digits = calloc(sizeof(int), n);
    int max = round(pow(b, n));
    for (int i = 0; i < max; i ++) {
        for (int j = 0; j < n; j ++) {
            printf("%d", digits[j]);
        }
        int k = n - 1;
        digits[k] ++;
        while (k && digits[k] == b) {
            digits[k] = 0;
            k--;
            digits[k] ++;
        }
        printf("\n");
    }
    free(digits);
}

【讨论】:

  • 我很抱歉另一个人,他给出了一个非常好的答案和努力,但我更喜欢你的功能,这更接近我的代码风格。非常感谢,这正是我想做的。给你最好的答案!
  • 你能解释一下 tho 是什么回合,以及我不使用 pow 函数的更好方法吗?
  • @THZ 补充说明
【解决方案2】:

你说的80%我都听不懂……

这是一个糟糕的比例。让我解释一下:

你增加内部循环中的每个数字。

您在内部循环中无条件地递增每个数字,并在必要时将其包装起来。这意味着您的枚举会以同步方式递增所有数字,从而产生诸如 00、11、22、00、11、2、...等输出。

您可以连续增加最后一位数字(并计算进位),直到第一个数字换行(想想里程表)...

您可以从全零数组开始。打印它。增加最后一位。检查溢出,如果溢出,将其设置为零并增加下一个数字,依此类推。如果最左边的数字溢出,请停止枚举。这就是汽车中的里程表(英里/公里计数器)的工作原理:

void printnum(int dig[], int n)
{
    static const char *digit = "0123456789abcdefghijklmnopqrstuvwxyz";

    while (n--) putchar(digit[dig[n]]);
    putchar('\n');
}

int enumerate(int base, int n)
{
    int dig[100] = {0};
    int count = 0;

    for (;;) {
        int i = 0;

        while (i < n && dig[i] == base) {
            dig[i++] = 0;
            dig[i]++;
        }
        if (i == n) break;

        printnum(dig, n);

        dig[0]++;
        count++;
    }

    return count;
}

或者您可以使用通常的代码打印 i 以打印每次通过的铈基整数。

您的枚举产生base^n 数字。 (不过,您可能不应该使用浮点函数pow 来计算这个幂。)您可以像在代码中那样循环所有这些数字,然后打印出给定基数的数字。通常的方法,你可以在 SO 上找到无数的例子,是从右边用后续除以基数的余数填充数组,直到数字为零。在这里,您希望打印所有数字,因此您应该除以 n 次,而不管分子为零。

int enumerate(int base, int n)
{
    int max = 1;
    int i;

    for (i = 0; i < n; i++) max *= base;

    for (i = 0; i < max; i++) {
        int buf[n];

        int j = i;
        int m;

        for (m = 0; m < n; m++) {
            buf[m] = j % base;
            j /= base;
        }

        printnum(buf, n);        
    }

    return max;
}

还有更多方法可以解决这个问题。欢乐时光!

【讨论】:

  • 我真的更喜欢第一个解决方案。我只是不明白两件事:1)我应该如何为有条件的循环而不是像你写的那样写? ('for(;;)') 2) 为什么要记下 'count' var 以及为什么要返回它?
  • (1) 条件在循环中间被求值;打破(名义上无限的)循环比在进入循环时评估条件更实际。 (当然,用入口条件重写代码是一个很好的练习:)) (2) 这不是绝对必要的,但它是一个合理的返回值,并且可以快速检查是否已打印所有可能性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多