I am asking the user to input a start time and an end time in this format: 15.45 (military time with a decimal instead of a colon) and I need to convert those times to a float to perform calculations on them. I am having trouble wrapping my mind around converting the 60 minutes of an hour to a decimal value. e.g. - User inputs start of 12.45 and end of 14.15, this should be converted to 12.75 and 14.25 respectively. How would I go about this conversion?
Also, something I believe I am more capable of figuring out, but curious anyway: how would I validate input so as not to allow a time greater than 23.59 and no time with the last two digits greater than 59?
As soon as one of the values is double, then the arithmetic will be
done in double, with double results. So you can convert the
minutes to double, using any of the three C++ syntaxes:
static_cast<double>(minutes), double(minutes) or (double)minutes,
or just divide by 60.0, rather than the integer 60. (I like to be
explicit, so I'd write double(minutes) / 60.0. And some people prefer
static_cast, even in this case.)
With regards to the validation, I'd do it before conversion; once you've
added the minutes to the hours, it's too late anyway.
just use
double time = hours + minutes / 60.0;
bool hoursValid = hours < 24; // hours are unsigned, right?
bool minutesValid = minutes < 60;
Example:
char buf[] = "9.45";
unsigned int hours, minutes;
sscanf(buf, "%d.%d", &hours, &minutes);
printf("%f", hours + minutes/60.0); // outputs 9.75
If you get double 9.45 as input, you need to #include <cmath> and split it as
hours = floor(v);
minutes = (v - hours) * 100;
You have to separate the integer and decimal components of the number. You will keep the integer part intact, then add the decimal part divided by 60 to it.
Validation is also simple once you separate into hours and minutes.
I'm going to assume your code reads the value in from the user as a string. You will need to parse the user input at the decimal point to get the hours and minutes as two separate values. Once you have that, then you can convert minutes into a fraction of an hour and add it to the number of hours.
bool military_time_valid(float a) {
int t = (int)a;
if (t >= 24)
throw std::runtime_error("invalid hours");
if (a-t >= .6)
throw std::runtime_error("invalid minutes");
}
float military_to_decimal(float a) {
int t = (int)a;
return t + (a-t)/.6;
}
float decimal_to_military(float a) {
int t = (int)a;
return t + (a-t)*.6;
}
float t = 15.45;
int h = (int) t;
float m = 100 * (t - h);
printf("%f", h + m / 60);
gives output: 15.750000
Check if h is between 0 and 23 and m is between 0 and 59.
Is there some reason you don't want to create a MilTime class and overload the arithmetic operators? That would save you from having to convert to/from all the time, and would more clearly state your intentions.
Related
I have two times stored in int type in a struct and want to calculate the no. of hours elapsed in between two times. How do I correctly store the result of in a double variable. I seem to get the difference wrong. Also how do I store the result up to two places after the decimal point.
This is my code :
struct time
{
int hour=0,min=0;
char am_pm='a';
};
int main()
{
time t1,t2;
// GET THE TIME INPUT FROM THE USER HERE
//assuming always t2's hour and min are always numerically greater than t1's hour and min and always `am`
double hour_diff=0.00,min_diff=0.00;
double time_elapsed=0.00;
cout<<"The time elapsed between your entered times is : ";
hour_diff=t2.hour-t1.hour; counting hour difference
min_diff=(t2.min+t1.min)/60; //counting total minutes and converting them into hours
time_elapsed=hour_diff+min_diff;
cout<<time_elapsed;
if i give these input i get wrong result 7 when i should get 7.25 :
INPUT
t1.hour = 5
t1.min = 30
t1.am_pm = a;
t2.hour = 11
t2.min = 45
t2.am_pm = a;
time elapsed = 7 // this is wrong, I should be getting 7.25
The error is because this expression (t2.min+t1.min)/60 will return int.
That's because (t2.min+t1.min) is of type int and 60 is of type int. Hence \ will be an integer division operation.
To resolve it you can convert your (t2.min+t1.min) to the double with static_cast<double>(t2.min+t1.min). See more about static_cast.
Or you can simply define 60 as a double by writing 60.0.
Since you are performing integer operations '(t2.min + t1.min)/60', even though you are storing them in a variable of type double, become simplified to an integer type.
Either make 60 a double by changing it to '60.0' or encompass the whole result with a 'static_cast' before your operations.
Background:
I have an array of integer times given as 0830 for 08:30, 1745 for 17:45, etc.
I need to calculate the time difference between times. So I'm first turning integer times into floating point times by dividing by 100.0. This means that 0830 will become 8.30.
int inTime = 0830, outTime = 1745;
float newIntime = inTime/100.0;
float newOutTime = outTime/100.0;
The next step, and this is my question, is: How do I divide the decimal part by 0.6 so I get 8.50. This is the only way I'll be able to subtract/add times and get the correct time difference in a meaningful format.
I have not been able to figure out (or look up) a way to multiply the decimal part, i.e. to "access" only what's on the right side of the decimal point. Any help will be appreciated!
float intPart = floor(newInTime);
float converted = intPart + (newInTime - intPart) / 0.6;
And it's better to not use float for this purpose. See others' answer.
Don't convert to float in the first place. Use modulus to extract the minutes:
int inTime = 830;
int inHours = inTime / 100;
int inMinutes = inTime % 100;
int inTotalMinutes = inHours * 60 + inMinutes;
Also, 0830 is not a valid literal. The leading zero causes it to be interpreted as an octal number, and 8 is not a valid octal digit.
You do not want to do this in float, because you will be potentially losing precision.
I would suggest doing something along the line of:
// or use std::tm per Potatoswatter's comment
struct Time
{
int hours;
int minutes;
Time(int time)
{
hours = time/100;
minutes = time-hours*100;
}
};
Time operator-(const Time& a, const Time& b)
{
// You could also just return these minutes and be done with it
int minutes (a.hours-b.hours)*60 + (a.minutes-b.minutes);
Time result;
result.hours = minutes/60;
result.minutes = minutes-result.hours;
}
int main()
{
Time inTime(830), outTime(1745);
Time result = inTime-outTime;
// ...
return 0;
}
Another thing to keep in mind, is that you should not write:
Time inTime(0830);
because the compiler will think that you are talking about octal base (and it cannot have the 8 as a digit).
It is easier and more reasonable to convert 08:30 to 8.5 rather than 8.3 for floating point calculation. It is 8.5 hours from 0:00. Convert back is also easy. Hour is whatever to the left of decimal point and minute is whatever to the right of decimal point multiple by 60.
Extract it with modf. That should eliminate the extra loss of precision.
Code in question:
std::stringstream cd;
int f = int((15 / allyCounter) * 100);
cd << f;
allyCounter is equal to 45. the idea is to get what percentage 15 is of allyCounter where allyCounter is a dynamic int that is constantly changing. i don't have much experience with c++ so I'm sure what I'm missing is something fundamental.
The problem here is almost certainly with integer vs. floating point math.
15/45 (when done in integer math) is 0.
Try
std::stringstream cd;
int f = int((15.0 / allyCounter) * 100);
cd << f;
...and see if things aren't better. 15.0 is a double precision floating point constant, so that'll force the math to be done in floating point instead of integers, so you'll get a percentage.
Another possibility would be to do the multiplication ahead of the division:
int f = 1500 / allyCounter;
If the numerator were a variable, this could lead to a problem from the numerator overflowing, but in this case we know it's a value that can't overflow.
In C++, 15 / 45 is 0. (It's called "integer division": the result of dividing two ints in C++ is also an int, and thus the real answer is truncated, and 15 / 45 is 0.)
If this is your issue, just make it a double before doing the division:
int f = static_cast<double>(15) / allyCounter * 100;
or even:
int f = 15. / allyCounter * 100;
(The . in 15. causes that to be a double.)
You are using integer division:
std::stringstream cd;
int f = int((15.0 / allyCounter) * 100);
cd << f;
The compiler sees 15/allyCounter and thinks it should return an integer (you passed it two integers, right?). 15/150 == 0 with integer division, you always round down. In this case the compiler sees 15.0 as a double, and uses decimal places.
I'm doing some homework for a C++ class, and i'm pretty new to C++. I've run into some issues with my if statement... What i'm doing, is i have the user input a time, between 0.00 and 23.59. the : is replaced by a period btw. that part works. i then am seperating the hour and the minute, and checking them to make sure that they are in valid restraints. checking the hour works, but not the minute... heres my code:
minute= startTime - static_cast<int>(startTime);
hour= static_cast<int>(startTime);
//check validity
if (minute > 0.59) {
cout << "ERROR! ENTERED INVALID TIME! SHUTTING DOWN..." << endl;;
return(0);
}
if (hour > 23) {
cout << "ERROR! ENTERED INVALID TIME! SHUTTING DOWN..." << endl;;
return(0);
}
again, the hour works if i enter 23, but if i enter 23.59, i get the error, but if i enter 23.01 i do not. also, if i enter 0.59 it also gives the error, but not 0.58. I tried switching the if(minute > 0.59) to if(minute > 0.6) but for some reason that caused problems elsewhere. i am at a complete loss as to what to do, so any help would be great! thanks a million!
EDIT: i just entered 0.58, and it didnt give me the error... but if i make it a 1.59 it gives an error again... also, upvotes would be nice :D
Floating-point arithmetic (float and double) is inherently fuzzy. There are always some digits behind the decimal point that you don't see in the rounded representation that is sent to your stream, and comparisons can also be fuzzy because the representation you are used to (decimal) is not the one the computer uses (binary).
Represent a time as int hours and int minutes, and your problems will fade away. Most libraries measure time in ticks (usually seconds or microseconds) and do not offer sub-tick resolution. You do well to emulate them.
Comparison of floating point numbers is prone to failure, because very few of them can be represented exactly in base 2. There's always going to be some possibility that two different numbers are going to round in different directions.
The simplest fix is to add a very tiny fudge factor to the number you're comparing:
if (minute > 0.59 + epsilon)
See What Every Computer Scientist Should Know About Floating-Point Arithmetic.
Don't, ever, use double (nor float) to store two integer values using the integer and decimal part as separator. The decimal data types are not precise enough, so you may have wrong results (in case of a round).
A good solution in your case is either to use a struct (or a pair) or even an integer.
With integer, you can use mod or div of multiples of then to extract the real value. Example:
int startTime = 2359;
int hour = startTime / 100;
int minute = startTime % 100;
Although, with struct the code would look simpler and easier to understand (and to maintain).
There's no way you can compare to exactly 0.59; this value
cannot be represented in the machine. You're comparing
something which is very close to 0.59 with something else that
is very close to 0.59.
Personally, I wouldn't input time this way at all. A much
better solution would be to learn how to use std::istream to
read the value. But if you insist, and you have startTime as
your double, you need to multiply it by 100.0 (so that all
of the values that interest you are integers, and can be
represented exactly), then round it, then convert it to an
integer, and use the modulo and division operators on the
integer to extract your values. Something along the lines of:
assert( startTime >= 0.0 && startTime <= 24.0 );
int tmpTime = 100.0 * startTime + 0.5;
int minute = tmpTime % 100;
int hour = tmpTime / 100;
When dealing with integral values, it's much simpler to use
integral types.
unsigned int deltaTime = now() - last();
unsigned int freq = getFreq();
float timeOfGap = float(deltaTime) / float(freq);
ASSERT(0.0f <= timeOfGap, "WHAT?");
I got a really weired result from my program. I didn't catch a scene which is happened. But I have a log which said that really raised at least multiple times.
There are possible way of dividing between two float numbers which was casted from unsigned int make negative float result?
OK, thank you guys. I'm glad to see your attentions.
Let me try to add some descriptions about it. It'll be helpful for you.
I'm working for an online game, and this situation was raised rarely but frequently while hundreds of million times game was serving. I can't debug or catch the exact shot, but it is logged on the db error messages.
The timeOfGap should be NaN as you noticed, but the log didn't alert the value exactly. The timeOfGap is accumulated like below;
mTotalFrameRateTimeAsASecond += timeOfGap;
And this program logs mTotalFrameRateTimeAsASecond, that was a negative value. But except this sign of value was a negative, it is correct value. Meaning, it point time as look as good if I divide the final value with a framerate. A hypothetical play time was 500 sec, it is -30000(with 60 framerate per sec).
Maybe it is not negative, but a NAN. 0.0f <= NAN is false. It may happen if both operands are zero.
This should find the problem:
unsigned int deltaTime = now() - last();
unsigned int freq = getFreq();
float timeOfGap = float(deltaTime) / float(freq);
char s[50] ;
sprintf (s, "WHAT? %u/%u < 0!", deltaTime, freq);
ASSERT(0.0f <= timeOfGap, s);
The value nan will not compare to anything successfully. So if you have:
float f = 0.0 / 0.0;
assert(f > 0 || f <= 0);
The assertion will fail!
You can do a simple test to verify the cast from unsigned int to float.
Try this :
unsigned int toto = 0xFFFFFFFF;
float convertedToto = float(toto);
convertedToto will equals -1 if the convertion (unsigned int -> float) is in fact (int -> float). You should get 2*10e31 with a proper conversion.