我正在尝试解决这个问题: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
。
答案 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