Efficiently iterating successive elements of a transposed matrix (via bit operators) - c

Let's consider matrices which are internally represented as a 1 dimensional array.
For instance a matrix(3, 4) is really an array (of say type double) or 3*4 elements. Here is the 'memory layout' of the matrix:
00 01 02 03
04 05 06 07
08 09 10 11
As such it's very easy to iterate (row by row, left to right) over all the elements of the matrix: it's just an 32-bit integer going from 0 to 11. This is what the transpose looks like:
00 04 08
01 05 09
02 06 10
03 07 11
What is a (fast) algorithm that taking as input a single 32-bit integer representing the i-th element of the transposed matrix (row by row, left to right) returns the index corresponding to the internal representation? By single I mean that an 'incremental' algorithm is not what I'm looking for, the function just take as input a single 32-bit integer (plus number of rows and columns) and output a single 32-bit integer. I mentioned bit-wise operators as it's likely to be the fastest way to solve the problem but any efficient solution suffice really.
In the example above:
0 --> 0
1 --> 4
2 --> 8
3 --> 1
4 --> 5
5 --> 9
6 --> 2
...
Also, what restrictions (if any) need to be imposed on the number of rows and columns (we already have that num_row*num_col fits in a 32-bit integer) so that the algorithms is guaranteed to work.
Thank you!

As long as the dimensions remain small, you can use a constant as a lookup table:
0x4cd0b73a62951840 >> (x*4)) & 15
If they get slightly larger, you could split this into e.g. generating the upper and lower bits of the result:
((0x00fea540 >> (x*2)) & 3) | (((0x00924924 >> (x*2) & 3) << 2))
Eventually though, the straight-forward approach will be faster.

Related

How to convert an array of 8 bytes into a 32-bit number, if the system does not support 64-bit arithmetic

I have an array of 8 bytes representing some huge number, e.g.
11017125042 decimal - as bytes it looks like 00 00 00 02 90 AB FC B2.
I want to convert the 8 bytes into a 32-bit signed integer, getting rid of last 4 digits.
In case you wonder, that's a position value, where one revolution is 1 billion units, so the value means 11.017125042 revolutions. I don't need such absurd resolution, so I want to get the initial value divided by 10 000 - 1101712 instead of 11017125042.
The tricky part is that the system (a Siemens PLC) does not support 64-bit arithmetic.
Any idea how to do it?
Thanks for any suggestions.
Do it in a SCL block or SCL network of a LAD/FBD block.
#posLrealDiv10k :=
+ #posBytes[7] * 0.0001 //remove if you don't care
+ #posBytes[6] * 0.0256 //remove if you don't care
+ #posBytes[5] * 6.5536 //...
+ #posBytes[4] * 1677.7216
+ #posBytes[3] * 429496.7296
+ #posBytes[2] * 109951162.7776
+ #posBytes[1] * 28147497671.0656
+ #posBytes[0] * 7205759403792.7936;
The SIOS forum is usually quite helpful with this sort of conversion problem. Just not this particular one, it seems.

Does MATLAB support truly 1d arrays?

