我正在尝试进行计算,由于某种原因,当我使用float时,我会得到-nan(ind),但是当我将变量(x,y)更改为两倍时,我会正确回答也许你们知道为什么会这样吗?谢谢
#include <stdio.h>
#include <math.h>
#define pi 3.1416
#define L1 0.5
#define L2 0.5
void main()
{
float q1[12], q2[12], q1_Degrees[12], q2_Degrees[12];
float x = 0.8;
float y = 0.6;
q2[0] = acos((pow(x, 2) + pow(y, 2) - pow(L1, 2) - pow(L2, 2)) / (2 * L1*L2));
q1[0] = atan(y / x) - atan((L2*sin(q2[0])) / (L1 + L2 * cos(q2[0])));
q1_Degrees[0] = (q1[0] * 180) / pi;
q2_Degrees[0] = (q2[0] * 180) / pi;
printf_s("q1 is = %.1f q2 is = %.1f\n\n", q1_Degrees[0], q2_Degrees[0]);
}
这可能在这里适用。
x
中的acos(x)
必须在[-1...1]
范围内。除此之外,结果可能是NaN。
[(pow(x, 2) + pow(y, 2) - pow(L1, 2) - pow(L2, 2)) / (2 * L1*L2)
易于受到轻微的计算影响,导致值刚好在[-1 ... 1]之外。
快速解决方法
double z = (pow(x, 2) + pow(y, 2) - pow(L1, 2) - pow(L2, 2)) / (2 * L1*L2);
if (z < -1.0) z = -1.0;
else if (z > 1.0) z = 1.0;
q2[0] = acos(z);
使用浮点数时,q2[0] = atan(1.0000012)
大于1,会导致NaN
。
我对您的代码做了一些更改,以检查分子和分母。
#include <stdio.h>
#include <math.h>
#define pi 3.1416
#define L1 0.5
#define L2 0.5
void main()
{
double q1[12], q2[12], q1_Degrees[12], q2_Degrees[12];
double x = 0.8;
double y = 0.6;
double qq2, qq1;
double numerator, denominator, ratio;
numerator = pow(x, 2) + pow(y, 2) - pow(L1, 2) - pow(L2, 2);
denominator = (2 * L1 * L2);
ratio = numerator / denominator;
qq2 = acos(ratio);
// qq2 = acos((pow(x, 2) + pow(y, 2) - pow(L1, 2) - pow(L2, 2)) / (2 * L1*L2));
qq1 = atan(y / x) - atan((L2*sin(qq2)) / (L1 + L2 * cos(qq2)));
q1_Degrees[0] = (qq1 * 180) / pi;
q2_Degrees[0] = (qq2 * 180) / pi;
printf("q1 is = %.1f q2 is = %.1f\n\n", q1_Degrees[0], q2_Degrees[0]);
}
我在onlinegdb上运行了它-link here尝试将类型改回float并查看变量。
本质上是两倍,该比率变为1.0,这使得atan(1.0)= 0。但是,当使用浮点数时,该比率大于1.0,结果为NaN。
使用浮点数时的变量值-
x 0.800000012
y 0.600000024
numerator 0.50000006
denominator 0.5
ratio 1.00000012
qq2 nan(0x400000)
使用双精度时的变量值-
x 0.80000000000000004
y 0.59999999999999998
numerator 0.5
denominator 0.5
ratio 1
qq2 0
一些基本调试:
首先,您可以将代码范围缩小到:
#include <stdio.h>
#include <math.h>
void main()
{
float x = 0.8;
float y = 0.6;
double q = acos((pow(x, 2) + pow(y, 2) - 0.5) * 2);
printf("q = %lf\n", q);
}
然后,很明显pow(x, 2)
或pow(y, 2)
产生的float
和double
的结果略有不同。
至此,让我们研究实际的差异:
(float)0.8
的值和(double)0.8
的值之间(float)0.6
的值和(double)0.6
的值之间#include <stdio.h>
void main()
{
printf("(float)0.8 = %.10f\n", (float)0.8);
printf("(double)0.8 = %.10lf\n", (double)0.8);
printf("(float)0.6 = %.10f\n", (float)0.6);
printf("(double)0.6 = %.10lf\n", (double)0.6);
}
打印输出为:
(float)0.8 = 0.8000000119
(double)0.8 = 0.8000000000
(float)0.6 = 0.6000000238
(double)0.6 = 0.6000000000
这能回答您的问题吗?
您正在获得四舍五入的累积舍入,其超出acos()
的域。
将示例简化到显示问题的最低限度:
#include <stdio.h>
#include <math.h>
#define L1 0.5
#define L2 0.5
int main()
{
float x = 0.8;
float y = 0.6;
float acos_param = (pow(x, 2) + pow(y, 2) - pow(L1, 2) - pow(L2, 2)) / (2 * L1*L2);
float q2 = acos(acos_param);
printf("acos_param = %.9f; q2 = %.9f\n", acos_param, q2);
return 0;
}
并运行此-带有浮点-我们看到:
acos_param = 1.000000119; q2 = nan
啊哈:大于1.0超出acos
的范围,所以您得到NaN
(不是数字)。
将所有float
更改为double
,我们得到:
acos_param = 1.000000000; q2 = 0.000000000
更符合期望。