当前位置:嗨网首页>书籍在线阅读

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°,该值与 xy 均为 5 时的返回值相同。也就是说, atan() 无法区分角度相同但反向相反的线(实际上, atan() 返回值的单位是弧度而不是度,稍后介绍两者的转换)。

当然,C库还提供了 atan2() 函数。它接受两个参数: x 的值和 y 的值。这样,通过检查 xy 的正负号就可以得出正确的角度值。 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