像C ++这样在C ++中舍入双值就可以了

时间:2012-01-06 12:59:21

标签: c++ excel double rounding

我在网上搜索过,但我找不到解决问题的方法。我只想要一个像MS Excel那样舍入双值的函数。这是我的代码:

#include <iostream>
#include "math.h"

using namespace std;

double Round(double value, int precision) {
    return floor(((value * pow(10.0, precision)) + 0.5)) / pow(10.0, precision);
}

int main(int argc, char *argv[]) {
    /* The way MS Excel does it:
        1.27815 1.27840 ->  1.27828
        1.27813 1.27840 ->  1.27827
        1.27819 1.27843 ->  1.27831
        1.27999 1.28024 ->  1.28012
        1.27839 1.27866 ->  1.27853
    */
    cout << Round((1.27815 + 1.27840)/2, 5) << "\n"; // *
    cout << Round((1.27813 + 1.27840)/2, 5) << "\n";
    cout << Round((1.27819 + 1.27843)/2, 5) << "\n";
    cout << Round((1.27999 + 1.28024)/2, 5) << "\n"; // *
    cout << Round((1.27839 + 1.27866)/2, 5) << "\n"; // *

    if(Round((1.27815 + 1.27840)/2, 5) == 1.27828) {
                      cout << "Hurray...\n";
    }
    system("PAUSE");
    return EXIT_SUCCESS;
}

我在stackoverflow找到了这个函数,答案表明它的工作方式与内置的excel舍入程序类似,但事实并非如此。你能告诉我我错过了什么吗?

5 个答案:

答案 0 :(得分:2)

要比较双值,您必须指定一个比较范围,其中结果可被视为“安全”。您可以使用宏。

以下是您可以使用的一个示例:

#define COMPARE( A, B, PRECISION ) ( ( A >= B - PRECISION ) && ( A <= B + PRECISION ) ) 

int main()
{
  double a = 12.34567;
  bool equal = COMPARE( a, 12.34567F, 0.0002 );

  equal = COMPARE( a, 15.34567F, 0.0002 );
  return 0;
}

答案 1 :(得分:2)

从某种意义上说,你所要求的是不可能的:

大多数常见平台上的浮点值没有“小数位数”的概念。像2.3或8.71这样的数字根本无法精确表示。因此,要求任何函数返回具有给定数量的非零小数位的浮点值是没有意义的 - 这些数字只是不存在

浮点类型唯一可以做的就是计算最接近的可表示近似值,然后以所需的精度打印结果,这将为您提供所需数字的文本形式。要计算表示,您可以这样做:

double round(double x, int n)
{
    int e;
    double d;

    std::frexp(x, &e);

    if (e >= 0) return x; // number is an integer, nothing to do

    double const f = std::pow(10.0, n);
    std::modf(x * f, &d);                 // d == integral part of 10^n * x

    return d / f;
}

(您也可以使用modf代替frexp来确定x是否已经是整数。您还应该检查n是否为非负数,否则为负“精度”定义语义。)


除了使用浮动点类型之外,您还可以执行固定点算术。也就是说,您将所有内容存储为整数,但您将它们视为1/1000的单位。然后你可以打印如下这样的数字:

 std::cout << n / 1000 << "." << n % 1000;

添加按预期工作,但您必须编写自己的乘法函数。

答案 2 :(得分:1)

谢谢大家的回答!在考虑了可能的解决方案之后,我在我的代码中更改了原始的Round()函数,将0.6而不是0.5添加到该值。

值“127827.5”(我明白这不是一个确切的表示!)变为“127828.1”,最后通过floor()并将其除以“1.27828”(或更像是1.2782800..001)。使用Renan Greinert建议的COMPARE并使用正确选择的精度,我现在可以安全地比较这些值。

以下是最终版本:

#include <iostream>
#include "math.h"
#define COMPARE(A, B, PRECISION) ((A >= B-PRECISION) && (A <= B+PRECISION))

using namespace std;

double Round(double value, int precision) {
    return floor(value * pow(10.0, precision) + 0.6) / pow(10.0, precision);
}
int main(int argc, char *argv[]) {
    /* The way MS Excel does it:
        1.27815 1.27840 // 1.27828
        1.27813 1.27840 ->  1.27827
        1.27819 1.27843 ->  1.27831
        1.27999 1.28024 ->  1.28012
        1.27839 1.27866 ->  1.27853
    */
    cout << Round((1.27815 + 1.27840)/2, 5) << "\n"; 
    cout << Round((1.27813 + 1.27840)/2, 5) << "\n";
    cout << Round((1.27819 + 1.27843)/2, 5) << "\n";
    cout << Round((1.27999 + 1.28024)/2, 5) << "\n";
    cout << Round((1.27839 + 1.27866)/2, 5) << "\n";

    //Comparing the rounded value against a fixed one
    if(COMPARE(Round((1.27815 + 1.27840)/2, 5), 1.27828, 0.000001)) {
       cout << "Hurray!\n";
    }
    //Comparing two rounded values
    if(COMPARE(Round((1.27815 + 1.27840)/2, 5), Round((1.27814 + 1.27841)/2, 5), 0.000001)) {
       cout << "Hurray!\n";
    }    

    system("PAUSE");
    return EXIT_SUCCESS;
}

我通过舍入一百个双倍值并将结果与​​Excel给出的结果进行比较来测试它。他们都是一样的。

答案 3 :(得分:0)

我担心答案是Round无法表演魔法 由于1.27828并不完全可以表示为double,因此您无法将某些双精度值与1.27828进行比较,并希望它能匹配。

答案 4 :(得分:0)

你需要在没有小数部分的情况下进行数学计算,以得到这些数字...就像这样。

double dPow = pow(10.0, 5.0);

    double a = 1.27815;
    double b = 1.27840;


    double a2 = 1.27815 * dPow;
    double b2 = 1.27840 * dPow;

    double c = (a2 + b2) / 2 + 0.5;

使用您的功能...

double c = (Round(a) + Round(b)) / 2 + 0.5;