使用c ++的非常大的数字总和

时间:2017-09-01 11:19:26

标签: c++

我正在尝试解决这个问题:Project Euler #16

  

2 ^ 15 = 32768,其数字之和为3 + 2 + 7 + 6 + 8 = 26   数字2 ^ 1000的数字总和是多少?

#include <iostream>
#include <cmath>
using namespace std;

int main()
{
   int num;
   cin >> num;
   long double n = pow(2, num);
   cout << fixed << n << endl;
   int sum = 0;
   while(n != 0.0)
   {
      sum = sum + fmod(n, 10);
      n = floor(n/10);
   }
   cout << sum << endl;
}

用户输入为1000时的输出为:

1181

然而,互联网提到的正确答案是1366,而不是我得到的1181

2 个答案:

答案 0 :(得分:5)

关于第一次计算的问题

long double n = pow(2, num);

即使常规double类型(max: 1.79769e+308)也会保留2^1000 = 1.07151e+301而不会出现任何问题,尤其是这是基数为2的计算。

请注意,您使用double版本pow()fmod()floor()代替long double版本powl(),{{1} }和fmodl()。但就像我说这个问题一样,并没有改变任何事情。

但是while循环中的计算将缺乏精度和舍入误差。在使用它们进行算术运算时,永远不要检查(un)相等的浮点数,请参阅here on SO(网络上有很多关于该主题的讨论和线索)。

简而言之:
我认为您的floorl()fmod()会导致精确丢失和舍入错误。

这是一个工作解决方案(see at ideone),用于将floor()转换为double并迭代字符串的每个字符,并将char转换为整数。

简而言之:
它只是使用初始计算(仅使用std::string)并将其转换为字符串。

double

<强>输出:

#include <iostream>
#include <cmath>

int main ()
{
   int num;
   std::cin >> num;
   double n = pow(2, num); /* note I use just double */

   std::string nstr = std::to_string(n);
   const char* nstr_p = nstr.c_str();

   std::cout << std::fixed << nstr << std::endl;
   int sum = 0;
   while (std::isdigit(*nstr_p)) /* number contains dot and fractional (.0000) */
   {
      sum = sum + (*nstr_p - '0'); /* convert character to integer and sum it */
      nstr_p++;
   }
   std::cout << sum << std::endl;
}

请注意,转化:1366 采用类似ASCII的编码或其他数字正在递增但十六进制表示没有间隙的编码。

答案 1 :(得分:0)

这是一种使用GMP的多精度整数算法的C ++方法(注意gmpxx.h)。

我尽可能选择整数,而gmp很容易使用大整数。

和安德烈一样,我创建了结果的std :: string,并添加了数字。

环境:

Ubuntu 15.10,64位,使用g ++ - 5是v5.2.1,适用于较旧的戴尔

代码:

#include <chrono>
// 'compressed' chrono access --------------vvvvvvv
typedef std::chrono::high_resolution_clock  HRClk_t; // std-chrono-hi-res-clk
typedef HRClk_t::time_point                 Time_t;  // ...-time-point
typedef std::chrono::milliseconds           MS_t;    // std-chrono-milliseconds
typedef std::chrono::microseconds           US_t;    // std-chrono-microseconds
typedef std::chrono::nanoseconds            NS_t;    // std-chrono-nanoseconds
using   namespace std::chrono_literals; // support suffixes like 100ms, 2s, 30us
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
#include <cassert>

#include <gmpxx.h>  // multiprecision arithmetic:
                    // no rounding errors because mpz_class is integer

class T526_t
{
public:
   T526_t() = default;
   ~T526_t() = default;

