所以我正在学习C ++。我已经获得了“C ++编程语言”和“有效的C ++”,而且我正在运行Project Euler。问题1 ... dunzo。问题2 ......没那么多。我在Win32控制台应用程序中使用VS2008。
斐波纳契数列的所有偶数项的总和是400万?
它没有工作,所以我减少了100个测试用例...
这是我写的......
// Problem2.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
cout << "Project Euler Problem 2:\n\n";
cout << "Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:\n\n";
cout << "1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...\n\n";
cout << "Find the sum of all the even-valued terms in the sequence which do not exceed four million.\n\n";
cout << "Answer: " << Solve();
}
double Solve() {
int FibIndex = 0;
double result = 0.0;
double currentFib = GenerateNthFibonacciNumber(FibIndex);
while (currentFib < 100.0){
cout << currentFib << " " << (int)currentFib << " " << (int)currentFib % 2 << "\n";
if ((int)currentFib % 2 == 0){
result += currentFib;
cout<<(int)currentFib;
}
currentFib = GenerateNthFibonacciNumber(++FibIndex);
}
return result;
}
double GenerateNthFibonacciNumber(const int n){
//This generates the nth Fibonacci Number using Binet's Formula
const double PHI = (1.0 + sqrt(5.0)) / 2.0;
return ((pow(PHI,n)-pow(-1.0/PHI,n)) / sqrt(5.0));
}
这是输出......
项目欧拉问题2:
Fibonacci中的每个新术语 序列是通过添加 前两个任期。从1开始 2,前10个术语将是:
1,2,3,5,8,13,21,34,55,89,......
找出所有偶数值的总和 序列中没有的术语 超过四百万。
0 0 0
1 1 1 1 1 1 2 2 0
3 3 1
5 5 1
8 8 0
13 1
21 21 1
34 34 0
55 54 0
89 89 1
答案:99
所以我有三列调试代码...从generate函数返回的数字,(int)generatedNumber和(int)generatedNumber%2
所以在第11个学期我们有
55,54,0
为什么(int)55 = 54?
由于
答案 0 :(得分:56)
转换为int
会截断数字 - 就像您调用floor(currentFib)
一样。因此,即使currentFib
为54.999999
...(数字如此接近55,打印时会被舍入),(int)currentFib
也会产生54。
答案 1 :(得分:13)
由于浮点舍入,55行计算的是54.99999。 将double转换为int会截断.99999。
在我的机器上,打印显示(currentFib-(int)currentFib)
的列会显示1.42109e-14的错误。所以它更像是0.999999999999986。
答案 2 :(得分:4)
好的,简短的回答是,在任何情况下都不应该(int)55 == 54,所以你需要开始问自己相关的代码行是什么。
第一个问题:与类型转换相比,==
绑定的强度有多大?
答案 3 :(得分:4)
Shog9是正确的,使用double类型来解决这个问题,如果你要将内容强制转换为最好的方法。如果您的编译器支持它,您应该使用long long或其他64位整数类型,这几乎肯定会保留所有偶数项的总和小于4百万Fibonacci序列的结果。
如果我们使用Fibonacci序列遵循奇数奇数甚至奇数奇数偶数的事实......如下所示应该做的伎俩。
...
unsigned int fib[3];
fib[0]=1;
fib[1]=1;
fib[2]=2;
unsigned long long sum=0;
while(fib[2]<4000000)
{
sum+=fib[2];
fib[0]=(fib[1]+fib[2]);
fib[1]=(fib[2]+fib[0]);
fib[2]=(fib[0]+fib[1]);
}
std::cout<<"The sum is: "<<sum<<". \n";
....
应该做的伎俩,可能有更快的方法,但这个方法非常直接,易于阅读。
看着它我意识到你可能会使用一个标准的无符号32位整数作为和数,但我会保留它以防万一。
此外,您的代码会对生成第n个Fibonacci数函数进行大量函数调用。一个不错的优化编译器会内联这些调用,但如果没有,那么事情会变慢,因为函数调用比其他技术更昂贵。
答案 4 :(得分:2)
我同意100%使用shog9的答案 - 使用你用来计算Fibonacci的算法,你必须非常小心浮点值。我发现页面cubbi.com: fibonacci numbers in c++似乎显示了获取它们的其他方式。
我四处寻找一个关于如何使GenerateNthFibonacciNumber处理它返回双54.999999的情况的好主意,但当你转换为int或long时,你得到54。
我在C++ Rounding看到了一个合理的解决方案,我在下面的代码中进行了调整。
此外,这不是一个巨大的交易,但您可能想要预先计算PHI,然后将其作为参数传递或将其作为全局引用 - 现在您每次调用时都会重新计算它功能
double GenerateNthFibonacciNumber(const int n)
{
//This generates the nth Fibonacci Number using Binet's Formula
const double PHI = (1.0 + sqrt(5.0)) / 2.0;
double x = ((pow(PHI,n)-pow(-1.0/PHI,n)) / sqrt(5.0));
// inspired by http://www.codingforums.com/archive/index.php/t-10827.html
return ((x - floor(x)) >= 0.5) ? ceil(x) : floor(x);
}
最后,这是我如何重写你的Solve()方法,以便只在代码中的一个地方调用GenerateNthFibonacciNumber(FibIndex)。我还在列中添加了当前运行总计甚至Fibonacci项的列到您的输出:
double Solve() {
long FibIndex = 0;
double result = 0.0;
double oldresult = 0.0;
int done = 0;
const double PHI = (1.0 + sqrt(5.0)) / 2.0;
while (!done)
{
double currentFib = GenerateNthFibonacciNumber(++FibIndex);
if ((int)currentFib % 2 == 0)
{
oldresult = result;
if (currentFib >= 4000000.0)
{
done = 1;
}
else
{
result += currentFib;
}
}
cout << currentFib << " " << (int)currentFib << " " << (int)currentFib % 2 << " " << (int)result << "\n";
}
return result;
}
答案 5 :(得分:2)
我知道这对你的真实问题没有帮助,但是你提到你正在学习C ++。出于学习目的,我建议尽可能接近ANSI。我认为MSVC上的/Za
(你可能正在使用它),或GCC上的-ansi -pedantic
。
特别是,您应该使用其中一个签名main
,直到您有一个良好的(特定于平台的)原因:
int main(int argc, char *argv[]);
int main(int argc, char **argv); // same as the first
int main();
...而不是任何特定于平台的版本,例如此(仅限Windows)示例:
#include <windows.h> // defines _TCHAR and _tmain
int _tmain(int argc, _TCHAR* argv[]); // win32 Unicode vs. Multi-Byte
答案 6 :(得分:2)
以上所有不使用整数数学浮点值的建议都值得注意!
如果要对正浮点值进行整数“舍入”,以使小数分量小于0.5的值舍入到下一个最小整数,小数分量为0.5或更大的值舍入到下一个更高的整数,例如< / p>
0.0 = 0
0.1 = 0
0.5 = 1
0.9 = 1
1.0 = 1
1.1 = 1
...etc...
将0.5加到你正在施放的值上。
double f0 = 0.0;
double f1 = 0.1;
double f2 = 0.5;
double f3 = 0.9;
int i0 = ( int )( f0 + 0.5 ); // i0 = 0
int i1 = ( int )( f1 + 0.5 ); // i1 = 0
int i2 = ( int )( f2 + 0.5 ); // i2 = 1
int i3 = ( int )( f3 + 0.5 ); // i3 = 1
答案 7 :(得分:0)
打破代码生成,有时浮点数不会像我们在长表达式中使用时那样思考...打破代码并检查它。