// https://i...content-available-to-author-only...e.com/6BG7hf
// 2^(expn2)を有効数字disp10桁の10進数で指数表示する。
// Usage: print_by_decimal <expn2> <disp10>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
#include <vector>
#include <utility>
#include <time.h>
// 指数の型
typedef uint64_t expn_t;
// 2乗したものを足し合わせてもuint64_tが桁あふれしない10進数
#define BIG_DECIMAL 10000000ULL
static_assert(UINT64_MAX - (BIG_DECIMAL - 1) * (BIG_DECIMAL - 1) >= 2 * (BIG_DECIMAL - 1), "*** ERR ***");
static_assert(2 * (BIG_DECIMAL - 1) + (BIG_DECIMAL - 1) * (BIG_DECIMAL - 1) <= UINT64_MAX, "*** ERR ***");
namespace
{
/// 先頭の0を切り詰めたサイズを返す。
size_t truncated_size(const std::vector<uint32_t>& mbuf)
{
const size_t sz = mbuf.size();
for (size_t i = sz; i > 0; i--) {
if (mbuf[i - 1] != 0UL) {
return i;
}
}
return sz;
}
/// 乗算
/// メモリ消費を半分にするため、キャリー伝搬を単純に桁の積和の都度行う。
std::vector<uint32_t> mlen_mul(const std::vector<uint32_t>& lhs, const std::vector<uint32_t>& rhs)
{
const size_t sz_lhs = truncated_size(lhs);
const size_t sz_rhs = truncated_size(rhs);
std::vector<uint32_t> mbuf(sz_lhs + sz_rhs, 0UL);
for (expn_t i = 0; i < sz_lhs; i++) {
uint32_t cy = 0UL;
for (expn_t j = 0; j < sz_rhs; j++) {
const uint64_t val64 = (uint64_t)mbuf[i + j] + (uint64_t)lhs[i] * (uint64_t)rhs[j] + (uint64_t)cy;
cy = (uint32_t)(val64 / BIG_DECIMAL);
mbuf[i + j] = (uint32_t)(val64 - cy * BIG_DECIMAL);
}
{
const expn_t j = sz_rhs;
const uint64_t val64 = (uint64_t)mbuf[i + j] + (uint64_t)cy;
cy = (uint32_t)(val64 / BIG_DECIMAL);
mbuf[i + j] = (uint32_t)(val64 - cy * BIG_DECIMAL);
assert(cy == 0UL);
}
}
return mbuf;
}
/// 2^nをBIG_DECIMAL進数で計算する。
std::vector<uint32_t> pow2(const expn_t n_)
{
const time_t startTmg = time(NULL);
std::vector<uint32_t> mbuf((size_t)1, 1UL);
std::vector<uint32_t> mbuf_work((size_t)1, 2UL);
expn_t n = n_;
for (;;) {
if ((n & 0x1) != 0) {
mbuf = mlen_mul(mbuf, mbuf_work);
}
const time_t now = time(NULL);
printf("n=%llu, mbuf sz=%zu --- %lld sec\n", n, mbuf.size(), now - startTmg);
n >>= 1;
if (n == 0ULL) {
break;
}
mbuf_work = mlen_mul(mbuf_work, mbuf_work);
}
return mbuf;
}
} // namespace
int main(const int argc, char* argv[])
{
// 2のべきの指数
//expn_t expn2 = 1717986918;
//expn_t expn2 = 171798;
expn_t expn2 = 1000;
//expn_t expn2 = 64;
//expn_t expn2 = 32;
//expn_t expn2 = 16;
//expn_t expn2 = 8;
//expn_t expn2 = 0;
// 表示桁数(有効数字)
expn_t disp10 = 64;
#ifdef _WIN32
if (argc >= 2) {
expn2 = _atoi64(argv[1]);
}
if (argc >= 3) {
disp10 = _atoi64(argv[2]);
}
#else
(void)(argc, argv);
#endif
// テスト
//std::vector<uint32_t> lhs((size_t)1, 9000000UL);
//std::vector<uint32_t> rhs((size_t)1, 9000000UL);
//std::vector<uint32_t> result = mlen_mul(lhs, rhs);
//printf("%07lu %07lu\n", result[1], result[0]);
// 2^(expn2)
std::vector<uint32_t> result = pow2(expn2);
printf("2^%llu = ", expn2);
const size_t sz = result.size();
expn_t cnt = 0;
for (size_t i = sz; i > 0; i--) {
if (cnt < 10) {
printf(" %07lu", result[i - 1]);
}
cnt++;
}
if (cnt < 10) {
printf("\n");
}
else {
printf(". x 10^%llu\n", 7ULL * cnt - 10);
}
}