#define PRIu64 "llu"
#include <stdio.h>
#include <stdint.h>
#include <math.h>
//
// ひたすら足し算の方法
//
uint64_t fibonacci_z(unsigned int n_) {
switch (n_) {
case 0:
return 0;
case 1:
return 1;
default: {
uint64_t u_l = 0;
uint64_t u_r = 1;
uint64_t u_y = 1;
for (unsigned int i = 1; i < n_; ++i) {
u_y += u_l;
u_l = u_r;
u_r = u_y;
}
return u_y;
}
}
}
//
// 一般項
//
uint64_t fibonacci_f(unsigned int n_) {
const long double r_r5 = sqrtl((long double)5.0);
const long double r_phi = ((long double)1.0 + r_r5) / (long double)2.0;
long double r_fibonacci = ((powl(r_phi, (long double)n_) - powl((long double)1.0 - r_phi, (long double)n_)) / r_r5);
return (uint64_t)(r_fibonacci + 0.5);
}
// 再帰階乗計算
// https://w...content-available-to-author-only...i.edu/~eppstein/161/960109.html
// This is a recursive algorithm, so as usual we get a recurrence relation defining time,
// just by writing down the time spent in a call to matpow (O(1)) plus the time in each recursive call
// (only one recursive call, with argument n/2). So the recurrence is
//
// time(n) = O(1) + time(n / 2)
typedef uint64_t Muint64_2x2_t[2][2];
static void matpow(Muint64_2x2_t M_, unsigned int n_) {
static Muint64_2x2_t const IM = { {1, 1}, {1, 0} };
static Muint64_2x2_t TM;
if (n_ > 1) {
matpow(M_, n_ >> 1);
// M = M * M;
TM[0][0] = M_[0][0] * M_[0][0] + M_[0][1] * M_[1][0];
TM[0][1] = M_[0][0] * M_[0][1] + M_[0][1] * M_[1][1];
TM[1][0] = M_[1][0] * M_[0][0] + M_[1][1] * M_[1][0];
TM[1][1] = M_[1][0] * M_[0][1] + M_[1][1] * M_[1][1];
M_[0][0] = TM[0][0];
M_[0][1] = TM[0][1];
M_[1][0] = TM[1][0];
M_[1][1] = TM[1][1];
}
if (n_ & 1) {
// M = M * IM;
TM[0][0] = M_[0][0] * IM[0][0] + M_[0][1] * IM[1][0];
TM[0][1] = M_[0][0] * IM[0][1] + M_[0][1] * IM[1][1];
TM[1][0] = M_[1][0] * IM[0][0] + M_[1][1] * IM[1][0];
TM[1][1] = M_[1][0] * IM[0][1] + M_[1][1] * IM[1][1];
M_[0][0] = TM[0][0];
M_[0][1] = TM[0][1];
M_[1][0] = TM[1][0];
M_[1][1] = TM[1][1];
}
}
uint64_t fibonacci_m(unsigned int n_) {
switch (n_) {
case 0:
return 0;
case 1:
return 1;
default: {
Muint64_2x2_t M = { {1, 0}, {0, 1} };
matpow(M, n_ - 1);
return M[0][0];
}
}
}
// アホが書いたコード
// t は 0 のまま
// a は 1 のまま
// b は 0 のまま
// なにをやってるかは不明
uint64_t fibonacci_aho(unsigned int n) {
n++;
uint64_t a = 1;
uint64_t b = 0;
uint64_t t;
for (int i = 0 ; i < 64 ; i++) {
t = b * b; // t ← 0 = 0 * 0
b = 2 * a * b + t; // t ← 0 = 2 * 1 * 0 + 0
a = a * a + t; // a ← 1 = 1 * 1 + 0
if (n & 0x8000000000000000) {
// マイナスにはならない ここはとおらない
t = b;
b = a + b;
a = t;
}
n += n; // 一切使わない総和(1~n)を求めてる
}
return a;
}
int main(int argc, char* argv[]) {
for (unsigned int i = 0; i < 94; ++i) {
printf ("n = %d (z)%" PRIu64
" (f)%" PRIu64
" (m)%" PRIu64
" (aho)%" PRIu64
"\n", i
, fibonacci_z
(i
), fibonacci_f
(i
), fibonacci_m
(i
), fibonacci_aho
(i
)); }
return 0;
}
I2RlZmluZSBQUkl1NjQgImxsdSIKCiNpbmNsdWRlIDxzdGRpby5oPgojaW5jbHVkZSA8c3RkaW50Lmg+CiNpbmNsdWRlIDxtYXRoLmg+CgovLwovLyDjgbLjgZ/jgZnjgonotrPjgZfnrpfjga7mlrnms5UKLy8KdWludDY0X3QgZmlib25hY2NpX3oodW5zaWduZWQgaW50IG5fKSB7CgoJc3dpdGNoIChuXykgewoJCWNhc2UgMDoKCQkJcmV0dXJuIDA7CgkJY2FzZSAxOgoJCQlyZXR1cm4gMTsKCQlkZWZhdWx0OiB7CgoJCQl1aW50NjRfdCB1X2wgPSAwOwoJCQl1aW50NjRfdCB1X3IgPSAxOwoJCQl1aW50NjRfdCB1X3kgPSAxOwoKCQkJZm9yICh1bnNpZ25lZCBpbnQgaSA9IDE7IGkgPCBuXzsgKytpKSB7CgkJCQl1X3kgKz0gdV9sOwoJCQkJdV9sID0gdV9yOwoJCQkJdV9yID0gdV95OwoJCQl9CgkJCXJldHVybiB1X3k7CgkJfQoJfQp9CgovLwovLyDkuIDoiKzpoIUKLy8KdWludDY0X3QgZmlib25hY2NpX2YodW5zaWduZWQgaW50IG5fKSB7Cgljb25zdCBsb25nIGRvdWJsZSByX3I1ID0gc3FydGwoKGxvbmcgZG91YmxlKTUuMCk7Cgljb25zdCBsb25nIGRvdWJsZSByX3BoaSA9ICgobG9uZyBkb3VibGUpMS4wICsgcl9yNSkgLyAobG9uZyBkb3VibGUpMi4wOwoJbG9uZyBkb3VibGUgcl9maWJvbmFjY2kgPSAoKHBvd2wocl9waGksIChsb25nIGRvdWJsZSluXykgLSBwb3dsKChsb25nIGRvdWJsZSkxLjAgLSByX3BoaSwgKGxvbmcgZG91YmxlKW5fKSkgLyByX3I1KTsKCXJldHVybiAodWludDY0X3QpKHJfZmlib25hY2NpICsgMC41KTsKfQoKLy8g5YaN5biw6ZqO5LmX6KiI566XCi8vIGh0dHBzOi8vdy4uLmNvbnRlbnQtYXZhaWxhYmxlLXRvLWF1dGhvci1vbmx5Li4uaS5lZHUvfmVwcHN0ZWluLzE2MS85NjAxMDkuaHRtbAovLyBUaGlzIGlzIGEgcmVjdXJzaXZlIGFsZ29yaXRobSwgc28gYXMgdXN1YWwgd2UgZ2V0IGEgcmVjdXJyZW5jZSByZWxhdGlvbiBkZWZpbmluZyB0aW1lLAovLyBqdXN0IGJ5IHdyaXRpbmcgZG93biB0aGUgdGltZSBzcGVudCBpbiBhIGNhbGwgdG8gbWF0cG93IChPKDEpKSBwbHVzIHRoZSB0aW1lIGluIGVhY2ggcmVjdXJzaXZlIGNhbGwKLy8gKG9ubHkgb25lIHJlY3Vyc2l2ZSBjYWxsLCB3aXRoIGFyZ3VtZW50IG4vMikuIFNvIHRoZSByZWN1cnJlbmNlIGlzCi8vCi8vICAgIHRpbWUobikgPSBPKDEpICsgdGltZShuIC8gMikKCnR5cGVkZWYgdWludDY0X3QgTXVpbnQ2NF8yeDJfdFsyXVsyXTsKCnN0YXRpYyB2b2lkIG1hdHBvdyhNdWludDY0XzJ4Ml90IE1fLCB1bnNpZ25lZCBpbnQgbl8pIHsKCglzdGF0aWMgTXVpbnQ2NF8yeDJfdCBjb25zdCBJTSA9IHsgezEsIDF9LCB7MSwgMH0gfTsKCXN0YXRpYyBNdWludDY0XzJ4Ml90IFRNOwoKICAgIGlmIChuXyA+IDEpIHsKCQltYXRwb3coTV8sIG5fID4+IDEpOwoKCQkvLyBNID0gTSAqIE07CgkJVE1bMF1bMF0gPSBNX1swXVswXSAqIE1fWzBdWzBdICsgTV9bMF1bMV0gKiBNX1sxXVswXTsKCQlUTVswXVsxXSA9IE1fWzBdWzBdICogTV9bMF1bMV0gKyBNX1swXVsxXSAqIE1fWzFdWzFdOwoJCVRNWzFdWzBdID0gTV9bMV1bMF0gKiBNX1swXVswXSArIE1fWzFdWzFdICogTV9bMV1bMF07CgkJVE1bMV1bMV0gPSBNX1sxXVswXSAqIE1fWzBdWzFdICsgTV9bMV1bMV0gKiBNX1sxXVsxXTsKCgkJTV9bMF1bMF0gPSBUTVswXVswXTsKCQlNX1swXVsxXSA9IFRNWzBdWzFdOwoJCU1fWzFdWzBdID0gVE1bMV1bMF07CgkJTV9bMV1bMV0gPSBUTVsxXVsxXTsKCX0KCglpZiAobl8gJiAxKSB7CgkJLy8gTSA9IE0gKiBJTTsKCQlUTVswXVswXSA9IE1fWzBdWzBdICogSU1bMF1bMF0gKyBNX1swXVsxXSAqIElNWzFdWzBdOwoJCVRNWzBdWzFdID0gTV9bMF1bMF0gKiBJTVswXVsxXSArIE1fWzBdWzFdICogSU1bMV1bMV07CgkJVE1bMV1bMF0gPSBNX1sxXVswXSAqIElNWzBdWzBdICsgTV9bMV1bMV0gKiBJTVsxXVswXTsKCQlUTVsxXVsxXSA9IE1fWzFdWzBdICogSU1bMF1bMV0gKyBNX1sxXVsxXSAqIElNWzFdWzFdOwoKCQlNX1swXVswXSA9IFRNWzBdWzBdOwoJCU1fWzBdWzFdID0gVE1bMF1bMV07CgkJTV9bMV1bMF0gPSBUTVsxXVswXTsKCQlNX1sxXVsxXSA9IFRNWzFdWzFdOwoJfQp9Cgp1aW50NjRfdCBmaWJvbmFjY2lfbSh1bnNpZ25lZCBpbnQgbl8pIHsKCglzd2l0Y2ggKG5fKSB7CgkJY2FzZSAwOgoJCQlyZXR1cm4gMDsKCQljYXNlIDE6CgkJCXJldHVybiAxOwoJCWRlZmF1bHQ6IHsKCgkJCU11aW50NjRfMngyX3QgTSA9IHsgezEsIDB9LCB7MCwgMX0gfTsKCQkJbWF0cG93KE0sIG5fIC0gMSk7CgkJCXJldHVybiBNWzBdWzBdOwoJCX0KCX0KCn0KCi8vIO+9se++juOBjOabuOOBhOOBn++9uu+9sO++hO++ngovLyB0IOOBryAwIOOBruOBvuOBvgovLyBhIOOBryAxIOOBruOBvuOBvgovLyBiIOOBryAwIOOBruOBvuOBvgovLyDjgarjgavjgpLjgoTjgaPjgabjgovjgYvjga/kuI3mmI4KdWludDY0X3QgZmlib25hY2NpX2Fobyh1bnNpZ25lZCBpbnQgbikgewoJbisrOwoJdWludDY0X3QgYSA9IDE7Cgl1aW50NjRfdCBiID0gMDsKCXVpbnQ2NF90IHQ7Cglmb3IgKGludCBpID0gMCA7IGkgPCA2NCA7IGkrKykgewoJCXQgPSBiICogYjsgLy8gdCDihpAgMCA9IDAgKiAwCgkJYiA9IDIgKiBhICogYiArIHQ7IC8vIHQg4oaQIDAgPSAyICogMSAqIDAgKyAwCgkJYSA9IGEgKiBhICsgdDsgLy8gYSDihpAgMSA9IDEgKiAxICsgMAoJCWlmIChuICYgMHg4MDAwMDAwMDAwMDAwMDAwKSB7CgkJCS8vIO++j++9su++he+9veOBq+OBr+OBquOCieOBquOBhCDjgZPjgZPjga/jgajjgYrjgonjgarjgYQKCQkJdCA9IGI7CgkJCWIgPSBhICsgYjsKCQkJYSA9IHQ7CgkJfQoJCW4gKz0gbjsgLy8g5LiA5YiH5L2/44KP44Gq44GE57eP5ZKMKDHvvZ5uKeOCkuaxguOCgeOBpuOCiwoJfQoJcmV0dXJuIGE7Cn0KCmludCBtYWluKGludCBhcmdjLCBjaGFyKiBhcmd2W10pIHsKCglmb3IgKHVuc2lnbmVkIGludCBpID0gMDsgaSA8IDk0OyArK2kpIHsKCQlwcmludGYgKCJuID0gJWQgKHopJSIgUFJJdTY0ICIgKGYpJSIgUFJJdTY0ICIgKG0pJSIgUFJJdTY0ICIgKGFobyklIiBQUkl1NjQgIlxuIiwgaSwgZmlib25hY2NpX3ooaSksIGZpYm9uYWNjaV9mKGkpLCBmaWJvbmFjY2lfbShpKSwgZmlib25hY2NpX2FobyhpKSk7Cgl9CglnZXRjaGFyKCk7CglyZXR1cm4gMDsKfQo=