   int exec()
      {
         Time_t start_us = HRClk_t::now();

         mpz_class  N("1"); // initialize multi-precision integer to value 1

         std::string s;
         int i;
         for (i=0; true; ++i) // run forever
         {
            std::stringstream ss;
            ss << N;              // stream i/o from gmpxx.h
            N = N * 2;            // compute next value

            if(i <= 16) // confirm the first 17 values
            {
               std::cout << "\n"
                         << "  2 ^" << std::setw(3) << i
                         << "  size:" << std::setw(2) << ss.str().size()
                         << "  " << digiComma(ss.str())
                         << "  sum : " << sumOfDigits(ss.str());
            }
            s = ss.str();

            if (1000 == i) break; // enough already
         }

         std::cout << "\n\n"
                   << "  2 ^" << std::setw(5) << i
                   << "  size:" << std::setw(4) << s.size()
                   << "  \n\n" << digiComma(s)
                   << "\n\n  sum-of-digits: " << sumOfDigits(s) << std::endl;

         auto duration_us =
            std::chrono::duration_cast<US_t>(HRClk_t::now() - start_us);

         std::cout << "\n\n  duration: "
                   << digiComma(std::to_string(duration_us.count()))
                   << " us" << std::endl;

         return (0);
      }


private: // methods

   size_t sumOfDigits(std::string s)
      {
         size_t retVal = 0;
         for (uint i=0; i<s.size(); ++i)
         {
            retVal += s[i] - '0';
         }
         return retVal;
      }

   std::string digiComma(std::string s)
      {  //vvvvv--sSize must be signed int of sufficient size
         int32_t sSize = static_cast<int32_t>(s.size());
         if (sSize > 3)
            for (int32_t indx = (sSize - 3); indx > 0; indx -= 3)
               s.insert(static_cast<size_t>(indx), 1, ',');
         return(s);
      }


}; // class T526_t


int main(int , char** )
{
   Time_t start_us = HRClk_t::now();

   int retVal = -1;
   {
      T526_t   t526;
      retVal = t526.exec();
   }

   auto  duration_us =
      std::chrono::duration_cast<US_t>(HRClk_t::now() - start_us);

   std::cout << "\n  FINI   " << duration_us.count() << " us" << std::endl;
   return(retVal);
}

结果:

Rule-526: dumy526.cc
rm -f dumy526
g++-5 -m64  -O0 -ggdb -std=c++14 -Wall -Wextra -Wshadow -Wnon-virtual-dtor
                -pedantic -Wcast-align -Wcast-qual -Wconversion -Wpointer-arith
                -Wunused -Woverloaded-virtual   dumy526.cc  -o dumy526
                -L../../bag  -lbag_i686  -lgmpxx -lgmp

real    0m2.235s
user    0m1.992s
sys 0m0.208s

  2 ^  0  size: 1  1  sum : 1
  2 ^  1  size: 1  2  sum : 2
  2 ^  2  size: 1  4  sum : 4
  2 ^  3  size: 1  8  sum : 8
  2 ^  4  size: 2  16  sum : 7
  2 ^  5  size: 2  32  sum : 5
  2 ^  6  size: 2  64  sum : 10
  2 ^  7  size: 3  128  sum : 11
  2 ^  8  size: 3  256  sum : 13
  2 ^  9  size: 3  512  sum : 8
  2 ^ 10  size: 4  1,024  sum : 7
  2 ^ 11  size: 4  2,048  sum : 14
  2 ^ 12  size: 4  4,096  sum : 19
  2 ^ 13  size: 4  8,192  sum : 20
  2 ^ 14  size: 5  16,384  sum : 22
  2 ^ 15  size: 5  32,768  sum : 26
  2 ^ 16  size: 5  65,536  sum : 25

  2 ^ 1000  size: 302  

10,715,086,071,862,673,209,484,250,490,600,018,105,614,048,117,055,336,074,437,
503,883,703,510,511,249,361,224,931,983,788,156,958,581,275,946,729,175,531,468,
251,871,452,856,923,140,435,984,577,574,698,574,803,934,567,774,824,230,985,421,
074,605,062,371,141,877,954,182,153,046,474,983,581,941,267,398,767,559,165,543,
946,077,062,914,571,196,477,686,542,167,660,429,831,652,624,386,837,205,668,069,
376

  sum-of-digits: 1366


  duration: 4,569 us

  FINI   4616 us

JFF(只是为了好玩),因为使用mpz_class很容易:

2 ^ 10000  size: 3011  

19,950,631, ... ,596,709,376

sum-of-digits: 13,561



2 ^ 100000  size: 30103  

9,990,020, ... ,883,109,376

sum-of-digits: 135,178