patterncppMinor
Calculating the change of a vending machine
Viewed 0 times
thecalculatingmachinechangevending
Problem
I would like to know if this function is correct (I know that it works, but I have not got enough knowledge so as to demonstrate that it is correct).
Indication: a
Example: if I want to store 5 x 50€ + 2 x 20€ + 0 x 10€ + 1 x 5€ +... et cetera, I would type:
Pre:
Description and post:
Code:
``
for (int i = 0; i 0) and I keep on subtracting all $$$
//as much as I can (they are always 0; ++i) {
while (p[i] =
Indication: a
colleccio is defined as a vector always of size 12, so I can represent the number of banknotes and/or coins of value 50, 20, 10, 5, 2, 1, 0.50, 0.20, 0.10, 0.05, 0.02, 0.01 € in positions 0..11.Example: if I want to store 5 x 50€ + 2 x 20€ + 0 x 10€ + 1 x 5€ +... et cetera, I would type:
colleccio v(12); v[0]=5; v[1]=2; v[2]=0; and so on.Pre:
- No money exchange has been done before the function.
machineis a validcolleccio: it is the content of the machine (how many banknotes and/or coins has inside).
paidis another validcollecciobut, in this case, it is what the user has paid.
possible_changeis an emptycolleccio.
numeric_changeis a valid currency (X.XX€, two decimals, positive value). Its value is the price of the product-what the customer has paid. Its value is valid before computing the function.
Description and post:
i_have_change checks if, given machine and paid, exists a possible_change to be returned to the user lately. If it is possible, in possible_change there will be a valid colleccio in which it is stored the most optimum change (that is: the less "currency" items (banknotes/coins), the better). machine should be correctly modified (it doesn't matter if it changes even though I cannot give change).Code:
``
bool i_have_change (colleccio& machine, const colleccio& paid,
colleccio& possible_change, double numeric_change) {
vector p(12); //the values of the currency are stored in p.
p[0] = 50.; p[1] = 20.; p[2] = 10.;
p[3] = 5.; p[4] = 2.; p[5] = 1.;
p[6] = .50; p[7] = .20; p[8] = .10;
p[9] = .05; p[10] = .02; p[11] = .01;
//Add paid to machine`for (int i = 0; i 0) and I keep on subtracting all $$$
//as much as I can (they are always 0; ++i) {
while (p[i] =
Solution
I see a number of things that may help you improve your code. Because it makes a lot of things simpler, I'm going to assume that you and your compiler are able to handle C++11.
Post complete code
Here on Code Review, we prefer longer and more complete questions and code which is different from many of the other sister sites. For that reason, when posting a question here for review, it's often best to include a short driver code showing the context of how your code is intended to be used. It helps reviewers quickly understand your code and give you a better review.
Use
The
Don't use floating point for money
There is a problem using floating point (that is,
Simplify expressions
The code currently has these lines:
We can simplify this to:
However this is something of a problem with floating point values. Either change the variable to use and integer type or compare to a real value smaller than your minimum change amount. For example, you might use 0.005. Much better would be to use integers.
Think carefully about the problem
If the vending machines contains €0.07 and I put in €50.00 for something that costs €10.00 what I would want to have happen is that I would get my €50.00 back and not the €10.00 item. What the program seems to actually do, however, is return €0.07. That is, I would expect that the function would return the value
Putting it all together
Using these suggestions, here is what the routine becomes:
Test code
Since the code for
Now here is a convenience macro and test code in
Sample output
Post complete code
Here on Code Review, we prefer longer and more complete questions and code which is different from many of the other sister sites. For that reason, when posting a question here for review, it's often best to include a short driver code showing the context of how your code is intended to be used. It helps reviewers quickly understand your code and give you a better review.
Use
const where practicalThe
std::vector p gets created and destroyed every time the function is invoked. That's not very efficient and not at all necessary. Instead, we can make it static so it's created once and const because it shouldn't change. We can do that with this single line:static const std::vector p{ 50, 20, 10, 5, 2, 1, 0.5, 0.2, 0.1, 0.05, 0.02, 0.01 };Don't use floating point for money
There is a problem using floating point (that is,
float or double types) fto represent money values. For example, when I tried to use your code to return €0.03 I only got €0.02. This is a fundamental problem with using double (or any floating-point representation) for money values. An alternative is to keep a number of cents as an integer value internally. For more depth about floating point issues, I'd recommend the excellent article "What every computer scientist should know about floating-point arithmetic" by David Goldberg.Simplify expressions
The code currently has these lines:
if (numeric_change != 0) return false;
return true;We can simplify this to:
return !numeric_change;However this is something of a problem with floating point values. Either change the variable to use and integer type or compare to a real value smaller than your minimum change amount. For example, you might use 0.005. Much better would be to use integers.
Think carefully about the problem
If the vending machines contains €0.07 and I put in €50.00 for something that costs €10.00 what I would want to have happen is that I would get my €50.00 back and not the €10.00 item. What the program seems to actually do, however, is return €0.07. That is, I would expect that the function would return the value
false (which it does), and then have possible_change identical to the paid object. The specification you quote is not very clear on this issue, but it seems like the right behavior to me.Putting it all together
Using these suggestions, here is what the routine becomes:
bool i_have_change (colleccio& machine, const colleccio& paid,
colleccio& possible_change, double numeric_change) {
static const std::vector p{ 5000, 2000, 1000, 500, 200, 100, 50, 20, 10, 5, 2, 1 };
//Add paid to machine
for (size_t i = 0; i 0) and I keep on substracting all $$
//as I can (they are always 0; ++i) {
while (p[i] = 1) {
change -= p[i];
++possible_change[i];
--machine[i];
}
}
if (change) {
// can't make change so return money
for (size_t i = 0; i < paid.size(); ++i) {
possible_change[i] = paid[i];
}
}
//If I still have change, I have not physical change!
return !change;
}Test code
Since the code for
colleccio objects was not given, I created my own to test the code.#include
#include
#include
#include
class colleccio : public std::vector
{
public:
colleccio(std::initializer_list w) :
std::vector{w}
{}
colleccio() : std::vector(12) {}
double value() const { return std::inner_product(v.begin(), v.end(), begin(), 0)/100.0; }
friend std::ostream& operator v;
};
const std::vector colleccio::v{ 5000, 2000, 1000, 500, 200, 100, 50, 20, 10, 5, 2, 1 };Now here is a convenience macro and test code in
main.#define SHOW(X) std::cout << # X " = " << (X) << std::endl
int main()
{
colleccio machine{0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 7};
colleccio paid {1, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0};
colleccio change;
double chg_amount{40.0};
std::cout << std::boolalpha;
SHOW(machine);
SHOW(paid);
SHOW(change);
SHOW(chg_amount);
SHOW(i_have_change(machine, paid, change, chg_amount));
SHOW(machine);
SHOW(paid);
SHOW(change);
SHOW(chg_amount);
}Sample output
machine = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, } = 0.07
paid = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } = 50
change = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } = 0
chg_amount = 40
i_have_change(machine, paid, change, chg_amount) = false
machine = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } = 50
paid = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } = 50
change = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } = 50
chg_amount = 40Code Snippets
static const std::vector<double> p{ 50, 20, 10, 5, 2, 1, 0.5, 0.2, 0.1, 0.05, 0.02, 0.01 };if (numeric_change != 0) return false;
return true;return !numeric_change;bool i_have_change (colleccio& machine, const colleccio& paid,
colleccio& possible_change, double numeric_change) {
static const std::vector<unsigned> p{ 5000, 2000, 1000, 500, 200, 100, 50, 20, 10, 5, 2, 1 };
//Add paid to machine
for (size_t i = 0; i < paid.size(); ++i)
machine[i] += paid[i];
unsigned change = numeric_change * 100;
//I start with change (> 0) and I keep on substracting all $$$
//as I can (they are always <= change)
for (size_t i = 0; i < machine.size() and change > 0; ++i) {
while (p[i] <= change and machine[i] >= 1) {
change -= p[i];
++possible_change[i];
--machine[i];
}
}
if (change) {
// can't make change so return money
for (size_t i = 0; i < paid.size(); ++i) {
possible_change[i] = paid[i];
}
}
//If I still have change, I have not physical change!
return !change;
}#include <vector>
#include <initializer_list>
#include <iostream>
#include <numeric>
class colleccio : public std::vector<int>
{
public:
colleccio(std::initializer_list<int> w) :
std::vector<int>{w}
{}
colleccio() : std::vector<int>(12) {}
double value() const { return std::inner_product(v.begin(), v.end(), begin(), 0)/100.0; }
friend std::ostream& operator<<(std::ostream& out, const colleccio& col) {
out << "{ ";
for (const auto n : col)
out << n << ", ";
return out << "} = " << col.value();
}
private:
static const std::vector<unsigned> v;
};
const std::vector<unsigned> colleccio::v{ 5000, 2000, 1000, 500, 200, 100, 50, 20, 10, 5, 2, 1 };Context
StackExchange Code Review Q#116056, answer score: 3
Revisions (0)
No revisions yet.