28-三角问题
16.10.1 三角问题
我们可以使用数学库解决一些常见的问题:把 x/y 坐标转换为长度和角度。例如,在网格上画了一条线,该线条水平穿过了4个单元( x 的值),垂直穿过了3个单元( y 的值)。那么,该线的长度(量)和方向是什么?根据数学的三角公式可知:
大小 =square root (x2+y2)
角度 = arctan(y/x)
数学库提供平方根函数和一对反正切函数,所以可以用C程序表示这个问题。平方根函数是 sqrt() ,接受一个 double 类型的参数,并返回参数的平方根,也是 double 类型。
atan() 函数接受一个 double 类型的参数(即正切值),并返回一个角度(该角度的正切值就是参数值)。但是,当线的 x 值和 y 值均为 -5 时, atan() 函数产生混乱。因为 (-5)/(-5) 得 1 ,所以 atan() 返回45°,该值与 x 和 y 均为 5 时的返回值相同。也就是说, atan() 无法区分角度相同但反向相反的线(实际上, atan() 返回值的单位是弧度而不是度,稍后介绍两者的转换)。
当然,C库还提供了 atan2() 函数。它接受两个参数: x 的值和 y 的值。这样,通过检查 x 和 y 的正负号就可以得出正确的角度值。 atan2() 和 atan() 均返回弧度值。把弧度转换为度,只需将弧度值乘以 180 ,再除以 pi 即可。 pi 的值通过计算表达式 4 * atan(1) 得到。程序清单16.14演示了这些步骤。另外,学习该程序还复习了结构和 typedef 相关的知识。
程序清单16.14 rect_pol.c 程序
/* rect_pol.c -- 把直角坐标转换为极坐标 */
#include <stdio.h>
#include <math.h>
#define RAD_TO_DEG (180/(4 * atan(1)))
typedef struct polar_v {
double magnitude;
double angle;
} Polar_V;
typedef struct rect_v {
double x;
double y;
} Rect_V;
Polar_V rect_to_polar(Rect_V);
int main(void)
{
Rect_V input;
Polar_V result;
puts("Enter x and y coordinates; enter q to quit:");
while (scanf("%lf %lf", &input.x, &input.y) == 2)
{
result = rect_to_polar(input);
printf("magnitude = %0.2f, angle = %0.2f\n",
result.magnitude, result.angle);
}
puts("Bye.");
return 0;
}
Polar_V rect_to_polar(Rect_V rv)
{
Polar_V pv;
pv.magnitude = sqrt(rv.x * rv.x + rv.y * rv.y);
if (pv.magnitude == 0)
pv.angle = 0.0;
else
pv.angle = RAD_TO_DEG * atan2(rv.y, rv.x);
return pv;
}
下面是运行该程序后的一个输出示例:
Enter x and y coordinates; enter q to quit:
10 10
magnitude = 14.14, angle = 45.00
-12 -5
magnitude = 13.00, angle = -157.38
q
Bye.
如果编译时出现下面的消息:
Undefined: _sqrt
或
'sqrt': unresolved external
或者其他类似的消息,表明编译器链接器没有找到数学库。UNIX系统会要求使用 -lm 标记(flag)指示链接器搜索数学库:
cc rect_pol.c –lm
注意, -lm 标记在命令行的末尾。因为链接器在编译器编译C文件后才开始处理。在Linux中使用GCC编译器可能要这样写:
gcc rect_pol.c -lm