Unexpected IF statement result

Write your question here.

This is a simple program to calculate how much a person will be charged based on the the user-inputed: Start time (HH.MM) & number of minutes. The rate is solely determined by the start time. The program is designed to prevent the user from entering an invalid start time such as HH > 23 and MM > .59.

Anyways, this is what is happening and its prolly an easy fix but I can't seem to find it. I set a series of IF/AND statements to identify range at which a specified rate will be charged. The problem is anytime I make a value with .MM = .59, it goes to the default statement. INVALID TIME (which I designed in the program). As long as I don't use .59 in the .MM, it will perform the correct calculations. Please help! I starting to lean towards the static_cast statement causing the problem because once i change the datatype from a float to an int, i perform a simple subtraction problem (test = float - int) and I think the result is being inherited to a float perhaps causing the value to fall out of range but to be completely honest....I don't really know...just a suspicion

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
#include <iomanip> 

using namespace std;

int main()
{
 const float r1 = .12, r2 = .23, r3 = .55, r4 = .35;
 float st, m, test, tot;
 int stH;
 cout << "Start Time: "; cin >> st; 
 cout << "Number of minutes: "; cin >> m;
 stH = static_cast<int>(st);
 test = st - stH;

 if(st>=00.00 && st<=06.59){
    tot = m * r1;
    cout << fixed << setprecision(2) << "Total charges for this call is $" <<  tot << endl;}
  
 if (st>=07.00 && st<=12.59){
  tot = m * r2;
  cout << fixed << setprecision(2) << "Total charges for this call is $" << tot << endl;}
 
 if (st>=13.00 && st<=19.00){
     tot = m * r3;
     cout << fixed << setprecision(2) << "Total charges for this call is $" << tot << endl;}
 
 if (st>=19.01 && st<=23.59){
    tot = m * r4;
    cout << fixed << setprecision(2) << "Total charges for this call is $" << tot << endl;}
    
 if(test>0.59 || stH>23 || m<0)
   cout << "\n** YOU HAVE ENTERED AN INVALID TIME **\n" << endl;

   return 0;
}
Floating point is inherently imprecise.

See: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
By the logic of your program line 16 is true and line 32 is true, if start-time is "1.99942" and m is -7.

Consider something similar to:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
unsigned int h=0, m=0, d=0;
cin >> h;
cin.ignore( 1 );
cin >> m;
if ( h < 24 && m < 60 )
{
  cin >> d;
  float rate = 0.0f;
  if ( h < 7 ) { rate = r1; }
  else if ( h < 13 ) { rate = r2; }
  else ...

  cout << d * rate;
}
else
{
  cout << "Error";
}
If I where to change it to a double datatype.... would I get the same result when though...I know it is a floating-type variable too.
Nichalos, this works on my PC if it is any help.
-- Donnie Down Under


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>
#include <iomanip>

using namespace std;

int main()
{
 double st, m, tot;

 cout << "Please enter the Start Time of your call in HH.MM: "; cin >> st;

 while(st<0 || st>24)
  {cout << "\n** YOU HAVE ENTERED AN INVALID TIME **\n";
   cout << "\nPlease enter a correct Start Time between zero and 24 hours.";
   cin >> st;}

   cout << "\nPlease enter the number of minutes of your call: "; cin >> m;

 while(m<=0)
  {cout << "\n** YOU HAVE ENTERED AN INVALID TIME **\n";
   cout << "\nPlease enter your call duration in minutes. ";
   cin >> m;}

 if(st>=00.00 && st<7.00)
    tot = m * .12;

 else if (st>07.00 && st<=13.00)
  tot = m * .23;

 else if (st>13.00 && st<19.00)
     tot = m * .55;

 else tot = m * .35;

    cout << fixed << setprecision(2) << "\nTotal charge for this call is $" << tot;

    cin.clear();
    cin.sync();
    cin.get();
    return 0;
}
@Donnie: I like the format but where the issue is a user will be able to enter a start time of something like 12.67 and there is no such thing as 12:67 pm. But love the loop idea just have to get past a user not being able to enter anything over .59 in the .mm field.

@kesk: the only problem is, I have to keep user-entered start time in the format hh.mm
Last edited on
I FIGURED IT OUT. After playing around with it! I turned the decimal .MM to an integer an and ran the IF statement on the INT:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

#include <iostream>
#include <iomanip>

using namespace std;

int main()
{
    const float r1 = .12, r2 = .23, r3 = .55, r4 = .35;
    float st, m, tot, stM;
    int test;

	cout << "Start Time: "; cin >> st; //06.59
	cout << "Number of minutes: "; cin >> m;//1
	stM = st - static_cast<int>(st);
	test =  static_cast<int>(100*stM);

    if(test> 59 || st>=24.00 || m<0)
            cout << "\n** YOU HAVE ENTERED AN INVALID TIME **\n" << endl;
	
    if(st>=00.00 && st<07.00){
			tot = m * r1;
			cout << fixed << setprecision(2) << "Total charges for this call is $" << tot << endl;}
	
    if (st>=07.00 && st<13.00){
			tot = m * r2;
			cout << fixed << setprecision(2) << "Total charges for this call is $" << tot << endl;}
   
    if (st>=13.00 && st<19.01){
            tot = m * r3;
            cout << fixed << setprecision(2) << "Total charges for this call is $" << tot << endl;}
  
    if (st>=19.01 && st<24.00){
            tot = m * r4;
            cout << fixed << setprecision(2) << "Total charges for this call is $" << tot << endl;}

        return 0;
}
@kesk: the only problem is, I have to keep user-entered start time in the format hh.mm

My code does so.
Nichalos, it doesn't matter in this particular case if a user does enter, say, 10.67 by mistake for the start time, because the computer recognizes this as a decimal number between 10 and 11, and uses the correct calling charge for this time zone (already defined by your code) anyway.

This works here because the start time is written as a decimal as requested, and not with a colon.

However, I understand why you would like to clean up this loose end, because normally it would matter.

Donnie Down Under

PS. To explain a bit more, 10.67 hours is actually 10 hours and 40 minutes,

whereas 10:67 am is a mistake and should be written as 11:07 am.

Last edited on
@kesk: I apologize if I overlooked the format. My mistake

@donnie: I understand exactly what you are saying, mathematically the result would fall within the boundaries of the current limits but I try to implement at least a little backwards compatibility for revision to the program and in a format that will be easier to update based on the expected format a company would give you for a revision(this case, i would expect a table with times and rates).

Lets say the company decided to make a bracket threshold change to 6:15am and lets also say the user then enters a time of 6.20. Mathmatically, the result will reside in bracket 1(<6:15) whereas the actual time 6:20am will reside in bracket 2 (>6:15).

@everyone: Thank-you for taking the time to respond with your experience and recommendations. I was about to pull out my hair. Lol!
Topic archived. No new replies allowed.