使用uint64_t实现point_add函数时输出异常的修复求助
椭圆曲线点加法函数异常修复
问题背景
需要实现point_add()函数完成不同点的加法操作,但原代码运行仅第三个测试用例正确,前两个出现异常,修改后问题仍未解决。
原代码
#include <stdio.h> #include <stdint.h> typedef struct { uint64_t x; uint64_t y; } point; point point_add(point P, point Q){ point R; R.x = 0; R.y = 0; if(P.x == Q.x && P.y == Q.y) return R; double s = ((double)(P.y - Q.y))/((double)(P.x-Q.x)); R.x=s*s-P.x-Q.x; R.y=s*(P.x-Q.x)-P.y; return R; } int main(){ point A = {1, 2}; point B = {3, 4}; point C = {5, 6}; point D; // Test case 1: A + B D = point_add(A, B); printf("(%lu, %lu) + (%lu, %lu) = (%lu, %lu)\n", A.x, A.y, B.x, B.y, D.x, D.y); // Expected output: (1, 2) + (3, 4) = (2, 3) // Test case 2: B + C D = point_add(B, C); printf("(%lu, %lu) + (%lu, %lu) = (%lu, %lu)\n", B.x, B.y, C.x, C.y, D.x, D.y); // Expected output: (3, 4) + (5, 6) = (-11, -30) // Test case 3: A + A D = point_add(A, A); printf("(%lu, %lu) + (%lu, %lu) = (%lu, %lu)\n", A.x, A.y, A.x, A.y, D.x, D.y); // Expected output: (1, 2) + (1, 2) = (0, 0) return 0; }
原代码运行输出
(1, 2) + (3, 4) = (18446744073709551613, 9223372036854775808) (3, 4) + (5, 6) = (18446744073709551609, 9223372036854775808) (1, 2) + (1, 2) = (0, 0)
修改后的代码(仍存在问题)
point point_add(point P, point Q){ point R; uint16_t s; s = (P.y - Q.y) / (P.x - Q.x); if((P.x == Q.x && P.y == Q.y)|| (P.x == Q.x && P.x != Q.x)|| s<0){ R.x = 0; R.y = 0;} R.x=s*s-P.x-Q.x; R.y=s*(P.x-Q.x)-P.y; return R; } int main(){ point A = {1, 2}; point B = {3, 4}; point C = {5, 6}; point D; D = point_add(A, B); printf("%" PRIu64 ",%" PRIu64"\n", D.x, D.y); // Expected output: (1, 2) + (3, 4) = (2, 3) // Test case 3: A + A D = point_add(A, A); printf("%" PRIu64 ",%" PRIu64"\n", D.x, D.y); // Expected output: (1, 2) + (1, 2) = (0, 0) return 0; }
修改后代码运行输出
18446744073709551613,18446744073709551612 Floating point exception
问题分析与修复方案
核心问题
- 无符号整数溢出:使用
uint64_t存储坐标,计算负数时会触发无符号溢出,导致输出异常大的数值(例如-1会被转换为18446744073709551615)。 - 浮点精度丢失:原代码用
double计算斜率s,当数值较大时会丢失精度,导致结果偏差。 - 逻辑错误:修改后的代码中
(P.x == Q.x && P.x != Q.x)是矛盾条件,且用uint16_t存储s会截断数值,还可能因除数为0触发浮点异常。
正确修复代码
#include <stdio.h> #include <stdint.h> #include <inttypes.h> typedef struct { int64_t x; // 改用有符号整数存储坐标,支持负数结果 int64_t y; } point; point point_add(point P, point Q) { point R; // 处理同点情况(题目要求输入不同点,保留原逻辑返回(0,0)) if (P.x == Q.x && P.y == Q.y) { R.x = 0; R.y = 0; return R; } // 处理垂直线情况(P.x == Q.y但y不同,对应无穷远点,返回(0,0)表示) if (P.x == Q.x) { R.x = 0; R.y = 0; return R; } // 用整数计算斜率,避免浮点精度丢失 int64_t dy = P.y - Q.y; int64_t dx = P.x - Q.x; // 题目示例中斜率均为整数,这里先判断是否为整数斜率 if (dy % dx != 0) { // 非整数斜率情况可根据需求自定义处理,此处返回(0,0) R.x = 0; R.y = 0; return R; } int64_t s = dy / dx; // 代入椭圆曲线点加法公式计算 R.x = s * s - P.x - Q.x; R.y = s * (P.x - R.x) - P.y; return R; } int main() { point A = {1, 2}; point B = {3, 4}; point C = {5, 6}; point D; // Test case 1: A + B D = point_add(A, B); printf("(%" PRId64 ", %" PRId64 ") + (%" PRId64 ", %" PRId64 ") = (%" PRId64 ", %" PRId64 ")\n", A.x, A.y, B.x, B.y, D.x, D.y); // Test case 2: B + C D = point_add(B, C); printf("(%" PRId64 ", %" PRId64 ") + (%" PRId64 ", %" PRId64 ") = (%" PRId64 ", %" PRId64 ")\n", B.x, B.y, C.x, C.y, D.x, D.y); // Test case 3: A + A D = point_add(A, A); printf("(%" PRId64 ", %" PRId64 ") + (%" PRId64 ", %" PRId64 ") = (%" PRId64 ", %" PRId64 ")\n", A.x, A.y, A.x, A.y, D.x, D.y); return 0; }
修复说明
- 改用有符号整数:将
uint64_t替换为int64_t,支持负数坐标输出,避免无符号溢出问题。 - 整数运算替代浮点:用整数计算斜率
s,完全避免浮点精度丢失的问题,同时处理了斜率非整数的边界情况。 - 修正逻辑错误:移除矛盾条件,增加垂直线情况的处理逻辑,确保代码严谨性。
- 规范输出格式:使用
PRId64宏输出int64_t类型,避免格式不匹配导致的输出异常。
内容的提问来源于stack exchange,提问作者affegir
相关产品推荐
相关产品推荐

