我正在编写代码以获取非常大的斐波那契数字的最后一位数字,例如fib(239)等。我使用字符串存储数字,从头到尾抓取各个字符然后将它们转换为int而不是将值存储回另一个字符串。我无法测试我写的内容,因为我的程序在std::cin >> n;
行之后突然关闭。
这是我到目前为止所拥有的。
#include <iostream>
#include <string>
using std::cin;
using std::cout;
using namespace std;
char get_fibonacci_last_digit_naive(int n) {
cout << "in func";
if (n <= 1)
return (char)n;
string previous= "0";
string current= "1";
for (int i = 0; i < n - 1; ++i) {
//long long tmp_previous = previous;
string tmp_previous= previous;
previous = current;
//current = tmp_previous + current; // could also use previous instead of current
// for with the current length of the longest of the two strings
//iterates from the end of the string to the front
for (int j=current.length(); j>=0; --j) {
// grab consectutive positions in the strings & convert them to integers
int t;
if (tmp_previous.at(j) == '\0')
// tmp_previous is empty use 0 instead
t=0;
else
t = stoi((string&)(tmp_previous.at(j)));
int c = stoi((string&)(current.at(j)));
// add the integers together
int valueAtJ= t+c;
// store the value into the equivalent position in current
current.at(j) = (char)(valueAtJ);
}
cout << current << ":current value";
}
return current[current.length()-1];
}
int main() {
int n;
std::cin >> n;
//char& c = get_fibonacci_last_digit_naive(n); // reference to a local variable returned WARNING
// http://stackoverflow.com/questions/4643713/c-returning-reference-to-local-variable
cout << "before call";
char c = get_fibonacci_last_digit_naive(n);
std::cout << c << '\n';
return 0;
}
输出始终如一。无论我为n输入什么,输出总是相同的。这是我用来运行代码及其输出的行。
$ g++ -pipe -O2 -std=c++14 fibonacci_last_digit.cpp -lm
$ ./a.exe
10
在10之后有一个换行符,而我输入的是n。 我感谢任何帮助。祝节日快乐!
答案 0 :(得分:7)
我发布此信息是因为您对该问题的理解似乎已经落后于您尝试部署的解决方案的选择。这是XY Problem的一个示例,其中选择解决方案方法以及问题或障碍及其实现会混淆您尝试解决的实际问题。
你正试图计算第N Fibonacci number的最后一位数,其中N可能是合群的。对斐波那契序列的基本了解告诉你
fib(0) = 0 fib(1) = 1 fib(n) = fib(n-1) + fib(n-2), for all n larger than 1.
为其值解决fib(N)
的迭代解决方案将是:
unsigned fib(unsigned n)
{
if (n <= 1)
return n;
unsigned previous = 0;
unsigned current = 1;
for (int i=1; i<n; ++i)
{
unsigned value = previous + current;
previous = current;
current = value;
}
return current;
}
这一切都很好,但是一旦N
导致我们选择的数据类型的存储功能溢出(在上面的情况下,大多数32位平台上的unsigned
将溢出后,显然会溢出仅仅47次迭代)。
但我们不需要每次迭代的实际fib
值。我们只需要每次迭代的最后一位数。好吧,基数10的最后一位数很容易从任何无符号值中获得。对于我们的示例,只需替换它:
current = value;
用这个:
current = value % 10;
给我们一个几乎相同的算法,但只有&#34;记住&#34;每次迭代的最后一位数字:
unsigned fib_last_digit(unsigned n)
{
if (n <= 1)
return n;
unsigned previous = 0;
unsigned current = 1;
for (int i=1; i<n; ++i)
{
unsigned value = previous + current;
previous = current;
current = value % 10; // HERE
}
return current;
}
现在current
总是保留先前总和的最后一位数,无论该先前总和是否超过10或者与我们无关。一旦我们有了,下一次迭代就可以用它来计算两个单个正数的总和,这个数字不能超过18,再次,我们只需要 的最后一个数字 / em>迭代等等。这一直持续到我们多次请求迭代,并在完成时,最终答案将出现。
<强>验证强>
我们知道前20个左右的斐波纳契数字看起来像这样,贯穿fib
:
0:0
1:1
2:1
3:2
4:3
5:5
6:8
7:13
8:21
9:34
10:55
11:89
12:144
13:233
14:377
15:610
16:987
17:1597
18:2584
19:4181
20:6765
以下是我们通过fib_last_digit
运行算法时得到的结果:
0:0
1:1
2:1
3:2
4:3
5:5
6:8
7:3
8:1
9:4
10:5
11:9
12:4
13:3
14:7
15:0
16:7
17:7
18:4
19:1
20:5
这应该会给你一种崭露头角的信心,这可能就是你所寻求的算法,你可以完全放弃字符串操作。
答案 1 :(得分:1)
在Mac上运行此代码我得到:
libc++abi.dylib: terminating with uncaught exception of type std::out_of_range: basic_string before callin funcAbort trap: 6
代码本身最明显的问题是以下几行:
for (int j=current.length(); j>=0; --j) {
原因:
此外,正如其他人所指出的那样,如果您唯一感兴趣的是最后一位数字,那么您不需要经历遍历每个数字的每个数字的麻烦。这里的诀窍是只记住前一个和当前的最后一个数字,所以大数字永远不是问题,你不必做像stoi这样的事情。
答案 2 :(得分:1)
作为先前答案的替代方案将是字符串添加。 我用斐波纳契数100000测试它,它在几秒钟内就可以正常工作。只使用最后一位数字可以解决您的问题,确保更大的数字。对于你们所有需要斐波纳契数的人来说,这里有一个算法:
std::string str_add(std::string a, std::string b)
{
// http://ideone.com/o7wLTt
size_t n = max(a.size(), b.size());
if (n > a.size()) {
a = string(n-a.size(), '0') + a;
}
if (n > b.size()) {
b = string(n-b.size(), '0') + b;
}
string result(n + 1, '0');
char carry = 0;
std::transform(a.rbegin(), a.rend(), b.rbegin(), result.rbegin(), [&carry](char x, char y)
{
char z = (x - '0') + (y - '0') + carry;
if (z > 9) {
carry = 1;
z -= 10;
} else {
carry = 0;
}
return z + '0';
});
result[0] = carry + '0';
n = result.find_first_not_of("0");
if (n != string::npos) {
result = result.substr(n);
}
return result;
}
std::string str_fib(size_t i)
{
std::string n1 = "0";
std::string n2 = "1";
for (size_t idx = 0; idx < i; ++idx) {
const std::string f = str_add(n1, n2);
n1 = n2;
n2 = f;
}
return n1;
}
int main() {
const size_t i = 100000;
const std::string f = str_fib(i);
if (!f.empty()) {
std::cout << "fibonacci of " << i << " = " << f << " | last digit: " << f[f.size() - 1] << std::endl;
}
std::cin.sync(); std::cin.get();
return 0;
}
答案 3 :(得分:0)
首先计算斐波纳契数,然后使用int
将std::string
转换为std::to_string()
。在下文中,您可以使用最后一个索引上的[]
运算符提取最后一位数字。
int fib(int i)
{
int number = 1;
if (i > 2) {
number = fib(i - 1) + fib(i - 2);
}
return number;
}
int main() {
const int i = 10;
const int f = fib(i);
const std::string s = std::to_string(f);
if (!s.empty()) {
std::cout << "fibonacci of " << i << " = " << f << " | last digit: " << s[s.size() - 1] << std::endl;
}
std::cin.sync(); std::cin.get();
return 0;
}
避免使用关键字using
重复。
当您的号码变大时,还要考虑从int
切换到long
或long long
。由于斐波纳契数是正数,因此也使用unsigned
。