度与弧度互相转换在软件工程里是非常常见的操作。在C++代码中,可以通过定义宏来方便快捷地进行度与弧度的互相转换。然而,这看似平常的操作,如果疏忽,可能会引入一些比较隐晦的BUG,只有在特定情况下才会被触发。这里的示例来自与本人调试算法时最终定位出来的问题,现将其剥离出来进行说明,引以为戒。
版本一
#include <iostream>
using namespace std;
#define PI 3.1415926535897932384626433832795
#define DEG2RAD(x) (x/180*PI)
#define RAD2DEG(x) (x/PI*180)
int main()
{
double rad = DEG2RAD(90);
cout << "rad = " << rad << endl;
double deg = RAD2DEG(3.14);
cout << "deg = " << deg << endl;
return 0;
}
显然,3.14从弧度转换为度接近180度,这个是正确的。然而90度转换为弧度是0?明显不对,这是因为90和180都是整数,通过整除以后就是0,正确写法应该把180改为180.0,这样除以浮点数以后结果还是浮点数。
版本二
#include <iostream>
using namespace std;
#define PI 3.1415926535897932384626433832795
#define DEG2RAD(x) (x/180.0*PI)
#define RAD2DEG(x) (x/PI*180.0)
int main()
{
double rad = DEG2RAD(90);
cout << "rad = " << rad << endl;
rad = DEG2RAD(90 + 30);
cout << "rad = " << rad << endl;
double deg = RAD2DEG(3.14);
cout << "deg = " << deg << endl;
deg = RAD2DEG(3.14 + 3.14);
cout << "deg = " << deg << endl;
return 0;
}
这里第一个rad和deg计算结果都是对的,但是第二个rad和deg明显是错的。120度对应的弧度不可能这么大,另外两个3.14相加对应的度应该接近360度才对。结合宏定义的本质,仔细分析就会发现问题所在:
DEG2RAD(90 + 30)等价于(90 + 30/180.0*PI)
RAD2DEG(3.14 + 3.14)等价于(3.14 + 3.14/PI*180.0)
x没有加括号!!!
正确版本
#include <iostream>
using namespace std;
#define PI 3.1415926535897932384626433832795
#define DEG2RAD(x) ((x)/180.0*PI)
#define RAD2DEG(x) ((x)/PI*180.0)
int main()
{
double rad = DEG2RAD(179);
cout << "rad = " << rad << endl;
rad = DEG2RAD(20.5 + 25.6);
cout << "rad = " << rad << endl;
double deg = RAD2DEG(3.14);
cout << "deg = " << deg << endl;
deg = RAD2DEG(3.14 + 0.146);
cout << "deg = " << deg << endl;
return 0;
}
总结:当分子分母都是整数但结果要求为浮点数时,注意整除的影响;用宏定义进行表达式计算时,注意隐含的优先级操作。