以模数整数空间

时间:2015-08-19 14:18:24

标签: c algorithm conditional integer-overflow

我想知道最有效的公式是什么,用于测试三个数字是否是毕达哥拉斯三元组 提醒一下:毕达哥拉斯三重奏是三个整数a²+b²=c²

我的意思不是时间上最有效的公式,而是一个在不导致特定整数溢出方面最有效的公式(假设 32位unsigned int

我正在尝试重新安排a*a + b*b == c*c

  

让我们假设a<=b<c,那么我能得到的最佳公式是:
  2b*(c-b) == (a+b-c) * (a-b+c)
  使用此公式可以证明,右侧小于a*c因此应该是左侧,但a*c看起来不像c*c的巨大改进。

所以我的问题是,如果有一个更好的公式,这个条件适用于更大的数字而不会溢出整数空间。公式的执行时间并不重要,除了它应该是O(1)。

PS:我不知道我是否应该在Mathematics SE发布这样的问题,但对我而言,似乎更多的是关于编程。

2 个答案:

答案 0 :(得分:2)

我认为很少的重新安排会有很大的帮助。

a²+b²=c² 

can be written as b²=c²-a²

which is b² = (c-a)(c+a)

and hence we arrive at

b/(c+a) = (c-a)/b

or (c+a)/b = b/(c-a)

现在使用上面的等式,您不需要计算平方。

所以我们必须这样做

  if(((c+a)/(double)b)==((double)(b)/(c-a)))
    printf("Yes it is pythagorean triples");
  else printf("No it is not");

答案 1 :(得分:2)

编辑如果你需要一直有32位整数,那么你可以修改数学以满足你的要求。为了简单起见,我对16位数据块进行数学运算(平方和求和),并使用包含2个无符号整数的结构作为结果。

http://ideone.com/er2TaS

#include <iostream>
using namespace std;
struct u64 {
    unsigned int lo;
    unsigned int hi;
    bool of;
};
u64 square(unsigned int a) {
    u64 result;
    unsigned int alo = (a & 0xffff);
    unsigned int ahi = (a >> 16);
    unsigned int aalo = alo * alo;
    unsigned int aami = alo * ahi;
    unsigned int aahi = ahi * ahi;
    unsigned int aa1 = aalo & 0xffff;
    unsigned int aa2 = (aalo >> 16) + (aami & 0xffff) + (aami & 0xffff);
    unsigned int aa3 = (aa2 >> 16) + (aami >> 16) + (aami >> 16) + (aahi & 0xffff);
    unsigned int aa4 = (aa3 >> 16) + (aahi >> 16);
    result.lo = (aa1 & 0xffff) | ((aa2 & 0xffff) << 16);
    result.hi = (aa3 & 0xffff) | (aa4 << 16);
    result.of = false; // 0xffffffff^2 can't overflow
    return result;
}
u64 sum(u64 a, u64 b) {
    u64 result;
    unsigned int a1 = a.lo & 0xffff;
    unsigned int a2 = a.lo >> 16;
    unsigned int a3 = a.hi & 0xffff;
    unsigned int a4 = a.hi >> 16;
    unsigned int b1 = b.lo & 0xffff;
    unsigned int b2 = b.lo >> 16;
    unsigned int b3 = b.hi & 0xffff;
    unsigned int b4 = b.hi >> 16;
    unsigned int s1 = a1 + b1;
    unsigned int s2 = a2 + b2 + (s1 >> 16);
    unsigned int s3 = a3 + b3 + (s2 >> 16);
    unsigned int s4 = a4 + b4 + (s3 >> 16);
    result.lo = (s1 & 0xffff) | ((s2 & 0xffff) << 16);
    result.hi = (s3 & 0xffff) | ((s4 & 0xffff) << 16);
    result.of = (s4 > 0xffff ? true : false);
    return result;
}
bool isTriple(unsigned int a, unsigned int b, unsigned int c) {
    u64 aa = square(a);
    u64 bb = square(b);
    u64 cc = square(c);
    u64 aabb = sum(aa, bb);
    return aabb.lo == cc.lo && aabb.hi == cc.hi && aabb.of == false;
}
int main() {
    cout << isTriple(3,4,5) << endl;
    cout << isTriple(2800,9600,10000) << endl;

    return 0;
}

将32位整数分成64位长或甚至浮点双精度编辑 减少溢出的可能性并继续以编程方式O(1),因为所有主要的体系结构(x86,ARM等)在低级别具有int到double转换操作码,并且从int转换为long也是O(1)操作。

bool isTriple(int a, int b, int c) {
long long bigA = a;
long long bigB = b;
long long bigC = c;
return bigA * bigA + bigB * bigB == bigC * bigC;
}