【问题标题】:Calculate the sum of digits in 100 factorial计算 100 阶乘中位数的总和
【发布时间】:2015-01-19 20:20:30
【问题描述】:

编辑 - 更改标题以匹配实际问题陈述。

我正在编写一个函数来计算 100 中数字的总和!但我似乎有两个大问题。

  1. 100的实际结果!仅限前几个数字(实际结果是93326215999390750859939075968993895088993989508899398950898938950889939895089939895088993989508989389508899389508C0000/389508899389508C0000/3885689993989508993989508993939508393986508C0000W/2950898939395089993989508893989508C0000“() LI>

  2. 我将结果数字的位数相加的方法没有输出正确的结果。

这是我当前的代码:

void factorialSum()
{
    double fact100 = factorial(100);
    double suma = 0;

    printf("100! is equal to: %.0f", fact100);

    while (fact100 > 0)
    {
        double temporal = fmod(fact100, 10);
        suma = suma + temporal;
        fact100 = fact100/10;
    }
    printf("\nThe sum of all digits in 100! is: %.0f", suma);
}

而函数factorial()定义为:

double factorial (double n)
{
    double mult = 1;
    double i = n;

    while (i>=1)
    {
        mult *= i;
        i = i - 1;
    }
    return mult;
}

在程序输出93326215443944102188325606108575267240944254854960571509166910400407995064242937148632694030450512898042989296944474898258737204311236641477561877016501813248作为100的结果!并说它的数字总和等于666。

感谢您的帮助,谢谢。

【问题讨论】:

标签: c factorial


【解决方案1】:

在 C 中,double 通常具有 53 位精度,对应于 16 或 17 位精度。因此,一旦超出22!double 就不能再代表确切的结果,如以下代码所示。请注意,23! 处的尾随零消失了,因为 double 不再代表确切的值。

#include <stdio.h>
#include <stdint.h>

int main( void )
{
    double y;

    y = 1;
    for ( int i = 2; i < 30; i++ )
    {
        y *= i;
        printf( "%2d %32.0lf\n", i, y );
    }
}

这是程序的输出

 2                                2
 3                                6
 4                               24
 5                              120
 6                              720
 7                             5040
 8                            40320
 9                           362880
10                          3628800
11                         39916800
12                        479001600
13                       6227020800
14                      87178291200
15                    1307674368000
16                   20922789888000
17                  355687428096000
18                 6402373705728000
19               121645100408832000
20              2432902008176640000
21             51090942171709440000
22           1124000727777607680000
23          25852016738884978212864
24         620448401733239409999872
25       15511210043330986055303168
26      403291461126605650322784256
27    10888869450418351940239884288
28   304888344611713836734530715648
29  8841761993739700772720181510144

如果您想计算100! 的确切值,您需要使用数字数组(又名bignums)来进行计算。您可以找到要使用的 bignum 库,也可以自己实现 bignum 乘法。关于 bignums 的维基百科文章提供了 pseudocode 用于计算阶乘。

【讨论】:

    【解决方案2】:
    #include <stdio.h>
    #include <stdlib.h>
    
    typedef unsigned char byte;
    
    int main(){
        size_t size =16;//initial size
        size_t temp, len;
        byte *n = malloc(size);
        byte i, carry = 0;
        *n = 1;
        len = 1;
    
        for(i=2;i<=100; ++i){
            size_t k;
            for(k = 0; k < len; ++k){
                if(k == size){
                    n = realloc(n, size*=2);//expand, check omitted
                }
                temp = n[k] * i + carry;//Calculation is performed on the promoted to int
                carry = (temp >= 10) ? temp / 10 : 0;//or simply temp/10
                n[k] = temp % 10;
            }
            while(carry){
                if(k == size){
                    n = realloc(n, size*=2);
                }
                temp = carry;
                carry = (temp >= 10) ? temp / 10 : 0;
                n[k++] = temp % 10;
                ++len;
            }
        }
        temp = 0;
        while(len){
            printf("%u", n[--len]);
            temp += n[len];
        }
        puts("");
        printf("sum=%zu\n", temp);
        free(n);
    
        return 0;
    }
    #if 0
    anticipate in advance the required size
    100! = 1*2*...99*100
    size > (log(1)+log(2)+...log(99)+log(100))/log(10)
    (∫1->100 log(x)dx)/log(10)
    f(x)=log(x) => F(x)=x(log(x)-1)+C
    (∫1->101 log(x)dx)/log(10) = (101*log(101)-101+1)/log(10) ≒ 159.00..
    160 digits are sufficient.
    http://en.wikipedia.org/wiki/Stirling%27s_approximation
    log10(n!)≒log10(√(2nπ)(n/e)^n)=log10(√(2nπ))+nlog10(n/e)=157.9696..
    size=158
    #endif
    

    【讨论】:

      【解决方案3】:

      正如其他人所提到的,您可以为此编写自己的 bignum 库(使用字节数组),也可以使用 OpenSSL 的 BIGNUM 实现之类的东西。

      这是事实函数的 OpenSSL 版本(在几乎所有发行版上都使用 gcc main.c -lcrypto 编译)。您只需要包含&lt;openssl/bn.h&gt;

      BIGNUM* fact (unsigned long n, BN_CTX* ctx) {
      
          BIGNUM *mult, *i, *one;
      
          mult = BN_new();
          i = BN_new();
          one = BN_new();
      
          BN_one(one);
      
          BN_set_word(mult, 1L);
          BN_set_word(i, n);
      
      
          while (BN_cmp(i, one) >= 0) {
              BIGNUM *a, *b;
      
              a = BN_new();
              b = BN_new();
      
              BN_mul(a, i, mult, ctx);
      
              BN_sub(b, i, one);
      
              BN_free(mult);
              BN_free(i);
              mult = a;
              i = b;
          }
      
          BN_free(one);
          BN_free(i);
      
          return mult;
      }
      

      然后,您可以使用BN_bn2bin 生成此数字的字符串表示形式,然后您可以使用它来计算数字的总和。

      【讨论】:

        【解决方案4】:

        这可能会有所帮助。假设您有一个像 2356 这样的数字。如何添加它的数字。好吧,您可以提取最低有效数字,将其添加到结果中并将其丢弃(右移)。你通过取数字 mod 10 来提取最小的数字。你通过除以 10 来移动。所以 2356 mod 10 = 6 和 2356 / 10 = 235。

        使用 mod 很容易,您只需检查产品中的数字,对它们进行 mod 并将 mod 相乘。例如 12*6 mod 10 = (12 mod 10) * (6 mod 10) = 2 * 6 = 12 然后取最后一个 mod:12 mod 10 = 2。如果你要乘以 12 *6 你将得到 72 等于 2 mod 10。

        最难的部分是除以 10。现在,如果产品包含 10 的倍数(例如 100),则将该数字除以 10,就完成了。如果不存在这样的数字,您仍然可以除以 10,但我猜这会搞砸结果。因此,如果你能找到如何做到这一点,你就可以在不实施 BIGNUM 的情况下解决问题。如果不是,那也没那么难,你只需要实现一个函数,将两个 BIGNUM 加在一起(乘法就是重复加法)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2023-03-22
          • 1970-01-01
          • 1970-01-01
          • 2011-10-17
          • 1970-01-01
          • 2015-04-19
          • 1970-01-01
          • 2022-01-17
          相关资源
          最近更新 更多