I am doing an ongoing project to refine a c craps game I made. One of the aspects of the code, distributing the chips, is a hassle to do, as there is 12 different chip types and rates, that I do not have enough coding expertise to know how to best code, taking up about 90 lines of code that I think could be lessened. However, as code to distribute dollar value and bills is almost exactly like the problem I am having, but only having four types instead of twelve, I will use those as an example and the basis of this question instead, as I don’t think anyone wants to see 12 if else statements in their stack exchange platform, or the complexity of twelve types of values when it can be lessened for the example. There are two ways that I currently know of to do it, the first being to just use if else statements in order to check to see which bill best fits the value given. The other is less efficient than the first right now, but that is likely because I just learned about the concept that it relies on, that being maps, and map.upperbound. No matter what the method is, I would think that both would likely required things like floor to round down to the bill value, and possibly fmod to lower the money value to repeat the loop until it sees no other way to distribute the money, but could be wrong. The question I have is what is the most efficient way to go about this? Is the if/else chain the best way to do this problem in general? Is there some aspect of maps that I am unaware of that can help solve this problem? Or is there some other concept that I don’t know that can do this better than if/else chains and maps?
One way:
#include <iostream>
#include <map>
#include <math.h>
#include <iomanip>
using namespace std;
int main()
{
int dollar1 = 0;
int dollar5 = 0;
int dollar10 = 0;
int dollar100 = 0;
float money;
int itFirst;
int itSecond;
float moneyhold;
std::cout << "What is the amount in $ you want?" << endl;
cin >> money;
while (money) {
if (money / 100 >= 1) {
moneyhold = floor(money / 100);
std::cout << std::fixed;
std::cout << std::setprecision(0);
money = fmod(money, 100);
}
else if (money / 10 >= 1) {
moneyhold = floor(money / 10);
std::cout << std::fixed;
std::cout << std::setprecision(0);
money = fmod(money, 10);
}
else if (money / 5 >= 1) {
moneyhold = floor(money / 5);
std::cout << std::fixed;
std::cout << std::setprecision(0);
money = fmod(money, 5);
}
else if (money / 1 >= 1) {
moneyhold = floor(money / 1);
std::cout << std::fixed;
std::cout << std::setprecision(0);
money = fmod(money, 1);
}
if (money < 1) {
money = 0;
}
}
cout << "You have " << dollar1 << " one dollar bills, " << dollar5 << " five dollar bills, " << dollar10 << " ten dollar bills, and " << dollar100 << " hundred dollar bills";
}
Other way:
#include <iostream>
#include <map>
#include <math.h>
#include <iomanip>
using namespace std;
int main()
{
int dollar1 = 3;
int dollar5 = 5;
int dollar10 = 7;
int dollar100 = 10;
std::map<int, int> am{
{ 1,dollar1 },
{ 5,dollar5 },
{ 10,dollar10 },
{ 100,dollar100}
};
float money;
int itFirst;
int itSecond;
float placehold;
std::cout << "What is the amount in $ you want?" << endl;
cin >> money;
while (money) {
auto iter = am.upper_bound(money);
if (iter != am.begin())
{
--iter;
itFirst = iter->first;
itSecond = iter->second;
}
placehold = floor(money / itFirst);
money = fmod(money, itFirst);
if (itFirst == 1) {
dollar1 = itSecond placehold;
}
else if (itFirst == 5) {
dollar5 = itSecond placehold;
}
else if (itFirst == 10) {
dollar10 = itSecond placehold;
}
else if (itFirst == 100) {
dollar100 = itSecond placehold;
}
if (money < 1) {
money = 0;
}
}
cout << "You have " << dollar1 << " one dollar bills, " << dollar5 << " five dollar bills, " << dollar10 << " ten dollar bills, and " << dollar100 << " hundred dollar bills";}
CodePudding user response:
Use a table and stick to integers.
Something like this, perhaps:
int main()
{
struct Bill { int value = 1; int amount = 0; };
std::vector<Bill> bills = {{100}, {10}, {5}, {1}};
int total_remaining = 1234;
for (auto& bill: bills)
{
if (total_remaining >= bill.value)
{
bill.amount = total_remaining / bill.value;
total_remaining %= bill.value;
}
}
std::cout << "You get:\n";
for (const auto& bill: bills)
{
std::cout << bill.amount << ' ' << bill.value << " dollar bills\n";
}
}
CodePudding user response:
You can pretty easily calculate directly:
unsigned int cents;
std::cin >> cents;
// you'd start with greatest value and go down to smallest:
unsigned int dollar100 = cents/10000;
cents %= 10000;
unsigned int dollar5 = cents/500;
cents %= 500;
unsigned int dollar1 = cents/100;
cents %= 100;
// analogously for the sub-units...
Note operating on another data type for two reasons:
float
(anddouble
) is (almost) never a good choice to represent currencies. Not even such a simple value like 0.1 can be represented exactly, as it is periodic in binary. All you get with is quite a lot of trouble due to rounding issues (for the sub-units and for large values as well!). Use the currency's sub-units instead (cents, pfennig, bani, ...) – or, if not precise enough, sub-units of (tenth, hundredth, ... of cents, ...). Your representation on screen might remain dollars – but you'd convert to cents immediately on reading input from, and you'd only convert back to dollars immediately before outputting.I assume depts are not meaningful – when someone is running out of money – that's it... This fact is represented better by an unsigned type. If some one wants to give a bid you'd need to check in advance anyway if money yet suffices for, so that shouldn't come with negative impact for you. Though if the assumption is wrong – or might be in the future – then, of course, the signed type is the right choice.