在C++中舍入双精度值,就像MS Excel一样

qeeaahzv  于 2023-11-20  发布在  其他
关注(0)|答案(5)|浏览(140)

我找遍了整个网络,但我找不到解决我的问题的方法。我只是想要一个像MS Excel一样对双精度值进行四舍五入的函数。下面是我的代码:

  1. #include <iostream>
  2. #include "math.h"
  3. using namespace std;
  4. double Round(double value, int precision) {
  5. return floor(((value * pow(10.0, precision)) + 0.5)) / pow(10.0, precision);
  6. }
  7. int main(int argc, char *argv[]) {
  8. /* The way MS Excel does it:
  9. 1.27815 1.27840 -> 1.27828
  10. 1.27813 1.27840 -> 1.27827
  11. 1.27819 1.27843 -> 1.27831
  12. 1.27999 1.28024 -> 1.28012
  13. 1.27839 1.27866 -> 1.27853
  14. */
  15. cout << Round((1.27815 + 1.27840)/2, 5) << "\n"; // *
  16. cout << Round((1.27813 + 1.27840)/2, 5) << "\n";
  17. cout << Round((1.27819 + 1.27843)/2, 5) << "\n";
  18. cout << Round((1.27999 + 1.28024)/2, 5) << "\n"; // *
  19. cout << Round((1.27839 + 1.27866)/2, 5) << "\n"; // *
  20. if(Round((1.27815 + 1.27840)/2, 5) == 1.27828) {
  21. cout << "Hurray...\n";
  22. }
  23. system("PAUSE");
  24. return EXIT_SUCCESS;
  25. }

字符串
我在stackoverflow找到了这个函数,答案是它像内置的excel舍入例程一样工作,但它不是。你能告诉我我错过了什么吗?

disho6za

disho6za1#

从某种意义上说,你所要求的是不可能的:
大多数通用平台上的浮点值没有“小数位数”的概念。像2.3或8.71这样的数字根本无法精确表示。因此,要求任何函数返回具有给定小数位数的浮点值是没有意义的-这样的数字根本不存在。
对于浮点类型,你唯一能做的就是计算最接近的可表示的近似值,然后以所需的精度打印结果,这将给予你所需的数字的文本形式。要计算表示,你可以这样做:

  1. double round(double x, int n)
  2. {
  3. int e;
  4. double d;
  5. std::frexp(x, &e);
  6. if (e >= 0) return x; // number is an integer, nothing to do
  7. double const f = std::pow(10.0, n);
  8. std::modf(x * f, &d); // d == integral part of 10^n * x
  9. return d / f;
  10. }

字符串
(You也可以使用modf而不是frexp来确定x是否已经是整数。您还应该检查n是否为非负,或者定义负“精度”的语义。)
除了使用 * 浮点 * 类型,你还可以执行 * 定点 * 运算。也就是说,你把所有的东西都存储为 * 整数 *,但是你把它们当作单位,比如说1/1000。然后你可以打印这样一个数字,如下所示:

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


加法可以像预期的那样工作,尽管你必须编写自己的乘法函数。

展开查看全部
eqzww0vc

eqzww0vc2#

为了比较双精度值,你必须指定一个比较范围,在这个范围内,结果可以被认为是“安全的”。你可以使用宏来实现。
下面是一个用途:

  1. #define COMPARE( A, B, PRECISION ) ( ( A >= B - PRECISION ) && ( A <= B + PRECISION ) )
  2. int main()
  3. {
  4. double a = 12.34567;
  5. bool equal = COMPARE( a, 12.34567F, 0.0002 );
  6. equal = COMPARE( a, 15.34567F, 0.0002 );
  7. return 0;
  8. }

字符串

8e2ybdfx

8e2ybdfx3#

在考虑了可能的解决方案后,我将代码中原始的Round()函数改为将值增加0.6而不是0.5。
值“127827.5”(我知道这不是一个精确的表示!)变成“127828.1”,最后通过floor()除以它变成“1.27828”(或者更像1.2782800..001)。使用Renan Greinert建议的COMPARE,正确选择精度,我现在可以安全地比较这些值。
以下是最终版本:

  1. #include <iostream>
  2. #include "math.h"
  3. #define COMPARE(A, B, PRECISION) ((A >= B-PRECISION) && (A <= B+PRECISION))
  4. using namespace std;
  5. double Round(double value, int precision) {
  6. return floor(value * pow(10.0, precision) + 0.6) / pow(10.0, precision);
  7. }
  8. int main(int argc, char *argv[]) {
  9. /* The way MS Excel does it:
  10. 1.27815 1.27840 // 1.27828
  11. 1.27813 1.27840 -> 1.27827
  12. 1.27819 1.27843 -> 1.27831
  13. 1.27999 1.28024 -> 1.28012
  14. 1.27839 1.27866 -> 1.27853
  15. */
  16. cout << Round((1.27815 + 1.27840)/2, 5) << "\n";
  17. cout << Round((1.27813 + 1.27840)/2, 5) << "\n";
  18. cout << Round((1.27819 + 1.27843)/2, 5) << "\n";
  19. cout << Round((1.27999 + 1.28024)/2, 5) << "\n";
  20. cout << Round((1.27839 + 1.27866)/2, 5) << "\n";
  21. //Comparing the rounded value against a fixed one
  22. if(COMPARE(Round((1.27815 + 1.27840)/2, 5), 1.27828, 0.000001)) {
  23. cout << "Hurray!\n";
  24. }
  25. //Comparing two rounded values
  26. if(COMPARE(Round((1.27815 + 1.27840)/2, 5), Round((1.27814 + 1.27841)/2, 5), 0.000001)) {
  27. cout << "Hurray!\n";
  28. }
  29. system("PAUSE");
  30. return EXIT_SUCCESS;
  31. }

字符串
我测试了一下,取整了100个双精度值,然后将结果与Excel给出的结果进行比较,结果都是一样的。

展开查看全部
c0vxltue

c0vxltue4#

恐怕答案是圆圆不能施展魔法
由于1.27828不能完全表示为一个double,你不能将某个double与1.27828进行比较,并希望它匹配。

js5cn81o

js5cn81o5#

你需要做的数学没有小数部分,得到的数字.所以这样的东西。

  1. double dPow = pow(10.0, 5.0);
  2. double a = 1.27815;
  3. double b = 1.27840;
  4. double a2 = 1.27815 * dPow;
  5. double b2 = 1.27840 * dPow;
  6. double c = (a2 + b2) / 2 + 0.5;

字符串
使用您的功能...

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

展开查看全部

相关问题