formatting arrays with numbers and characters - arrays

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

Related

Weird string formatting with 2 vs 4 decimal places in currency field

I have the following piece of code. I want to format numbers with string templates. One variable has 2 decimal places, the other 4 decimal places but they represent the same number 50000 (fifty thousand).
The first number is correctly formatted (German representation) 50.000,00, the other one however is formatted as 5 million 5.000.000,00!
DATA: lv_p2 TYPE p LENGTH 9 DECIMALS 2,
lv_p4 TYPE p LENGTH 14 DECIMALS 4.
START-OF-SELECTION.
lv_p2 = '50000'.
lv_p4 = lv_p2.
SET COUNTRY 'DE'.
"This is correctly formatted as 50.000,00
WRITE |{ lv_p2 NUMBER = ENVIRONMENT CURRENCY = 'EUR' }|.
"This is on the other hand interpreted as five million! 5.000.000,00
WRITE |{ lv_p4 NUMBER = ENVIRONMENT CURRENCY = 'EUR' }|.
Is this documented somewhere? What am I doing wrong here?
EDIT:
It looks like the problem is with the addition CURRENCY. If I don't use it, then the number is correctly formatted.
WRITE |{ lv_p4 NUMBER = ENVIRONMENT }|.
or WRITE |{ lv_p4 NUMBER = ENVIRONMENT DECIMALS = 2 }|.
Anyway looks like some kind of a bug.
I believe this behaviour is documented.
ABAP Documentation - WRITE, format_options - CURRENCY cur
When CURRENCY is added:
"For data objects of type p, the decimal places determined by the
definition of the data type are ignored completely. Independently of
the actual value and without rounding, decimal separators and
thousands separators are inserted between the digits in the places
determined by cur."
Shortly: if CURRENCY is added (by WRITE), the number of decimal places is determined by the currency (in this case EUR has 2 decimal places), so the value 50.000,0000 will be 5.000.000,00. Same length (9 digits) only the number of decimals will be different.

Formula to write milliseconds in hh:mm:ss.000 format gives wrong values

I'm trying to convert duration in one column which is written in milliseconds (Ex: 600,2101,1110....) to hh:mm:ss.000 format(Ex:00:00:00.600, 00:00:02.101...) using the below formula in google spreadsheets:
=CONCATENATE(TEXT(INT(A1/1000)/86400,"hh:mm:ss"),".",A1-(INT(A1/1000)*1000))
It gives correct values for almost all , but one type of values which is durations having '0' as their second digit (Eg: 2010,3056,1011).
When 0 is the second digit , the after decimal value in hh:mm:ss.000 is rounded to the third digit and 0 is ignored (Example row 1 and 2 in below table). But for other durations it gives right value(row 3).
I need a formula that works well on all type of values i.e 1080 → 00:00:01.080 and not 00:00:01.80 .
Can someone please help with this.
Duration in milliseconds
hh:mm:ss.000 format
1080
00:00:01.80 (wrong)
2010
00:00:02.10 (wrong)
1630
00:00:01.630 (correct)
try:
=INDEX(IF(A2:A="",,TEXT(A2:A/86400000, "hh:mm:ss.000")))

Iterating through a column in a CSV file in C

Not sure how to get loop through the columns only
Given the function header
double getMin(char csvfile[], char column[]);
return the minimum score of the specified column.
When implementing the above functions, you can assume csvfile is a valid CSV file and it can always be opened for reading, and the column parameter is a short form of the column heading and it starts with a letter (P for Participation, C for Challenge, and L for Lab) followed by a chapter number, a dot, and a section number. For example, P5.6, C5.4 and L5.25 represent the column headings 5.6 – Participation, 5.4 – Challenge, and 5.25 – Lab respectively. You shall return -2.0 (double) or 2 (integer) if the corresponding column name or student name does not exist, and -1.0 or 1 if the corresponding column is optional.
Ex. file-
Last name,First name,5.1 - Participation (11),5.2 - Participation (20), 5.1 - Challenge (0),5.2 - Challenge (9), 5.25 - Lab (10)
Alvarez,Abel,100,100,100,100,100
Mendez,Charlene,0,0,0,0,0
Zimmerman,Drew,100,100,100,100,60
set accumulator to 0.
set numberoflines to 0.
read the file line by line (but ignore first header line); goto 6 if no more lines
for each line skip n-1 commas (beware commas embedded in quotes) increment numberoflines and add the value to the accumulator
goto 3.
divide accumulator by numberoflines and return.

Adding 0 at starting of int value in 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

Concatenating all characters from a date into a 1x1 array in Matlab

I need to concatenate all characters from a date/time string into a single 1x1 array.
If I do
K>> datestr(now, 'mmm dd yyyy - HH:MM')
ans =
Jan 04 2014 - 11:58
K>> size(datestr(now, 'mmm dd yyyy - HH:MM'))
ans =
1 19
I end up with a 1x19 array for my date. It needs to be 1x1 as it will be the first of many other comma separated values exported to a single CSV file.
values =[
software_version; date_time; % <===== date_time should be 1x1 to fit
P_total; P_total_SD; P_total_CV; % in single cell
t1;
con_int1; con_int2; ...
];
Do you have any suggestions on how to accomplish this?
My question is only partially addressed here, so I believe this is not a duplicate.
They suggest dlmwrite but that will not work for my case in which there are many other values being output to a single file.
The string has 19 characters, so as a character array it is necessarily of size 1x19. How to write this to a CSV file depends on the method you use; if the respective function supports to output strings to the file, I would expect it to accept a cell array as input. In that case, your 1x19 character array would be contained in one cell of the cell array:
values ={
software_version; date_time;
P_total; P_total_SD; P_total_CV;
t1;
con_int1; con_int2; ...
};
The difference from your code is to replace [] by {}.

Resources