So essentially I'm doing a C book, and one of the exercises is to modify an example from the book to use banker's rounding. For context, banker's rounding is where in fractional cents, you round to the nearest even integer. I've been trying for hours to find out how to implement it, but nothing has worked for me. The code from the book is listed below.
// Ex. 5.31: DollarAmount.h
// DollarAmount class gets two parameter constructor
#include <string>
#include <cmath>
class DollarAmount {
public:
// initialize amount from an int64_t value
explicit DollarAmount(int64_t dollars, int64_t cents) : amount{dollars * 100 cents} { }
// add right's amount to this object's amount
void add(DollarAmount right) {
// can access private data of other objects of the same class
amount = right.amount;
}
// subtract right's amount from this object's amount
void subtract(DollarAmount right) {
// can access private data of other objects of the same class
amount -= right.amount;
}
// divide amount by the divisor
void divide(int divisor) {
amount = (amount divisor / 2) / divisor;
}
// uses integer arithmetic to calculate interest amount,
// then calls add with the interest amount
void addInterest(int rate, int divisor) {
// create DollarAmount representing the interest
DollarAmount interest {
((amount * rate divisor / 2) / divisor) / 100, // dollars
((amount * rate divisor / 2) / divisor) % 100 // cents
};
add(interest); // add interest to this object's amount
}
// return a string representation of a DollarAmount object
std::string toString() const {
std::string dollars{std::to_string(amount / 100)};
std::string cents{std::to_string(std::abs(amount % 100))};
return dollars "." (cents.size() == 1 ? "0" : "") cents;
}
private:
int64_t amount{0}; // dollar amount in pennies
};
I've tried several things but I reverted the code back to its original form since the other ones didn't work. The current algorithm uses normal rounding. The author didn't really explain the rounding system very well.
Edit: Here's also the main program used.
// Ex. 5.31: Interest.cpp
// Compound-interest calculations with class DollarAmount and integers.
#include <iostream>
#include <iomanip>
#include <string>
#include "DollarAmount.h"
using namespace std;
int main() {
DollarAmount d1{123, 45}; // $123.45
DollarAmount d2{15, 76}; // $15.76
cout << "After adding d2 (" << d2.toString() << ") into d1 ("
<< d1.toString() << "), d1 = ";
d1.add(d2); // modifies object d1
cout << d1.toString() << "\n";
cout << "After subtracting d2 (" << d2.toString() << ") into d1 ("
<< d1.toString() << "), d1 = ";
d1.subtract(d2); // modifies object d1
cout << d1.toString() << "\n";
cout << "After subtracting d1 (" << d2.toString() << ") from d2 ("
<< d2.toString() << "), d2 = ";
d2.subtract(d1); // modifies object d2
cout << d2.toString() << "\n";
cout << "After dividing d1 (" << d1.toString() << ") by 2, d1 = ";
d1.divide(2); // modifies object d1
cout << d1.toString() << "\n\n";
cout << "Enter integer interest rate and divisor. For example:\n"
<< "for 2%, enter: 2 100\n"
<< "for 2.3%, enter: 23 1000\n"
<< "for 2.37%, enter: 237 10000\n"
<< "for 2.375%, enter: 2375 100000\n";
int rate; // whole-number interest rate
int divisor; // divisor for rate
cin >> rate >> divisor;
DollarAmount balance{1000, 0}; // initial principal amount in pennies
cout << "\nInitial balance: " << balance.toString() << endl;
// display headers
cout << "\nYear" << setw(20) << "Amount on deposit" << endl;
// calculate amount on deposit for each of ten years
for (unsigned int year{1}; year <= 10; year ) {
// increase balance by rate % (i.e., rate / divisor)
balance.addInterest(rate, divisor);
// display the year and the amount
cout << setw(4) << year << setw(20) << balance.toString() << endl;
}
}
I'm currently testing with the inputs 2 100 and 5 1000000.
I've tried to make a conditional if the expression mod 1 is 0.5, and use the normal cents if it's true and uses the normal cents plus zero if the expression mod 2 is even and one if the expression mod 2 is odd. That ended up being messy and didn't even work and somehow got rid of all of the cents when I tested it. For the banker's rounding algorithm, inputting 2 100 should return 1218.98 for 10 years and 5 1000000 should always return 1000 because it's rounding to the nearest even integer, rounding down.
Edit 2: I've made some modifications to the code and I think I've thought of the algorithm I'll use. Here's the modified source code.
// Ex. 5.31: DollarAmount.h
// DollarAmount class gets two parameter constructor
#include <string>
#include <iostream>
#include <cmath>
class DollarAmount {
public:
// initialize amount from an int64_t value
explicit DollarAmount(int64_t dollars, int64_t cents) : amount{dollars * 100 cents} { }
// add right's amount to this object's amount
void add(DollarAmount right) {
// can access private data of other objects of the same class
amount = right.amount;
}
// subtract right's amount from this object's amount
void subtract(DollarAmount right) {
// can access private data of other objects of the same class
amount -= right.amount;
}
// divide amount by the divisor
void divide(int divisor) {
amount = (amount divisor / 2) / divisor;
}
// uses integer arithmetic to calculate interest amount,
// then calls add with the interest amount
void addInterest(int rate, int divisor) {
// create DollarAmount representing the interest
DollarAmount interest {
((amount * rate divisor / 2) / divisor) / 100, // dollars
((amount * rate divisor / 2) / divisor) % 100 // cents
};
if (static_cast<int64_t>((((amount * rate divisor / 2) / divisor) % 1) * 10) == 5) {
if (interest.amount % 2 == 1) {
interest.amount--;
}
std::cout << "test";
}
add(interest); // add interest to this object's amount
}
// return a string representation of a DollarAmount object
std::string toString() const {
std::string dollars{std::to_string(amount / 100)};
std::string cents{std::to_string(std::abs(amount % 100))};
return dollars "." (cents.size() == 1 ? "0" : "") cents;
}
private:
int64_t amount{0}; // dollar amount in pennies
};
So essentially my plan is to just create the interest object normally, but then I check if the banker's rounding condition is met, and then if the interest.amount variable % 2 == 1, implying that it did not round to the nearest even integer. If this condition is met it deincrements the interest.amount variable. This seems to be a bit messy but since it doesn't seem like there is an easier way of doing it I think I'll be trying out this method. The problem is the if statement currently doesn't work that checks if banker's rounding is needed.
Edit 3: Added comments
// Ex. 5.31: DollarAmount.h
// DollarAmount class gets two parameter constructor
#include <string>
#include <iostream>
#include <cmath>
class DollarAmount {
public:
// initialize amount from an int64_t value
explicit DollarAmount(int64_t dollars, int64_t cents) : amount{dollars * 100 cents} { }
// add right's amount to this object's amount
void add(DollarAmount right) {
// can access private data of other objects of the same class
amount = right.amount;
}
// subtract right's amount from this object's amount
void subtract(DollarAmount right) {
// can access private data of other objects of the same class
amount -= right.amount;
}
// divide amount by the divisor
void divide(int divisor) {
amount = (amount divisor / 2) / divisor;
}
// uses integer arithmetic to calculate interest amount,
// then calls add with the interest amount
void addInterest(int rate, int divisor) {
// create DollarAmount representing the interest
DollarAmount interest {
((amount * rate divisor / 2) / divisor) / 100, // dollars
((amount * rate divisor / 2) / divisor) % 100 // cents
};
// banker's rounding special case
std::cout << (((amount * rate divisor / 2) / divisor) % 1) * 10 << std::endl;
if (static_cast<int64_t>((((amount * rate divisor / 2) / divisor) % 1) * 10) == 5) {
// if interest.amount is odd, implying normal rounding deviated from banker's rounding
if (interest.amount % 2 == 1) {
interest.amount--; // deincrement interest.amount to account for banker's rounding
}
std::cout << "test";
}
add(interest); // add interest to this object's amount
}
// return a string representation of a DollarAmount object
std::string toString() const {
std::string dollars{std::to_string(amount / 100)};
std::string cents{std::to_string(std::abs(amount % 100))};
return dollars "." (cents.size() == 1 ? "0" : "") cents;
}
private:
int64_t amount{0}; // dollar amount in pennies
};
Edit 4: Okay, so I've figured out I will use normal rounding then check if bankers rounding is needed, then if it is and interest.amount is odd, implying it deviated from bankers rounding, it de-increments it. The only problem left is that my if statement that checks if bankers rounding is needed doesn't work.
CodePudding user response:
Here it goes:
// Ex. 5.31: DollarAmount.h
// DollarAmount class gets two parameter constructor
#include <string>
#include <cmath>
#include <iostream>
class DollarAmount {
public:
// initialize amount from an int64_t value
explicit DollarAmount(int64_t dollars, int64_t cents) : amount{dollars * 100 cents} { }
// add right's amount to this object's amount
void add(DollarAmount right) {
// can access private data of other objects of the same class
amount = right.amount;
}
// subtract right's amount from this object's amount
void subtract(DollarAmount right) {
// can access private data of other objects of the same class
amount -= right.amount;
}
// divide amount by the divisor
void divide(int divisor) {
amount = (amount divisor / 2) / divisor;
}
// uses integer arithmetic to calculate interest amount,
// then calls add with the interest amount
void addInterest(int rate, int divisor) {
// create DollarAmount representing the interest
DollarAmount interest {
((amount * rate divisor / 2) / divisor) / 100, // dollars
((amount * rate divisor / 2) / divisor) % 100 // cents
};
add(interest); // add interest to this object's amount
}
// return a string representation of a DollarAmount object
std::string toString() const {
std::string dollars{std::to_string(amount / 100)};
std::string cents{std::to_string(std::abs(amount % 100))};
return dollars "." (cents.size() == 1 ? "0" : "") cents;
}
void bankersRounding() {
std::cout << "money: " << amount << " cents" << std::endl;
int dollarsPart = amount/100;
int penniesPart = amount%100;
std::cout << " - dollars: " << dollarsPart << std::endl;
std::cout << " - pennies: " << penniesPart << std::endl;
// if it is equally distant from upper and lower integers,
// then apply banker's rounding
if (penniesPart==50)
{
// if the lower integer is zero, then round down to zero
if(dollarsPart==0)
{
std::cout << "it is zero" << std::endl;
amount -= 50;
}
// if the lower integer is even, then round down
else if ((dollarsPart%2)==0)
{
std::cout << "even" << std::endl;
amount -= 50;
}
// else the lower integer is odd, so round up
else {
std::cout << "odd" << std::endl;
amount = 50;
}
}
}
private:
int64_t amount{0}; // dollar amount in pennies
};
int main()
{
DollarAmount d1(0, 0);
DollarAmount d2(0, 50);
d1.add(d2);
d1.bankersRounding();
std::cout << "final: " << d1.toString() << std::endl;
return 0;
}
CodePudding user response:
Im not sure at which point youre stuck but maybe your are looking for something like this:
nearest_even=round(x/2)*2
I think thats a pretty simple implementation for "banker's rounding".