【问题标题】:How to improve precision of code如何提高代码的精度
【发布时间】:2012-10-23 20:02:49
【问题描述】:

如何提高以下的准确度(精度)?

struct Degree_Minutes { signed int degrees; signed int minutes; double seconds; };
Degree_Minutes geo_dec_to_deg (double dec)
{
    Degree_Minutes degrees_minutes;
    signed int degrees, minutes;
    double remainder, temp, seconds;

    remainder = fmod(dec, 1);
    degrees_minutes.degrees = dec - remainder;
    temp = remainder*60;
    remainder = fmod(temp,1);
    degrees_minutes.minutes = temp-remainder;
    degrees_minutes.seconds = remainder*60;

    return degrees_minutes;
}

    double geo_deg_to_dec (Degree_Minutes degrees)
{
    double decimal = degrees.degrees + (degrees.minutes/60) + (degrees.seconds/60);
    return decimal;
}

int main(int argc, char **argv)
{
    Degree_Minutes deg;
    double decimal = 38.898556;

    deg = geo_dec_to_deg(decimal);
    cout << "Results of geo_dec_to_deg function: \n" << decimal << " was converted to " << deg.degrees << " degrees, " << deg.minutes << " minutes, " << deg.seconds << " seconds.\n";
    decimal = geo_deg_to_dec(deg);
    cout << "Results of geo_dec_to_deg function: \n" << deg.degrees << " degrees, " << deg.minutes << " minutes, " << deg.seconds << " seconds was converted to " << decimal << "\n";

    return EXIT_SUCCESS;
}

编辑:忘记添加这里有一个结构:

struct Degree_Minutes { signed int degrees; signed int minutes; double seconds; };

当您从十进制转换为度/分/秒,然后再转换回十进制时,您将得到 38.9134,而原始值为 38.898556。

【问题讨论】:

  • 哦,顺便说一句,我忘了注意结构: struct Degree_Minutes { signed int degree;签名的 int 分钟;双秒; };
  • 请编辑帖子以包含此新信息。
  • 没有必要包括 Degree_Minutes 的声明,因为它可以从提供的信息中推断出来。 (如果minutes 被声明为浮点数或seconds 被声明为整数,则会得到不同的结果。)
  • 可能没有必要,但我认为最好是为了清晰。我知道还有很多像我一样的人仍在努力提高初出茅庐的技能。

标签: c++ floating-point precision floating-accuracy floating-point-precision


【解决方案1】:

由于意外的整数除法,您遇到了舍入/截断错误。要获得正确的双精度,您需要将degrees.minutesdegrees.seconds 隐式转换为double,如下所示:

double decimal = degrees.degrees + (degrees.minutes/60.0) + (degrees.seconds/3600.0);

注意60 -> 60.0 以及秒字段中从 60 到 3600 的更正。

【讨论】:

  • 如果我没记错的话,有一个编译器选项可以警告您此类错误,-Wconversion 表示 gcc 和 clang。 -Wall 更好。 :-)
  • 一个度数有3600秒。
  • 啊,我明白了.. 因为我使用的是signed int(不知道为什么我签了分钟)。所以,通过使用双精度它应该转换它....好吧,试过这个,但是,它现在离原来的更远了。一旦转换回来,它变成 39.7967 与 38.8985
  • 谢谢你们。更正了 3600 的问题,现在转换过程又回到了原来的过程。
【解决方案2】:

有两个问题。

首先,Degree_Minutes 结构的minutes 成员被声明为整数类型,因此degrees.minutes/60 将整数除以整数,从而产生截断的整数结果。将其更改为 degrees.minutes/60. 会产生浮点结果。

其次,degrees.seconds/60 不正确。应该将 degrees.seconds/3600degrees.seconds/60 添加到 degree.minutes 中,然后将总和除以 60。

【讨论】:

    【解决方案3】:
    #include <stdlib.h>
    #include <iostream>
    #include <math.h>
    
    using namespace std;
    
    struct Degree_Minutes { signed int degrees; signed int minutes; double seconds; };
    
    Degree_Minutes geo_dec_to_deg (double dec)
    {
        Degree_Minutes degrees_minutes;
        signed int degrees, minutes;
        double remainder, temp, seconds;
    
        remainder = fmod(dec, 1);
        degrees_minutes.degrees = dec - remainder;
        temp = remainder*60.0;
        remainder = fmod(temp,1);
        degrees_minutes.minutes = temp-remainder;
        degrees_minutes.seconds = remainder*60.0;
    
        return degrees_minutes;
    }
    
    double geo_deg_to_dec (Degree_Minutes degrees)
    {
        double decimal = degrees.degrees + (degrees.minutes/60.0) + (degrees.seconds/60.0/60.0);
        return decimal;
    }
    
    int main(int argc, char **argv)
    {
        Degree_Minutes deg;
        double decimal = 38.898556;
    
        deg = geo_dec_to_deg(decimal);
        cout << "Results of geo_dec_to_deg function: \n" << decimal << " was converted to " << deg.degrees << " degrees, " << deg.minutes << " minutes, " << deg.seconds << " seconds.\n";
        cout << "This should be: 38deg 53' 54.801\"" << endl;
        cout << endl;
        decimal = geo_deg_to_dec(deg);
        cout << "Results of geo_dec_to_deg function: \n" << deg.degrees << " degrees, " << deg.minutes << " minutes, " << deg.seconds << " seconds was converted to " << decimal << "\n";
        cout << "This should be: 38.898556" << endl;
    
        return EXIT_SUCCESS;
    }
    

    你几乎拥有它。您需要通过明确指定小数来强制双除(如另一个答案中所示),但您还需要将秒数除以 60 两次。在实践中,我可能会将其更改为 degrees.seconds/3600,但我保留它是为了说明。

    【讨论】:

      猜你喜欢
      • 2014-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多