【问题标题】:how to avoid the loss of precision when trying to round number? (C++)尝试四舍五入时如何避免精度损失? (C++)
【发布时间】:2018-03-16 15:15:50
【问题描述】:

刚结束我第一周的 C++(使用 Visual Studio 2017),我编写了一个程序,询问用户金额并打印纸币和硬币的数量。它在开始时有效,但有时它只是打印错误的数字。(当用户输入 1.28 美元时,它显示 1 美元、1 季度和 2 便士。) 这是我的代码,有什么问题吗?算法还是数据类型?

#include<iostream>
using namespace std;

float Q = 0.25;
float D = 0.10;
float N = 0.05;
float P = 0.01;
float Dollar = 1;
float money;
float dollars, quarters, dimes, nickels, pennies;


int main()  //to break money into coins.
{

cout << "how many money do u have?" << endl;
cin >> money;
dollars = (int)money;
quarters = (int)((money - dollars*Dollar)/Q);
dimes = (int)((money - dollars*Dollar - quarters*Q) / D);
nickels = (int)((money - dollars*Dollar - quarters*Q - dimes*D) / N);
pennies = (int)((money - dollars*Dollar - quarters*Q - dimes*D - nickels*N) / P);
cout << "$" << money << " can be break into :" << endl;
cout << dollars << " dollars. " << endl;
cout << quarters << " quarters. " << endl;
cout << dimes << " dimes. " << endl;
cout << nickels << " nickels. " << endl;
cout << pennies << " pennies. " << endl;
}

【问题讨论】:

  • 金钱不应该用浮点数来表示。使用表示值的美分数的 int。例如,$1.28 将由 int 值 128 表示。您需要以直接的方式调整数学,但精度不会成为问题。

标签: c++ type-conversion


【解决方案1】:

在尝试取整时如何避免精度损失? (C++)

从浮点数转换为整数时,小数部分会被截断。为确保不损失整数精度(获得正确的“整数”),每次将结果加 0.5 例如:

quarters = static_cast<int>(((money - dollars*Dollar)/Q)+0.5);

但是,当结果为负时,这不起作用,例如: 50.5 - 100 = -49.5 -> +1 = -48.5 -> -48...不是 49

因此,对于负数,您需要减去 0.5。

【讨论】:

  • static_cast&lt;int&gt;(((money - dollars*Dollar)/Q)+0.5) 实际上。
  • @EJP。谢谢!对我来说一大早
【解决方案2】:

我假设,在这一行

pennies = (int)((money - dollars*Dollar - quarters*Q - dimes*D - nickels*N) / P);

(money - dollars*Dollar - quarters*Q - dimes*D - nickels*N) 部分将产生一个值,它不完全是 .03,而是稍低一些。这是由于浮点运算的性质,您应该阅读它。鉴于它类似于 .029999999995,除以 0.01 不会产生 3.0,但可能是 2.9999999995。由于您不是四舍五入,而是将值转换为整数,因此句点之后的整个部分将被丢弃,因此结果为 2 便士。

你如何解决这个问题?

最简单的方法是对值进行舍入而不是强制转换,这应该会产生正确的值,但对于一个有确切解决方案的问题,这是一种老套的解决方案。您也可以尝试使用double 而不是float,但这也不能解决问题。您可能会得到正确的答案,但相同仍可能出现类似的错误。

存储整个便士

您可以将全部金额存储为整数(整便士)

int amountInPennies;

int penniesPerDollar = 100;
int penniesPerQuarter = 25;
int penniesPerDime = 10;
int penniesPerNickle = 5;

int totalDollars = amountPennies / penniesPerDollar;
int totalQuarters = (amountPennies - totalDollars * penniesPerDollar) / penniesPerQuarter;
...

十进制类型

在处理金钱的实际应用程序中(嗯,取决于类型),您很可能会使用某种十进制类型而不是float。根据this answer 的说法,在 GNU 许可下可以使用具有任意精度算术的库。你仍然可以滚动你自己的十进制类型,它或多或少 - 与我在第一种方法中提出的一样。这可能是一个很好的练习,但对于现实世界的应用程序来说,现成的库可能是更好的选择。

【讨论】:

  • 无需分别存储美元和便士 - 只需以美分表示价值。 1.28 美元是 128 美分。
  • @MichaelButt True - 我会相应地对其进行编辑。谢谢。
  • 这不合逻辑,我的意思是,它不应该给我任何像 0.299999999999 这样的数据,在数学上没有意义
  • @TianyiLiu - 了解浮点运算。我承认,其含义并不明显或数学逻辑,但这就是我们所拥有的。浮点算术是通用计算的折衷方案,但也有其缺点。如果您有特殊需求,浮点运算可能不适合您。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-22
  • 2022-06-14
  • 2014-07-02
  • 2023-01-12
  • 2018-05-06
相关资源
最近更新 更多