我想知道最有效的公式是什么,用于测试三个数字是否是毕达哥拉斯三元组
提醒一下:毕达哥拉斯三重奏是三个整数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发布这样的问题,但对我而言,似乎更多的是关于编程。
答案 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个无符号整数的结构作为结果。
#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;
}