基于结构体的C语言梯形面积周长计算函数:测试用例未通过
梯形面积计算错误修复
问题描述
给定以下结构体定义:
struct Point { double x, y; }; struct Trapezoid { struct Point A,B,C,D; };
需要实现trapezoids函数,接收梯形数组、数组大小,以及两个空数组,分别存储每个梯形的周长和面积。现有代码在部分测试用例中计算结果不符,测试用例中4个梯形预期面积均为16.50,但实际输出为11.67 36.83 16.50 33.00。
原代码问题分析
- 平行边假设错误:原代码默认AB和CD是梯形的平行底边,但测试用例中部分梯形的平行边为AD和BC(如第4个测试用例),导致底边长取值错误。
- 高的计算逻辑错误:原代码用对角线BD的长度结合角度正弦值计算高,这不符合梯形高的定义——梯形的高是两平行底边之间的垂直距离,而非对角线相关的推导值。
- 浮点数精度处理缺失:直接用
==判断斜率是否相等,会因浮点数计算误差导致平行边判断失效。
修复后的代码
#include <stdio.h> #include <math.h> #include <stdbool.h> struct Point { double x; double y; }; struct Trapezoid { struct Point A, B, C, D; }; double distance(struct Point p1, struct Point p2) { double dx = p2.x - p1.x; double dy = p2.y - p1.y; return sqrt(dx * dx + dy * dy); } // 判断两个浮点数是否相等(考虑精度误差) bool isEqual(double a, double b) { return fabs(a - b) < 1e-8; } // 获取直线ax + by + c = 0的参数a、b、c void getLineParams(struct Point p1, struct Point p2, double *a, double *b, double *c) { *a = p2.y - p1.y; *b = p1.x - p2.x; *c = p2.x * p1.y - p1.x * p2.y; } // 计算点到直线的距离 double pointToLineDistance(struct Point p, double a, double b, double c) { return fabs(a * p.x + b * p.y + c) / sqrt(a*a + b*b); } void trapezoids(struct Trapezoid trapezoids[], int n, double perimeters[], double areas[]) { for (int i = 0; i < n; i++) { struct Trapezoid t = trapezoids[i]; // 计算四条边长度,用于周长计算 double AB = distance(t.A, t.B); double BC = distance(t.B, t.C); double CD = distance(t.C, t.D); double DA = distance(t.D, t.A); perimeters[i] = AB + BC + CD + DA; // 计算各边的斜率,处理垂直边(用INFINITY标记) double slope_AB = isEqual(t.B.x, t.A.x) ? INFINITY : (t.B.y - t.A.y)/(t.B.x - t.A.x); double slope_BC = isEqual(t.C.x, t.B.x) ? INFINITY : (t.C.y - t.B.y)/(t.C.x - t.B.x); double slope_CD = isEqual(t.D.x, t.C.x) ? INFINITY : (t.D.y - t.C.y)/(t.D.x - t.C.x); double slope_DA = isEqual(t.A.x, t.D.x) ? INFINITY : (t.A.y - t.D.y)/(t.A.x - t.D.x); double base1, base2, height; // 确定平行的对边 if (isEqual(slope_AB, slope_CD)) { // AB与CD平行,作为上下底 base1 = AB; base2 = CD; // 计算点C到直线AB的距离作为高 double a, b, c; getLineParams(t.A, t.B, &a, &b, &c); height = pointToLineDistance(t.C, a, b, c); } else if (isEqual(slope_DA, slope_BC)) { // DA与BC平行,作为上下底 base1 = DA; base2 = BC; // 计算点B到直线DA的距离作为高 double a, b, c; getLineParams(t.D, t.A, &a, &b, &c); height = pointToLineDistance(t.B, a, b, c); } else { // 非梯形输入,按题目假设可忽略,此处设面积为0 areas[i] = 0.0; continue; } // 梯形面积公式:(上底+下底)/2 × 高 areas[i] = 0.5 * (base1 + base2) * height; } } // 测试用例主函数示例 int main() { struct Trapezoid array[] = { {{-4,2}, {0.950, 6.950}, {-2.586, 7.657}, {-5.414, 4.828}}, // 45度 {{-4,2}, {-7.5, 8.062}, {-9.098, 4.830}, {-7.098, 1.366}}, // 120度 {{-4,2}, {-11, 2}, {-9, -1}, {-5, -1}}, // 180度 {{-4,2}, {-4, -5}, {-1, -3}, {-1, 1}} // 270度 }; double perimeters[4], areas[4]; trapezoids(array, 4, perimeters, areas); for (int i = 0; i < 4; i++) { printf("%.2f ", areas[i]); } // 输出应为:16.50 16.50 16.50 16.50 return 0; }
修复说明
- 动态识别平行边:通过计算四条边的斜率,结合精度判断,自动识别哪组对边平行,避免固定假设的错误。
- 正确计算高:使用点到直线的距离公式,计算平行底边之间的垂直距离,作为梯形的高。
- 浮点数精度处理:用
isEqual函数判断浮点数是否相等,允许1e-8的误差范围,避免计算误差导致的判断错误。
内容的提问来源于stack exchange,提问作者Irma Ibrović
相关产品推荐
相关产品推荐