It would really help me reason about my MATLAB code if I didn't have to worry about accidental 2d operations. For instance, if I want to do element-wise multiplication of 1d arrays, but one is a row and another is a column, I end up with a 2d result.
>> a = 1:8;
>> a = a(:);
>> a .* cumsum(ones(8))
ans =
1 1 1 1 1 1 1 1
4 4 4 4 4 4 4 4
9 9 9 9 9 9 9 9
16 16 16 16 16 16 16 16
25 25 25 25 25 25 25 25
36 36 36 36 36 36 36 36
49 49 49 49 49 49 49 49
64 64 64 64 64 64 64 64
I'd like to prevent this type of thing, and likely other problems that I can't foresee, by keeping all my arrays 1d wherever I can. But every time I check the size() of vector, I get at least 2 elements back:
>> size(1:1:6)
ans =
1 6
>> size(linspace(0, 5, 10))
ans =
1 10
I've tried the suggestions at How to create single dimensional array in matlab? and some of the options here (PDF download), and I can't get a "truly" 1d array. How would you deal with this type of issue?
There is no such thing as 1D array. The documentation says (emphasis mine):
All MATLAB variables are multidimensional arrays, no matter what type of data. A matrix is a two-dimensional array often used for linear algebra.
You may use isvector, isrow and iscolumn to identify vectors, row vectors and column vectors respectively.
#Sardar has already said the last word. Another clue is ndims:
N = ndims(A) returns the number of dimensions in the array A. The
number of dimensions is always greater than or equal to 2. ...
But about your other question:
How would you deal with this type of issue?
There's not much you can do. Debug, find the mistake and fix it. If it's some one-time script, you are done. But if you are writing functions that may be used later, it's better to protect them from accepting arguments with unequal dimensions:
function myFunc(A, B)
if ndims(A)~=ndims(B) || any(size(A)~=size(B))
error('Matrix dimensions must agree.');
end
% ...
end
Or, if your function really needs them to be vectors:
function myFunc(A, B)
if ~isvector(A) || ~isvector(B) || any(size(A)~=size(B))
error('A and B must be vectors with same dimensions.');
end
% ...
end
You can also validate different attributes of arguments using validateattributes:
function myFunc(A, B)
validateattributes(A, {'numeric'},{'vector'}, 'myFunc', 'A')
validateattributes(B, {'numeric'},{'size', size(A)}, 'myFunc', 'B')
% ...
end
Edit:
Also, if the function only needs the inputs to be vectors and their orientation does not matter, you can modify them inside the function (thanks to #CrisLuengo for commenting).
function myFunc(A, B)
if ~isvector(A) || ~isvector(B) || length(A)~=length(B)
error('A and B must be vectors with the same length.');
end
A = A(:);
B = B(:);
% ...
end
However, this is not recommended when the output of the function is also a vector with the same size as the inputs. This is because the caller expects the output to be in the same orientation as the inputs, and if this is not the case, problems may arise.

Multi-Dimensional Arrays Julia

I am new to using Julia and have little experience with the language. I am trying to understand how multi-dimensional arrays work in it and how to access the array at the different dimensions. The documentation confuses me, so maybe someone here can explain it better.
I created an array (m = Array{Int64}(6,3)) and am trying to access the different parts of that array. Clearly I am understanding it wrong so any help in general about Arrays/Multi-Dimensional Arrays would help.
Thanks
Edit I am trying to read a file in that has the contents
58 129 10
58 129 7
25 56 10
24 125 25
24 125 15
13 41 10
0
The purpose of the project is to take these fractions (58/129) and round the fractions using farey sequence. The last number in the row is what both numbers need to be below. Currently, I am not looking for help on how to do the problem, just how to create a multidimensional array with all the numbers except the last row (0). My trouble is how to put the numbers into the array after I have created it.
So I want m[0][0] = 58, so on. I'm not sure how syntax works for this and the manual is confusing. Hopefully this is enough information.
Julia's arrays are not lists-of-lists or arrays of pointers. They are a single container, with elements arranged in a rectangular shape. As such, you do not access successive dimensions with repeated indexing calls like m[j][i] — instead you use one indexing call with multiple indices: m[i, j].
If you trim off that last 0 in your file, you can just use the built-in readdlm to load that file into a matrix. I've copied those first six rows into my clipboard to make it a bit easier to follow here:
julia> str = clipboard()
"58 129 10\n58 129 7\n25 56 10\n24 125 25\n24 125 15\n13 41 10"
julia> readdlm(IOBuffer(str), Int) # or readdlm("path/to/trimmed/file", Int)
6×3 Array{Int64,2}:
58 129 10
58 129 7
25 56 10
24 125 25
24 125 15
13 41 10
That's not very helpful in teaching you how Julia's arrays work, though. Constructing an array like m = Array{Int64}(6,3) creates an uninitialized matrix with 18 elements arranged in 6 rows and 3 columns. It's a bit easier to see how things work if we fill it with a sensible pattern:
julia> m .= [10,20,30,40,50,60] .+ [1 2 3]
6×3 Array{Int64,2}:
11 12 13
21 22 23
31 32 33
41 42 43
51 52 53
61 62 63
This has set up the values of the array to have the row number in their tens place and the column number in the ones place. Accessing m[r,c] returns the value in m at row r and column c.
julia> m[2,3] # second row, third column
23
Now, r and c don't have to be integers — they can also be vectors of integers to select multiple rows or columns:
julia> m[[2,3,4],[1,2]] # Selects rows 2, 3, and 4 across columns 1 and 2
3×2 Array{Int64,2}:
21 22
31 32
41 42
Of course ranges like 2:4 are just vectors themselves, so you can more easily and efficiently write that example as m[2:4, 1:2]. A : by itself is a shorthand for a vector of all the indices within the dimension it indexes into:
julia> m[1, :] # the first row of all columns
3-element Array{Int64,1}:
11
12
13
julia> m[:, 1] # all rows of the first column
6-element Array{Int64,1}:
11
21
31
41
51
61
Finally, note that Julia's Array is column-major and arranged contiguously in memory. This means that if you just use one index, like m[2], you're just going to walk down that first column. As a special extension, we support what's commonly referred to as "linear indexing", where we allow that single index to span into the higher dimensions. So m[7] accesses the 7th contiguous element, wrapping around into the first row of the second column:
julia> m[5],m[6],m[7],m[8]
(51, 61, 12, 22)

fpe2 and sp78 data types?

I've been analysing the code needed to get CPU temperature and CPU fan speed on Mac OS X.
There are many examples out there. Here is one of them:
https://github.com/lavoiesl/osx-cpu-temp
Now, in the smc.h file there are some strange(to me) data types defined:
#define DATATYPE_FPE2 "fpe2"
#define DATATYPE_SP78 "sp78"
These are data types that later Apple's IOKit writes in memory as a return value, and that then need to be converted to something usable. The author of the code does it like so (Note that he made a typo writing fp78 instead sp78 in comments...):
// convert fp78 value to temperature
int intValue = (val.bytes[0] * 256 + val.bytes[1]) >> 2;
return intValue / 64.0;
What I find mind boggling is that I'm unable to find any note about these two codes fpe2 and sp78, beside in unofficial code examples for accessing temp and fan readings on a Mac.
Does anyone here know how would one ever figure this out on his own, about these codes?! And basically can someone point me out to some documentation about this and/or explain here what those data types are?
While there doesn't seem to be any "official" documentation of these type names, they are generic enough to figure out.
FP = Floating point, unsigned.
SP = floating point, signed.
The last two (hex) digits indicate the integer/fraction bits. The total tells us that the value fits into 16 bits.
So: FPE2 = floating point, unsigned, 14 (0xE) bits integer, 2 (0x2) bits fraction.
15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
I I I I I I I I I I I I I I F F
The SP values have the added complication of a sign bit.
15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
S I I I I I I I F F F F F F F F
To convert these values to integers, discard the F bits (by shifting) and cast to an integer type. Be careful with the sign bit on the SP values, whether or not the sign is preserved depends on the type you are shifting.

Convert unknown Hex digits to a Longitude and Latitude

F3 c8 42 14 - latitude //05.13637° should be nearby this coordinate
5d a4 40 b2 - longitude //100.47629° should be nearby this coordinate
this is the hex data i get from GPS device, how to convert to readable coordinate?
i don't have any manual document.please help.thanks
22 00 08 00 c3 80 00 20 00 dc f3 c8 42 14 5d a4 40 b2 74 5d 34 4e 52 30 39
47 30 35 31 36 34 00 00 00
this is my full bytes i received,but the engineer told me that F3 c8 42 14 is latitude and 5d a4 40 b2 is longitude
I worked with a Motorola GPS module once and the documentation said that the two hexes represented int types.
In your case, you might want to look at the documentation as well. If you know the model number, you can just google it.
Here is the documentation link for the motorola GPS I used.
Motorola GPS Module
I also took the liberty to do some calculations for you. If your lattitude was indeed
0x1442c8f3
(endianness does make a difference here). The integer equivalent is
339921139
in decimal system. If you divide that by 3600000 milliarcseconds
(where 1 deg = 60 min = 60 * 60 s = 60*60*1000 ms) you get
94.4225386
deg, which is close to your expectations. There isn't enough data to validate it but I believe most of the GPS modules return the milliarcseconds for both latitude and longitude.)
Assuming the hex codes represent unencrypted 32-bit floating point numbers (they might not do), you could try reading them into a C program and printing them out using printf("%f").
Don't forget that the words could have both endianness, i.e. the first one could be F3 C8 42 14 or 14 42 C8 F3 (bytes reversed).
Try it both ways and see if you get anything useful.
I wasn't able to get anything quickly from this online floating point calculator here.
Edit:
Building on Khanal's answer, this link to Latitude/Longitude suggests that the numbers are indeed fixed point and explains the sign convention.
Perhaps more useful for the calculations is HexIt, which allows choosing from a variety of C data types, both integer and floating point, as well as flipping back and forth between little and big endian representations.
I think the values are in 32-bit floating point. However, the bytes are slightly shifted in the stream that you show. Taking longitude first: 100.47629 in 32-bit floating point is 42C8F3DC these are bytes 10 through 13 in your stream (Least significant byte first).
For latitude 5.13637 in 32-bit floating point is 40A45D24 these are bytes 14 through 17 but it's 40A45D14 in the byte stream so it's off a little in the least significant decimal digit (Again, it's least significant byte first).

Resources