zod*_*iac 7 c algorithm geometry computational-geometry
我试图检查三角形是否是C语言中的直角三角形.a
,b
并且c
是一些三角形的边长.
int is_right_triangle(int a, int b, int c)
{
return (a * a + b * b == c * c || a * a + c * c == b * b || b * b + c * c == a * a);
}
Run Code Online (Sandbox Code Playgroud)
如何避免求和和乘法中的整数溢出?假设我们没有long long
类型.
改进(优化)版本
int
)int is_right_triangle(int a, int b, int c)
{
unsigned int sum, diff;
int f = 2; /* factor */
unsigned int hcf, irts, irtd;
/* sort */
if(b > c) swap(&b, &c);
if(a > b) swap(&a, &b);
if(b > c) swap(&b, &c);
sum = c;
diff = c;
sum += a;
diff -= a;
hcf = gcd(sum, diff);
if(b % hcf != 0) return 0;
sum /= hcf;
diff /= hcf;
b /= hcf;
irts = isqrt(sum);
if(irts * irts != sum || b % irts != 0) return 0;
b /= irts;
irtd = isqrt(diff);
if(irtd * irtd != diff || b % irtd != 0) return 0;
b /= irtd;
return b == 1;
}
Run Code Online (Sandbox Code Playgroud)
isqrt
可以找到@Methods_of_computing_square_roots的算法或者使用二分查找的方法。
#define NEXT(n, i) (((n) + (i)/(n)) >> 1)
unsigned int isqrt(int number) {
unsigned int n = 1;
unsigned int n1 = NEXT(n, number);
while(abs(n1 - n) > 1) {
n = n1;
n1 = NEXT(n, number);
}
while(n1*n1 > number)
n1--;
return n1;
}
Run Code Online (Sandbox Code Playgroud)
isqrt
从codecodex直接复制过来,没有任何改变
旧答案
int
)int is_right_triangle(int a, int b, int c)
{
unsigned int sum, diff;
int f = 2; /* factor */
/* sort */
if(b > c) swap(&b, &c);
if(a > b) swap(&a, &b);
if(b > c) swap(&b, &c);
sum = c;
diff = c;
sum += a;
diff -= a;
while(f * f <= sum || f * f <= diff) {
int count = 0;
while(sum % f == 0) { sum /= f; ++count; }
while(diff % f == 0) { diff /= f; ++count; }
if(count % 2 == 1) return 0;
while(count != 0) {
b /= f;
count -= 2;
}
++f; /* f = (f == 2 ? 3 : f + 2); */
}
return b == 1;
}
Run Code Online (Sandbox Code Playgroud)
优化
1. 正如此评论中提到的,您可以用 gcd(unsigned_sum, unsigned_diff) 除 unsigned_sum、unsigned_diff 和 b,并且可以分别处理 unsigned_sum 和 unsigned_diff。
2. 在循环中,如果您可以在任何点检查sum
和diff
(以及 b 的平方)的乘积保证不会溢出,您可以进行sum * diff == (unsigned)b * b
相应的检查和中断。