背景:
我一直在研究以下问题,S. Skiena 的“编程挑战:编程竞赛培训手册”中的“旅行”:
A group of students are members of a club that travels annually to different locations. Their destinations in the past have included Indianapolis, Phoenix, Nashville, Philadelphia, San Jose, and Atlanta. This spring they are planning a trip to Eindhoven.
The group agrees in advance to share expenses equally, but it is not practical to share every expense as it occurs. Thus individuals in the group pay for particular things, such as meals, hotels, taxi rides, and plane tickets. After the trip, each student's expenses are tallied and money is exchanged so that the net cost to each is the same, to within one cent. In the past, this money exchange has been tedious and time consuming. Your job is to compute, from a list of expenses, the minimum amount of money that must change hands in order to equalize (within one cent) all the students' costs.
Input
Standard input will contain the information for several trips. Each trip consists of a line containing a positive integer n denoting the number of students on the trip. This is followed by n lines of input, each containing the amount spent by a student in dollars and cents. There are no more than 1000 students and no student spent more than $10,000.00. A single line containing 0 follows the information for the last trip.
Output
For each trip, output a line stating the total amount of money, in dollars and cents, that must be exchanged to equalize the students' costs.
我用下面的代码解决了这个问题:
/*
* the-trip.cpp
*/
#include <iostream>
#include <iomanip>
#include <cmath>
int main( int argc, char * argv[] )
{
int students_number, transaction_cents;
double expenses[1000], total, average, given_change, taken_change, minimum_change;
while (std::cin >> students_number) {
if (students_number == 0) {
return 0;
}
total = 0;
for (int i=0; i<students_number; i++) {
std::cin >> expenses[i];
total += expenses[i];
}
average = total / students_number;
given_change = 0;
taken_change = 0;
for (int i=0; i<students_number; i++) {
if (average > expenses[i]) {
given_change += std::floor((average - expenses[i]) * 100) / 100;
}
if (average < expenses[i]) {
taken_change += std::floor((expenses[i] - average) * 100) / 100;
}
}
minimum_change = given_change > taken_change ? given_change : taken_change;
std::cout << "$" << std::setprecision(2) << std::fixed << minimum_change << std::endl;
}
return 0;
}
我原来的实现有 float
而不是 double
。它正在处理描述中提供的小问题实例,我花了很多时间试图找出问题所在。
最后我发现我必须使用 double
精度,显然编程挑战测试中的一些大输入使我的 float 算法失败。
问题:
鉴于输入可以有 1000 个学生,每个学生最多可以花费 10,000 美元,我的 total
变量必须存储最大大小的数字
10,000,000。
我应该如何决定需要哪种精度? 有什么东西应该给我一个提示,即 float 不足以完成这项任务吗?
我后来意识到,在这种情况下,我完全可以避免 float ,因为我的数字适合整数类型,但我仍然有兴趣了解是否有办法预见 float
在这种情况下不够精确。
最佳答案
Is there something that should have given me an hint that float wasn't enough for this task?
事实上 0.10 根本不能用二进制 float 表示(如果您使用普通计算机,float
和 double
都是)应该是提示.二进制 float 非常适合一开始就不准确的物理量,或者无论具有可判定相等性的合理数值系统如何都会不准确的计算。货币金额的精确计算不是二进制 float 的良好应用。
How should I decide which precision is needed? … my total variable has to store a number of the maximum size of 10,000,000.
使用整数类型表示美分数。根据你自己的推理,你不应该处理超过 1,000,000,000 美分的金额,所以 long
应该足够了,但只需使用 long long
并节省你自己的风险角落案例的麻烦。
关于c++ - 在 float 和 double 之间选择,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33983827/