为了好玩,我一直在用C ++实现一些数学,我一直在尝试实现Fermats Factorisation Method,但是,我不知道我理解它应该返回什么。我有这个实现,返回105
以获取维基百科文章中给出的示例编号5959。
维基百科中的伪代码如下所示:
尝试a的各种值,希望这是一个正方形。
FermatFactor(N): // N should be odd
a → ceil(sqrt(N))
b2 → a*a - N
while b2 isn't a square:
a → a + 1 // equivalently: b2 → b2 + 2*a + 1
b2 → a*a - N // a → a + 1
endwhile
return a - sqrt(b2) // or a + sqrt(b2)
我的C ++实现,如下所示:
int FermatFactor(int oddNumber)
{
double a = ceil(sqrt(static_cast<double>(oddNumber)));
double b2 = a*a - oddNumber;
std::cout << "B2: " << b2 << "a: " << a << std::endl;
double tmp = sqrt(b2);
tmp = round(tmp,1);
while (compare_doubles(tmp*tmp, b2)) //does this line look correct?
{
a = a + 1;
b2 = a*a - oddNumber;
std::cout << "B2: " << b2 << "a: " << a << std::endl;
tmp = sqrt(b2);
tmp = round(tmp,1);
}
return static_cast<int>(a + sqrt(b2));
}
bool compare_doubles(double a, double b)
{
int diff = std::fabs(a - b);
return diff < std::numeric_limits<double>::epsilon();
}
应该归还什么?它似乎只是返回a + b
,这不是5959
的因素?
修改
double cint(double x){
double tmp = 0.0;
if (modf(x,&tmp)>=.5)
return x>=0?ceil(x):floor(x);
else
return x<0?ceil(x):floor(x);
}
double round(double r,unsigned places){
double off=pow(10,static_cast<double>(places));
return cint(r*off)/off;
}
答案 0 :(得分:3)
您的代码中存在两个问题:
compare_doubles
在足够接近时返回true。因此,while循环条件被反转。round
函数需要小数点后的位数。所以你应该使用round(x, 0)
。正如我所建议的那样,将int
用于您的数据类型会更容易。使用整数实现的Here's工作代码。
答案 1 :(得分:3)
请注意,您应该对整数类型进行所有这些计算,而不是浮点类型。它会更简单(也可能更正确)。
您的compare_doubles
功能错误。 diff
应为double
。
一旦你解决了这个问题,你就需要修复你的测试线。如果输入“几乎相等”,compare_doubles
将返回true。你需要在它们“不太平等”时循环。
所以:
bool compare_doubles(double a, double b)
{
double diff = std::fabs(a - b);
return diff < std::numeric_limits<double>::epsilon();
}
和
while (!compare_doubles(tmp*tmp, b2)) // now it is
{
您将获得此输入的正确结果(101
)。
您还需要将round
函数调用0
作为“地点”作为vhallac指出 - 您不应该在小数点后四舍五入到一位数。
您链接的维基百科文章中包含的公式允许您从b
和N
中识别a-b
。
答案 2 :(得分:2)
这两个因素是(a + b)和(a-b)。它正在返回其中一个。你可以很容易地得到另一个。
N = (a+b)*(a-b)
a-b = N/(a+b)