Adding 0 at starting of int value in c - c

I am in WinCE7 and to get the current time, I am using GetLocalTime(&systemTime);. This function gives the value of current time. Now if the milliseconds is 81, it displays it as 81 due to which the error occurs when I subtract two time values. For ex: time1 : 12:34:13:851 & time2: 12:34:14:81. Now I need to subtract seconds and milliseconds. So using sprintf, I am extracting seconds and milliseconds and putting them in time1 & time2 :
sprintf(time1,"%d.%d",systemTime.wSeconds,systemTime.wMilliseconds)
sprintf(time2,"%d.%d",systemTime.wSeconds,systemTime.wMilliseconds)
I am converting time1 & time2 into float using atof.Now time1 is 13.851 and time2 is 14.81. The milliseconds of time2 is actually 081 but it displays 81 so while subtracting it consider it as 810 which gives wrong values.
time2--> 14.810 14.081
time1--> 13.851 13.851
-------- ---------
result 0.959(wrong) 0.23(correct)
So to remove this error I thought of counting the digits of milliseconds and if it is 2 then add 0 at starting. So I did:
double digits = (floor (log10 (abs (milliseconds))) + 1); //calculate digits
if(digits == 2) //if milliseconds contains 2 digits, we need to add 0 at starting
{
sprintf(newMS,"0%d",milliseconds); //adding 0 to milliseconds
finalMilliseconds = atoi(newMS); //newMS is in char so converting it into integer and storing the value in finalMilliseconds
}
The problem occurs here. Lets say milliseconds = 18, so newMS = 018 but finalMilliseconds is again 18.
Please suggest any other way of conversion or any other way of adding 0 at starting

According to the documentation of SYSTEMTIME from MSDN:
It is not recommended that you add and subtract values from the
SYSTEMTIME structure to obtain relative times. Instead, you should
Convert the SYSTEMTIME structure to a FILETIME structure.
Copy the resulting FILETIME structure to a ULARGE_INTEGER structure.
Use normal 64-bit arithmetic on the ULARGE_INTEGER value.
The example here will give you some idea on how to get started.

It seems to me the simplest solution is to borrow what you need.
You already have integers. If you're subtracting two systemTime values, t2 from t1, say,
if( t1.wMilliseconds < t2.wMilliseconds ) {
t1.wMilliseconds += 1000;
t1.wSeconds--;
}
Or, just perform the subtraction. If the result's wMlliseconds is negative, adjust as above.
Take care to ensure t1 > t2, though. You don't want -1.25 = 0.0 - 0.75.
Instead of putzing with strings, if you want a float, make one:
double time1 = t1.wSeconds + 0.001 * t1.wMilliseconds;
C does the conversion for you. It's faster, more direct, and less error-prone than going through strings.

Another way of dealing with these marvels of lost leading or trailing zeroes (found in time and longlat), is to right pad the string with say four zeroes .i.e your newMS+"0000", and take the leftmost four characters.
You then have a number (as text) ranging from "0000" to "9990".
Put a "1" in front of it, then you can easily and unambiguously convert to an integer between 10000 and 19990.
Then you can add and subtract as you like.
Clumsy? Yes indeed :) But I have had to do weird tricks like this when GPS longitude readings go from 11.59(funny numbers) to 12.00

Related

formatting arrays with numbers and characters

