使用浮点数时计算错误

问题描述 投票:1回答:4

我正在尝试进行计算,由于某种原因,当我使用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]);
}

enter image description here

c variables math double calculation
4个回答
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);

0
投票

使用浮点数时,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

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)产生的floatdouble的结果略有不同。

至此,让我们研究实际的差异:

  1. (float)0.8的值和(double)0.8的值之间
  2. (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

这能回答您的问题吗?


0
投票

您正在获得四舍五入的累积舍入,其超出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

更符合期望。

© www.soinside.com 2019 - 2024. All rights reserved.