PDA

View Full Version : little q: illogical logical more c++



T1001
29th June 2015, 22:33
code below



diff_1 = 0;
if (diff_1 == 0.00) {cout<<"flag_1";}
if (diff_1==1.00) {pennies = pennies + 1;
cout<<"increment by a penny to "<<pennies<<endl;}


THis works a lot of the time but occasionally I'll run a number through the system and get bizzare output:

put in for diff_1-->1.00 (that's all - no decision tress)

sometimes 1.00 bypasses both conditions even though I manually set diff_1 to 1.00. and also fails to execute the decision tree next to it:

if (diff_1==1.00) {pennies = pennies + 1;
cout<<"increment by a penny to "<<pennies<<endl;}

west
29th June 2015, 22:44
http://doc.qt.io/qt-4.8/qtglobal.html#qFuzzyCompare

T1001
30th June 2015, 02:44
Thank you for the link, but I don't think this is what is going on. Not sure how this addresses the concern...

jefftee
30th June 2015, 06:52
Given your example, the value of pennies is indeterminate. Is it initialized prior to the example code you posted? Also, what is the data type for your diff_1 variable?

west
30th June 2015, 11:47
Give us compilable piece of code.

jefftee
30th June 2015, 15:49
Now that I have had coffee, I'm feeling much better. Post removed.

T1001
30th June 2015, 18:39
the problem is within this code. When the difference is 1 penny sometimes it bypasses teh decision tree below: "no adjustment necessary" or "adjustment necessary"

coffee the key towards great thoughts




cents_no_decimal = convert_cents(cents);
cout<<cents_no_decimal<<" converted to no decimal"<<endl;
find_change(cents_no_decimal, quarters, dimes, nickels, pennies, a, checksum_1);
//cout<<cents_no_decimal<<endl;

double diff_1 = 0;
diff_1 = cents_no_decimal - checksum_1; //find the offset amt which is the money before the function then after
cout<<"diff_1:"<<diff_1;
//difference = diff_1;
if (diff_1 == 0) {cout<<"no adjustment necessary"<<endl;
cout<<"difference :"<<difference <<endl;}
else if(diff_1==1) {cout<<"adjustment necessary"<<endl;}
//executive function
cout<<endl;
cout<<"continue y/n : ";

cin>>j;

if (j!='y')
{
cout<<"terminating program";
flag = false;
}

stampede
30th June 2015, 18:59
Try to reimplement double / float comparisons with qFuzzyCompare and qFuzzyIsNull and check if the error still persists.

jefftee
30th June 2015, 20:49
And please post all of your code. From what you've posted, there's no indication of the data type for cents_no_decimal or what in the world your checksum_1 variable contains, etc. You are much more likely to get help if we don't have to keep guessing, but from the limited info you've posted so far, I agree with @stampede that your problem is likely due to floating point calculations resulting in a result that is not exactly 1.0.

ChrisW67
30th June 2015, 21:15
If the value you are testing for equality to 1.00 (exactly) is the result of a computation then the approximation of the result may not be exactly 1.00. Some numbers cannot be exactly represented in a fixed length binary floating point form, and doing maths on them can lead to the situation where these approximation errors accumulate. You can end up with a floating point value that differs from the exact value at the 15 th decimal place and 1.0 != 1.00000000000001. This is why people keep telling you about qFuzzyCompare().

What Every Computer Scientist Should Know About Floating-Point Arithmetic (http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html)

In your situation, where you seem to be working with money, you may well be better off working strictly with integer numbers of cents.

d_stranz
1st July 2015, 00:35
In your situation, where you seem to be working with money, you may well be better off working strictly with integer numbers of cents.

Or using one of the many, many C++ classes which have been designed for working with currency and which avoid roundoff errors (resulting in "lost" fractional cents) or comparison problems such as you are experiencing. Google is your friend here. (http://ref.castedo.com/isomon/)

T1001
1st July 2015, 16:13
Hi guys, sorry to make things a little difficult, i apologize. Below is the full code. One problem I think I see but not sure of is the conversion between converting cents to 100 * cents to give me something to work with. Its a double...
code (plz see below). Also fyi I felt it would be quite a challenge to try to work out the decimal accuracy thing. Sure there are libraries and I'll use them if I can't get it : )



double convert_cents(double cents)
{
return cents*100;
}




Full code:

#include <QCoreApplication>
#include<iostream>
#include<math.h>
#include<iomanip>

using namespace std;

double change_due_now( double payment, double item_cost)
{
return payment - item_cost;

}

double convert_cents(double cents)
{
return cents*100;

}

int find_change(int cents_no_decimal, int quarters, int &dimes, int &nickels, int & pennies, int & checksum_1)
{

//rounding error cmopensation

int r_remainder = 0;

double pennies_1=0;
quarters = cents_no_decimal / 25;
r_remainder=cents_no_decimal % 25;
cout<<"quarters :"<<quarters<<endl;
//cout<<"remainder :"<<r_remainder<<endl;
dimes = r_remainder/10;
cout<<"dimes :"<<dimes<<endl;
r_remainder = r_remainder % 10;
//cout<<dimes<<endl;//" "<<r_remainder;
nickels = r_remainder/5;
cout<<"nickles :"<<nickels<<endl;

pennies = (r_remainder % 5);
cout<<"pennies :"<<pennies<<endl;
cout<<"---------"<<endl;
checksum_1 = (quarters*25)+ (dimes*10) + (nickels * 5) + (pennies * 1) ;
cout<<"sum change = "<<checksum_1<<endl;
return 0;
}

int main()

{
double total_change_due; double item_cost = 0; double payment = 0;
double dollar_amount = 0; double cents = 0; double quarters = 0;
int dimes = 0; int nickels = 0; int pennies = 0; double cents_no_decimal = 0;
int a = 0; int checksum_1 = 0;
bool flag = true; char j = 0;
while (flag==true) {
cout<<"item cost:";
cin>>item_cost;
cout<<"payment :";
cin>>payment;

cout<<fixed<<setprecision(2)<<showpoint;
total_change_due= change_due_now(payment, item_cost);
dollar_amount = int(total_change_due); double difference = 0;
cents = total_change_due-int(total_change_due);
cout<<"Change due: $"<<total_change_due<<endl;
cout<<"dollars : $"<<dollar_amount<<endl;
cout<<"cents : $"<<cents<<endl;

cents_no_decimal = convert_cents(cents);
cout<<cents_no_decimal<<" converted to no decimal"<<endl;
find_change(cents_no_decimal, quarters, dimes, nickels, pennies, checksum_1);
//cout<<cents_no_decimal<<endl;
//executive function
double diff_1 = 0;
diff_1 = cents_no_decimal - checksum_1; //find the offset amt which is the money before the function then after
cout<<"diff_1: "<<diff_1<<endl;
if (diff_1 == 0) {cout<<"no adjustment necessary"<<endl;
cout<<"difference :"<<difference <<endl;}
else if(diff_1!=0) {cout<<"adjustment necessary"<<endl;
pennies = pennies +1;
cout<<"Pennies adjusted total: "<<pennies;}

cout<<endl<<endl;
cout<<"continue y/n : ";

cin>>j;

if (j!='y')
{
cout<<"terminating program";
flag = false;
}

}

return 0;
}

jefftee
1st July 2015, 16:33
The whole point of converting all monies into cents is to avoid rounding issues with floating point numbers, so you should be returning an integer type from convert_cents, not a double.

T1001
1st July 2015, 23:35
Thank you, did that, problem solved. I thought I would lose information for sure with replacing the double with int, but my prediction was wrong.

d_stranz
2nd July 2015, 18:50
Since this clearly looks like a homework assignment, maybe you can take home a few C++ lessons from this which might help you be a better programmer. Why did you think you would "lose information for sure"? What assumptions did you make about preserving information that made you decide double was better than int, even though in the end everything you calculated was based on integer values for results (i.e., you can't have 1.3 quarters and 4.25 dimes as change when you give a dollar for a 25 cent purchase).

T1001
12th July 2015, 19:50
Hi d_stranz, sorry for following up so late. No, this is not a homework assignment per se: it was an assignment from a video course I was taking. There were no clues in the assignment so I had to research a lot of it. When I was done, the programs were similar, independently developed--I really learned a lot from it.

I decided double was better than int b/c I needed to preserve the decimal in double until I could multiply it out x 100. Once it became an integer, I could calculate the change in quarters, dimes, nickels and cents from the mod fx. You are correct to point out why double than int in the rest of the program and to my chagrin I will have to reflect on that. I was so frustrated with fixing the 1 cent rounding error I tried some try and see programming (ugggh).


(i.e., you can't have 1.3 quarters and 4.25 dimes as change when you give a dollar for a 25 cent purchase).

Sorry if I don't get your point but the program works, it gives out quarters, nickels and dimes using the mod fx.

Best regards

d_stranz
13th July 2015, 17:29
Sorry if I don't get your point but the program works, it gives out quarters, nickels and dimes

And it only gives out integer values for the number of quarters, nickels, and dimes, right? And if you reach into your pocket, you never pull out half a quarter, do you?

That's the whole point of the exercise, and it is one example of what is commonly referred to as a packing problem:

You have a box that's a certain size, and a set of smaller things that need to be packed into the box. How many of each thing can you fit in the box, with the least space left over?

Or you are filling a plane with cargo. What is the maximum number of things you can load into the plane while staying under the maximum weight?

Or you have a certain amount of change to give out, and coins of fixed denomination. What is the smallest number of coins of each type that adds to the total?