比较双打不起作用(看起来总是不同)

时间:2016-12-15 11:26:25

标签: c

我有一个计算poylgnárea和perimeter的程序,程序接收带坐标的文本文件并计算面积。

我对计算有一些问题。现在我试图比较双打,我不明白为什么它不起作用。

我有一个包含3行的文本文件:

1.0 2.5 5.1 5.8 5.9 0.7 
1.2 4.1 5.1 5.8 6.8 1.9 2.9 0.2
1.7 4.9 5.1 5.8 7.0 2.8 4.8 0.1 1.5 1.4

我希望这会产生结果:

    double expectedarea = 11.77;     
    double expectedperimeter = 15.64;     
    double expectedarea1 = 18.10;     
    double expectedperimeter1 = 17.02;     
    double expectedarea2 = 21.33;     
    double expectedperimeter2 = 16.60;  

所以我希望3个案例中出现“Arrays is same”这个消息,因为我给出了正确的值,但是我得到的消息数组在3个案例中是不同的。

你明白为什么我总是得到消息数组不同?

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
enum {x, y};
typedef struct triangle {
    double v1[2];
    double v2[2];
    double v3[2];
} triangle;
double area(triangle a);
double perimeter(double *vertices, int size);
double side(double *p1, double *p2);

double expectedarea = 11.77;     
double expectedperimeter = 15.64;     
double expectedarea1 = 18.10;     
double expectedperimeter1 = 17.02;     
double expectedarea2 = 21.33;     
double expectedperimeter2 = 16.60;     
int main()
{
    int idx;
    int triangles;
    int index;
    int xycount;
    double xy;
    double triangle_area;
    double polygon_area;
    double perim;
    double polygon_vertices[50] = {0.0};
    triangle a;
    FILE* data;
    char line[256];
    char* token;
    if ((data = fopen("test.txt", "r")) == NULL) {
        fprintf(stderr, "can't open data file\n");
        exit (EXIT_FAILURE);
    }
    while (fgets(line, sizeof (line), data)){
        xycount = 0;
        polygon_area = 0;
        line[strlen(line) - 1] = 0;
        token = strtok(line, " ");
        while (token != NULL){
            xy = atof(token);
            token = strtok(NULL, " ");
            polygon_vertices[xycount++] = xy;
        }
        idx = 0;
        triangles = (xycount / 2) - 2;
        for (index = 2, idx = 0;idx < triangles;index += 2, ++idx){
            a.v1[x] = polygon_vertices[0];
            a.v1[y] = polygon_vertices[1];
            a.v2[x] = polygon_vertices[index + 0];
            a.v2[y] = polygon_vertices[index + 1];
            a.v3[x] = polygon_vertices[index + 2];
            a.v3[y] = polygon_vertices[index + 3];
            triangle_area = area(a);
            polygon_area += triangle_area;
        }
        printf("area=%f\t", polygon_area);
        perim = perimeter(polygon_vertices, xycount);
        printf("perimeter=%f\n", perim);

        if(polygon_area == expectedarea && perim == expectedperimeter) {
            printf("Arrays are the same");
        }
        if(polygon_area == expectedarea1 && perim == expectedperimeter1) {
            printf("Arrays are the same");
        }
        if(polygon_area == expectedarea2 && perim == expectedperimeter2) {
            printf("Arrays are the same");
        }

        else {
            printf("Arrays are the different");        }
    }
    fclose(data);
    return 0;
}
/* calculate triangle area with Heron's formula */
double area(triangle a)
{
    double s1, s2, s3, S, area;
    s1 = side(a.v1, a.v2);
    s2 = side(a.v2, a.v3);
    s3 = side(a.v3, a.v1);
    S = (s1 + s2 + s3) / 2;
    area = sqrt(S*(S - s1)*(S - s2)*(S - s3));
    return area;
}
/* calculate polygon perimeter */
double perimeter(double *vertices, int size)
{
    int idx, jdx;
    double p1[2], p2[2], pfirst[2], plast[2];
    double perimeter;
    perimeter = 0.0;
    /* 1st vertex of the polygon */
    pfirst[x] = vertices[0];
    pfirst[y] = vertices[1];
    /* last vertex of polygon */
    plast[x] = vertices[size-2];
    plast[y] = vertices[size-1];
    /* calculate perimeter minus last side */
    for(idx = 0; idx <= size-3; idx += 2)
    {
        for(jdx = 0; jdx < 4; ++jdx)
        {
            p1[x] = vertices[idx];
            p1[y] = vertices[idx+1];
            p2[x] = vertices[idx+2];
            p2[y] = vertices[idx+3];
        }
        perimeter += side(p1, p2);
    }
    /* add last side */
    perimeter += side(plast, pfirst);
    return perimeter;
}
/* calculate length of side */
double side(double *p1, double *p2)
{
    double s1, s2, s3;
    s1 = (p1[x] - p2[x]);
    s2 = (p1[y] - p2[y]);
    s3 = (s1 * s1) + (s2 * s2);
    return sqrt(s3);
}

1 个答案:

答案 0 :(得分:1)

在测试OP的代码时,发布的列表在0.7之后有一个空格。通常情况下,此空白区域不是问题,但我保存文件text.txt会导致该行以" \r\n"结束,而'\r'会创建其他令牌。 strtok(NULL, " \n\r\t")的其他空格字符解决了这个问题。

<1.0 2.5 5.1 5.8 5.9 0.7 >
<1.2 4.1 5.1 5.8 6.8 1.9 2.9 0.2>
<1.7 4.9 5.1 5.8 7.0 2.8 4.8 0.1 1.5 1.4>

根据列表的保存方式,最后一行可能会也可能不会以'\n'结尾。 OP成为使用以下内容删除'\n'的方法成为问题,因为它可能会将最后一行显示为"1.7 4.9 5.1 5.8 7.0 2.8 4.8 0.1 1.5 1."(最后4丢失)。

    line[strlen(line) - 1] = 0;

最好使用下面的内容,不需要最终'\n'才能正常工作。

    line[strcspn(line, "\n")] = '\0';

OP的代码在其xy列表中创建了一个太多的坐标。由于其他白色空间,它也有潜在的麻烦。添加了更完整的列表。

while (token != NULL) {
  xy = atof(token);
  polygon_vertices[xycount++] = xy;
  token = strtok(NULL, " \n\r\t");  // more white-spaces.
  if (token == NULL) break;
}

然后,代码会将答案关闭计算为预期值。在该修复之后,先前提出的重复适用。 Is floating point math broken?

   area=11.775000   expected area=11.770000
   perimeter=15.645596  expected perimeter=15.640000

代替比较FP数字以进行精确匹配,代码需要允许小容差。见comparing double values in C
precision of comparing double values with EPSILON in C

可以进行各种简化和准确性改进。示例:

#include <assert.h>
/* calculate polygon perimeter */
double perimeter(double *vertices, int size) {
  assert(size % 2 == 0 && size >= 0);   // Insure only positive pairs are used
  double perimeter = 0.0;
  if (size > 1) {
    double x_previous =  vertices[size - 2];
    double y_previous =  vertices[size - 2 + 1];
    while (size > 1) {
      double x = *vertices++;
      double y = *vertices++;
      // hypot() certainly as accurate than sqrt(x*x + y*y) and avoids overflow
      perimeter += hypot(x - x_previous, y - y_previous);
      x_previous = x;
      y_previous = y;
      size -= 2;
    }
  }
  return perimeter;
}