給定一非負整數n計算2^n的值,一般而言把 2 乘上 n 次,就能得到答案。然而,當n特別大時,2^n要一次次地乘2可能稍嫌太慢,面對此一巨大問題利用分治(divide-and-conquer)演算法適當地拆解2 ^ n是個不錯的策略,特別是在進行2^m + 2^n這類運算時,其效果更為明顯。
第一行是測資個數,接下來的每一行會有兩個非負整數m和n以一個空白鍵隔開,其中0 <= m+n <= 5555
2^m + 2^n的精確值(每一筆輸出在十進制2,000位以內),每個case輸出完畢後請換行做為區隔。
3
12 13
20 14
140 115
12288
1064960
1393796616446538814624603420284493227884544
我自己想的C++程式碼如下
#include <iostream>
#include <algorithm>
#include <cmath>
#include <iomanip>
using namespace std;
long double divide_and_conquer_big_exponent(long double exp);
int main()
{
unsigned short T;
long double m, n;
cin >> T;
for (unsigned short i = 0; i < T; ++i)
{
cin >> m >> n;
// 2^m + 2^n = 2^min(m, n) * (2^abs(m-n) + 1)
cout << setprecision(2000) << divide_and_conquer_big_exponent(min(m, n)) * (divide_and_conquer_big_exponent(abs(m - n)) + 1) << '\n';
}
return 0;
}
long double divide_and_conquer_big_exponent(long double exp)
{
if (exp < 10)
{
return pow(2, exp);
}
return divide_and_conquer_big_exponent(exp / 2) * divide_and_conquer_big_exponent(exp - exp / 2);
}
但C++這樣寫精確度沒辦法到2000位,就連<cmath>
裡面的pow()
也沒辦法達到,因為pow()可以返回的最大精度類型是long double,這個也沒辦法到達2000位的精度。
想請問有其他方法可以用C++算到這麼高的精度嗎 ?? (像java裡面的BigInteger或python直接用**這樣可以直接計算大精度的整数)
使用 GMP The GNU Multiple Precision Arithmetic Library
https://gmplib.org/
我很討厭這種先輸入幾組,然後再 xxx 空格 yyy 這樣的測試資料輸入方式.
只做最後一組.
#include <stdio.h>
#include <stdlib.h>
#include <gmp.h>
int main()
{
mpz_t n,m,s;
mpz_t base;
mpz_init_set_ui(n,0);
mpz_init_set_ui(m,0);
mpz_init_set_ui(s,0);
mpz_init_set_ui(base, 2);
mpz_pow_ui(n, base, 140);
mpz_pow_ui(m, base, 115);
mpz_add(s, n, m);
printf("2 ^ 140 = ");
mpz_out_str(stdout,10,n);
printf("\n");
printf("2 ^ 115 = ");
mpz_out_str(stdout,10,m);
printf("\n");
printf("2 ^ 140 + 2 ^ 115 = ");
mpz_out_str(stdout,10,s);
printf("\n");
mpz_clear(n);
mpz_clear(m);
mpz_clear(s);
return EXIT_SUCCESS;
}
Result:
2 ^ 140 = 1393796574908163946345982392040522594123776
2 ^ 115 = 41538374868278621028243970633760768
2 ^ 140 + 2 ^ 115 = 1393796616446538814624603420284493227884544