精确度问题在于找到将数字表示为平方和的方法的数量

时间:2012-06-14 04:21:11

标签: algorithm math

我正在尝试这个问题,http://www.spoj.pl/problems/TWOSQ/。我们必须找到表示数字(大到10 ^ 15)作为平方和的不同方式的数量(不计算两次,即5 ^ 2 + 1 ^ 2和1 ^ 2 + 5 ^ 2是相同的) 。我以前见过这个任务,这也是我之前解决的问题。我不断得到法官的错误答案。有人可以告诉我为什么吗?或者建议采用不同的方法。我已经根据需要添加了评论以便理解。提前谢谢!。

#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;

int main()
{
long long X;
cin >> X;
const double EPS = 1e-6;
long long int count = 0;
// add EPS to avoid flooring x.99999 to x
for (int a = 0; a <= sqrt(X/2) + EPS; a++)
{
    long long int b2 = X - a*a; // b^2
    long long int b = (long long int) (sqrt(b2) + EPS);
    if (abs(b - sqrt(b2)) < EPS) // check b is an integer
        count++;
}
cout << count << endl;

}

4 个答案:

答案 0 :(得分:1)

我可以看到两个问题。

  1. 在计算b2时,使用表达式a*a。如果a只是一个int,那么这将很快溢出。
  2. EPS的价值太大了。你会得到误报。
  3. 使用最多53个有效位存储双精度浮点数。这意味着可以精确表示大约8e15的所有整数。要使这个数字的平方根正确舍入,你需要大约两倍的精度,这样你就可以得到4e15,仍在你的范围内。

    所以,我会做两件事:

    1. 将我的所有变量更改为双打。
    2. 完全取消EPS并使用精确比较。它们应该在您指定的范围内正常工作(最多X = 1e15)。

答案 1 :(得分:0)

你在主循环中使用EPS存在根本缺陷(可以想象它可以避免任何实际的错误,因为丢番图的原因,但这需要更多的思考而不是保证)。假设X / 2非常接近完美的正方形,例如10 ^ 14-1。然后sqrt(X / 2)将是大约10 ^ 7 - 0.5 * 10 ^ -7,它将使双精度浮点数下溢并舍入到10 ^ 7。

为什么不在2 * a * a&gt;时停止循环? X?当然,修复整数溢出危险。

答案 2 :(得分:0)

我想我知道你要做什么,它很酷......试试这个:

#include<cstdio>
#include<iostream>
#include<cmath>

using namespace std;

typedef unsigned long long int data_type;

int main()
{
    data_type value = 0,
              count = 0, 
              index = 0, 
              max = 0,         
              b_1 = 0; 

    cin >> value;
    max = (data_type)sqrt(value);
    char *flags = new char[max];
    memset(flags, 0, max);

    for (index = 0; index < max; index++)
    {   
        b_1 = value - (index * index);        

        if (!((data_type)sqrt(b_1) - sqrt(b_1)) && !flags[(data_type)(sqrt(b_1))] && !flags[index])
        {
            flags[(data_type)sqrt(b_1)] = 1;
            flags[index] = 1;
            count++;                          
        }
    }        

    cout << count << endl;
}

据我所知,然后采取差异,通过取平方根并检查任何剩余的浮点值,检查这个差异本身是否是一个完美的正方形,有点酷。

尚未经过全面测试如果有任何错误或问题,我会道歉。

我认为这个问题很重要。

请注意,(10**15)**.5约为32兆,因此将分配多少 祝你好运。

答案 3 :(得分:0)

我尝试了很多但是因为某种原因仍然得到了错误的答案。因此,我研究了一种不同的方法,并且能够找到这个非常快速的解决方案。

 long long L=res=0, R=(long long)sqrt(X) + 1;     
while (L<=R)
{
    long long Y = L*L + R*R;
    if (Y > X) R--;
    else if (Y < X) L++;
    else res++, L++;
}