2016-12-15 63 views
0

我有一個程序來計算一個聚合區和周長,程序收到一個帶座標的文本文件並計算出面積。比較雙打工作不正常(總是顯示不同)

我在計算中遇到了一些問題。現在我試圖比較雙打,我不明白爲什麼它不工作。

我有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因爲我給出正確的值,但我得到的消息數組是不同的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); 
} 
+2

調試尖端:打印增量('晶圓廠(polygon_area - expectedarea)'和'晶圓廠(丕林島 - expectedperimeter)')到您的' 「數組是不同的」'消息。然後你可以看到它是一個舍入錯誤還是真正的差異。通常,您應該比較浮點數與一些允許的差異來計算舍入誤差。 – grek40

+0

現在是開始學習如何使用調試器的好時機。當您逐步完成程序時,它可以幫助您遵循計算結果。 – user694733

+0

感謝您的回答。我以前就這樣做過,即使在它的實際情況下它出現了「陣列diferente」的消息。 – Chen

回答

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可能會將最後一行顯示爲"1.7 4.9 5.1 5.8 7.0 2.8 4.8 0.1 1.5 1."(缺少最後一個4),所以這會成爲OP用下面的方法刪除'\n'的方法的問題。

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; 
}