I need help turning a Decay.txt file into an array, the first 1-3 and 5th columns are numbers, the third column is "time elapsed" in integers, but the 4th column is a unit of time (milliseconds, Months, Days) but its spelled out with characters. i cant get this mixed array (numbers and characters) to transfer over to matlab
ideally id like to take the unit of time (4th column) change it to a seconds value, (i.e. hour becomes 3600 seconds) then multiply it by the number in the third column and have a final 4 column array where the 3rd column is simply the time elapsed in seconds
anyone know how to do either of these things?
ive tried
Decay = fopen('Decay.txt','r');
B = fscanf(Decay,'%f',[5 inf]);
which stops and has an error as soon as it hits the 4th column
and
Decay = fopen('Decay.txt','r');
B = fscanf(Decay,'%s',[5 inf]);
but this just creates a 5x10000 column where every single number, decimal, and letter is on its own in its own cell of the array
Your first example
Decay = fopen('Decay.txt','r');
B = fscanf(Decay,'%f',[5 inf]);
Breaks because it can't scan the fourth column (a string) as a number (%f). Your second example doesn't have numbers because you're scanning everything as a string (%s).
The correct specifier for your format should be
'%f %f %f %s %f'
However, if you call fscanfwith it, as per documentation:
If formatSpec contains a combination of numeric and character specifiers, then A is numeric, of class double, and fscanf converts each text characters to its numeric equivalent. This occurs even when formatSpec explicitly skips all numeric fields (for example, formatSpec is '%*d %s').
So this input file:
50 1.2 99 s 0
6.42 1.2 3.11 min 1
22 37 0.01 h 2
Has this (undesired) output:
>> fscanf(Decay, "%f %f %f %s %f", [5, inf])
ans =
50.0000 6.4200 110.0000 104.0000
1.2000 1.2000 1.0000 2.0000
99.0000 3.1100 22.0000 0
115.0000 109.0000 37.0000 0
0 105.0000 0.0100 0
That happens because a matrix in MATLAB can't have multiple data of different types. So, your best bet is scanning into a cell array, which can have any type inside.
B = textscan(Decay, "%f %f %f %s %f")
Returns a cell array with the appropriate types. You can use this output to convert the time data into the same unit and build your vectors/matrix. Columns 1, 2, 3 and 5 are trivial to do, just by accessing the cell B{n} for each n.
Column 4 is a cell array of cells. In each internal cell, there's the string you have. You need to apply a conversion from string to the number you need. For my example, such function would look like:
function scale = DecayScale(unit)
switch(unit)
case 's'
scale = 1;
case 'min'
scale = 60;
case 'h'
scale = 3600;
otherwise
throw('Number format not recognized');
end
end
Which you could then apply to the 4th column like:
timeScale = cellfun(#DecayScale, B{4})
And get the final time as:
timeColumn = B{3} .* timeScale

GMT subtraction on MATLAB

I'm currently working on a small project on handling time difference on MATLAB. I have two input files; Time_in and Time_out. The two files contain arrays of time in the format e.g 2315 (GMT - Hours and Minute)
I've read both Time_in' and 'Time_out on MATLAB but I don't know how to perform the subtraction. Also, I want the corresponding answers to be in minutes domain only e.g (2hrs 30mins = 150minutes)
this is one of several possible solutions:
First, you should convert your time strings to a MATLAB serial date number. If you've done this, you can do your calculation as you want:
% input time as string
time_in = '2115';
time_out = '2345';
% read the input time as datenum
dTime_in = datenum(time_in,'HHMM');
dTime_out = datenum(time_out,'HHMM');
% subtract to get the time difference
timeDiff = abs(dTime_out - dTime_in);
% Get the minutes of the time difference
timeout = timeDiff * 24 * 60;
Furthermore, to calculate the time differences correctly you also should put some information about the date in your time vector, in order to calculate the correct time around midnight.
If you need further information about the function datenum you should read the following part of the MATLAB documentation:
https://de.mathworks.com/help/matlab/ref/datenum.html
Any questions?
In a recent version of MATLAB, you could use textscan together with datetime and duration data types to do this.
% read the first file
fh1 = fopen('Time_in');
d1 = textscan(fh1, '%{HHmm}D');
fclose(fh1);
fh2 = fopen('Time_out');
d2 = textscan(fh2, '%{HHmm}D');
fclose(fh2);
Note the format specifier '%{HHmm}D' tells MATLAB to read the 4-digit string into a datetime array.
d1 and d2 are now cell arrays where the only element is a datetime vector. You can subtract these, and then use the minutes function to find the number of minutes.
result = minutes(d2{1} - d1{1})

algorithm for finding date in sorted array of dates

here is my problem.
I have a sorted array of dates that is stored in a circular buffer. I have a pointer to last date in buffer. There is a possibility that some dates are missing. Client requires a range of dates. If low limit date is missing, program should return first closest date that is higher then required one and vice versa for upper limit date.
Here is an example:
Dates in circular buffer (int[18]):
1,2,3,4,5,11,12,13,14,15,21,22,23,24,25,26,27,28
and if client wants from 8 to 23,
program should return 11,12,13,14,15,21,22,23.
I tried like this :
Notes:
- number between two stars is current date, and diff is number of steps to go to find 8.
- pointer can not be less then 0 or higher then 17.
{1,2,3,4,5,11,12,13,14,15,21,22,23,24,25,26,27,*28*}, diff = -20
{*1*,2,3,4,5,11,12,13,14,15,21,22,23,24,25,26,27,28}, diff = +7
{1,2,3,4,5,11,12,*13*,14,15,21,22,23,24,25,26,27,28}, diff = -5
{1,2,*3*,4,5,11,12,13,14,15,21,22,23,24,25,26,27,28}, diff = +5 -> (5/2)+1=+3<br />
(if I detect that I will just go x steps forward and x steps backward I split x in half)
{1,2,3,4,5,*11*,12,13,14,15,21,22,23,24,25,26,27,28}, diff = -3 -> (-3/2)-1 = -2
{1,2,3,*4*,5,11,12,13,14,15,21,22,23,24,25,26,27,28}, diff = 4
{1,2,3,4,5,11,12,*13*,14,15,21,22,23,24,25,26,27,28}, diff = -5
{1,2,*3*,4,5,11,12,13,14,15,21,22,23,24,25,26,27,28}, diff = +5 -> (5/2)+1=+3
If we continue like this we will get 13,3,11,4 over and over again.
Notes:
- It is only coincidence that we get 11 here. When I use some real examples, with more dates,this algorithm jumps over some other 4 (or 3) numbers.
- Dates are stored in EEPROM of uC, so reading dates take a while, and I need to find date as quick as it possible (with minimum reads).
Please help.
Set p1 to be the start of the buffer, p2 to be the end. X is what you're looking for.
If the date of p1Date is after X, return p1. If p2Date is before X return p2.
Look at the midpoint between p1 and p2, m. If mDate is after X then p1=m else p2=m.
Repeat until p1=p2.

Get the complete number when divide two fields

I was trying to round some fields. When I have 59 days, I want to change it to 60.
The problem is that when I use this code, the 59 is changed to 30 because the round it is 1.
select round(1.9666,0)*30, round(59/30,0)*3'
The result of that query is 60 for the first field and 30 for the second one. The problem is that when I've tried:
select 59/30
The result is 1 and I need the entire answer that is 1.9666...
How can I make it?
Because the number you are dividing by is an INT (the data type of the left side is irrelevant), SQL Server will return an INT as the answer.
If you want a number with a decimal place as your result, you'll need to divide by one.
Don't cast to a FLOAT as the answer is probably not what you want (floats are generally not accurate and are 'approximations'):
SELECT 59 / CAST(30 AS FLOAT) -- = 1.96666666666667
CAST the right-hand side of the division to a DECIMAL:
SELECT 59 / CAST(30 AS DECIMAL(10, 2)) -- = 1.96666
SELECT cast(59 AS FLOAT) / cast(30 AS FLOAT)
Because the original figures are whole numbers, SQL presumes you want a whole number output.
To ensure you get one with the decimal places, you need to first change the data type from an integer int to a floating point float.
This is what the CAST command does.
EDIT: Commenter suggests you cast to DECIMAL instead. The principle is the same, but you need to supply more arguments. To cast to a decimal use something like:
cast(59 as DECIMAL(18, 3))
The first argument (the 18) is the total number of figures you want to permit in the decimal. The second argument (the 3) is the number you want after the decimal point.
The suggestion that it's more accurate is correct - as you'll see if you run the SELECT statements in this answer one after the other. But in this particular case, it only makes a tiny difference.

What is the best way to change to a currency format?

I have a list of values such as "12000","12345","123456" that need to be converted to currency ("120.00", "123.45", "1234.56"). The only way I know is to convert the value to a string, copy the first strlen()-2 characters to one string (dollars) and the remainging two digits to another string(cents) and then write them as the following:
printf("%s.%s", dollars, cents);
printf("$%.2f", value/100);
Don't use floats for storing or representing monetary amounts. Use longs (if you need more than 4 billion cent use llongs). Its usually a good idea to represent currency in its minimum usable unit, example use 10000 to represent 100Euro). Then the correct way to format these values (assuming 100 cent to the euro or dollar) is:
printf( "%d.%02d", value/100, value%100);
Hope that makes sense...
Calculations with currency values is a complex subject but you cant go far wrong is you always aim to have a rounded answer to the nearest currency unit (cent for example) and always make sure that rounding errors are calculated for (example, to divide 1 dollar three ways you should end up with 33+33+34 or 33+33+33+1).
to prefix values less than $1.00 with 0, use:
printf( "$%0.2f", value / 100.0 );
This will result in $0.25 if value = 25

Resources