处理帕斯卡三角形的数字溢出



我正在尝试创建一个打印多达 70 行的大帕斯卡三角形。我的代码起初工作正常,但是当它到达第 65 行时,它开始打印出错误的输出。我知道它的问题,我尝试使用GMP。不幸的是,我用来编码的软件不支持GMP。还有其他方法可以在不使用GMP的情况下做到这一点吗?

char str;
int value;    
int pascal(int n)
{
    for (int i = 1; i < n + 2; i++)
    {
        unsigned long number = 1;
        for (int j = 1; j < i + 1; j++)  
        {
            if(j == i)
            {
                printf("%lun", number);
            }
            else
            {
                printf("%lu ", number);
            }
            number = (number * (i - j) / j);  
        }
    }
    return 0;
}

还有其他方法可以在不使用GMP的情况下做到这一点吗?

在形成数字(如 109069992321755544170(时所需的整数数学超过了基本的 64 位数学,这是一个超过 64 个前导有效位的 67 位数字。

尽管最宽的整数uintmax_t可以满足超过 64 位的数学需求,但它通常只有 64 位。

long double通常具有相当高的精度(在我的平台上只有 64 位(,但这不是为了满足 OP 的需求而指定的,并且调用了解决整数问题的通常 FP 问题。

幸运的是,所需的扩展数学只是乘法和除法。 一个简单但效率不高的字符串乘除法满足了需求。

void string_mult(char *y, unsigned x) {
  size_t len = strlen(y);
  unsigned acc = 0;
  size_t i = len;
  while (i > 0) {
    i--;
    acc += (y[i] - '0') * x;
    y[i] = acc % 10 + '0';
    acc /= 10;
  }
  while (acc) {
    memmove(&y[1], &y[0], ++len);
    y[0] = acc % 10 + '0';
    acc /= 10;
  }
}
unsigned string_div(char *y, unsigned x) {
  size_t len = strlen(y);
  unsigned acc = 0;
  for (size_t i = 0; i < len; i++) {
    acc *= 10;
    acc += y[i] - '0';
    y[i] = acc / x + '0';
    acc %= x;
  }
  while (y[0] == '0' && len > 1) {
    memmove(&y[0], &y[1], len);
    len--;
  }
  return acc;
}
void pascal(unsigned n) {
  printf("%u: ", n);
  for (unsigned i = 1; i < n + 2; i++) {
    char s[100] = "1";
    for (unsigned j = 1; j <= i; j++) {
      printf("%s ", s);
      string_mult(s, i - j);
      string_div(s, j);
    }
    printf("n");
  }
}
int main() {
  for (unsigned i = 0; i <= 70; i++)
    pascal(i);
}

输出

...
1 70 2415 54740 916895 12103014 131115985 1198774720 9440350920 65033528560 396704524216 2163842859360 10638894058520 47465835030320 193253756909160 721480692460864 2480089880334220 7877932561061640 23196134763125940 63484158299081520 161884603662657876 385439532530137800 858478958817125100 1791608261879217600 3508566179513467800 6455761770304780752 11173433833219812840 18208558839321176480 27963143931814663880 40498346384007444240 55347740058143507128 71416438784701299520 87038784768854708790 100226479430802391940 109069992321755544170 112186277816662845432 109069992321755544170 100226479430802391940 87038784768854708790 71416438784701299520 55347740058143507128 40498346384007444240 27963143931814663880 18208558839321176480 11173433833219812840 6455761770304780752 3508566179513467800 1791608261879217600 858478958817125100 385439532530137800 161884603662657876 63484158299081520 23196134763125940 7877932561061640 2480089880334220 721480692460864 193253756909160 47465835030320 10638894058520 2163842859360 396704524216 65033528560 9440350920 1198774720 131115985 12103014 916895 54740 2415 70 1 

经过进一步审查,long double可能会起作用,但我的努力在pascal(69)失败了。

最新更新