4-variable mapping into an array - c

I need to choose an aray item based on the values of 4 variables, as shown below, in C.
0 | 1 | 0 | -1 | array[1][0]
-1 | 0 | 1 | 0 | array[1][1]
0 | -1 | 0 | 1 | array[1][2]
1 | 0 | -1 | 0 | array[1][3]
1 | 0 | 0 | -1 | array[2][0]
1 | 0 | 0 | 1 | array[2][1]
-1 | 0 | 0 | 1 | array[2][2]
-1 | 0 | 0 | -1 | array[2][3]
0 | 1 | -1 | 0 | array[3][0]
0 | 1 | 1 | 0 | array[3][1]
0 | -1 | 1 | 0 | array[3][2]
0 | -1 | -1 | 0 | array[3][3]
(The order of the second column in the array isn't important and can be reordered if needed.)
While it's possible (and completely acceptable) to just stick all the possibilities in 12 chained ifs, I'd like to see if anyone can come up with a "cleaner" solution.
EDIT: to clarify: I want a function f(a,b,c,d) where (for example) f(0, 1, 0, -1) returns the value held in array[1][0].

I've described this solution in a way which is slightly less efficient than it could be to make it easier to explain; the more concise version is easily derived from what I have shown here.
Map the values -1, 0, and 1 to 0x00, 0x01, and 0x02, and store them, using 2 bits per value, in an 8-bit value so e.g. your array values correspond to the following numbers:
array[1][0]: binary value 01100100 = 0x64
array[1][1]: binary value 00011001 = 0x19
array[1][2]: binary value 01000110 = 0x46
array[1][3]: binary value 10010001 = 0x91
Create an array for all 255 possible values which can be held in an 8-bit value (note that some entries won't be used, i.e. any with both bits set to 1 - this is the inefficiency I mentioned).
So e.g.
array[0] points to the appropriate array for -1, -1, -1, -1
array[1] points to the appropriate array for -1, -1, -1, 0
array[2] points to the appropriate array for -1, -1, -1, 1
array[3] points nowhere
array[4] points to the appropriate array for -1, -1, 0, -1
array[5] points to the appropriate array for -1, -1, 0, 0
array[6] points to the appropriate array for -1, -1, 0, 1
array[7] points nowhere
(etc, obviously)
And then all you need is a single lookup, with no loop, to get the right array (or whatever you are keying to).
In the more concise solution, the table has no entries pointing to nowhere.
EDIT:
In this case, with array as above, the desired function is:
f(a,b,c,d) {
return array[(a+1) << 6 + (b+1) << 4 + (c+1) << 2 + (d+1)];
}

Revise your way of thinking and recognise that an array IS a function, from a set of indices to a set of values. Looked at this way, you would want to define your array like this:
array[0][1][0][-1] = value currently in array[1][0]
array[-1][0][1][0] = value currently in array[1][1]
etc
Now, it's unfortunate that C can't directly index arrays with arbitrary ranges of integers, but you could get round this in one of two ways:
defining constants such as one=1,zero=0,minusone=2 and use those in your array expressions;
use an offset such as adding 1 to every index and subtracting it when you make a reference to the array, eg array[1-1][2-1][1-1][0-1].
Of these two the former is probably preferable.
Finally, this array will have entries for values not in your table, you'll have to put some sort of null code into them.

Put the table you posted in array and search in it with a loop for the correct entry. This way you will code data as data and not as code.
Any cleverer method will generate undue maintenance work once your mapping specification changes. Unless the performance of the loop is proven to be unsufficient I would use the loop.

In addition to approaches suggested by #James McLeod and #High Performance Mark you could use the auto-generated switch statement:
f(a,b,c,d) {
switch(ind(a,b,c,d)) {
# include "cases.h"
default: assert(0);
};
}
Where ind():
enum { BASE = 3 };
int ind(int a, int b, int c, int d) {
// ind() should produce the same result as the one from the script (see below)
return (BASE*(BASE*(BASE*(a+1) + b+1) + c+1) + d+1);
}
And cases.h:
case 48: return array[1][0];
case 16: return array[1][1];
case 32: return array[1][2];
case 64: return array[1][3];
case 66: return array[2][0];
case 68: return array[2][1];
case 14: return array[2][2];
case 12: return array[2][3];
case 46: return array[3][0];
case 52: return array[3][1];
case 34: return array[3][2];
case 28: return array[3][3];
cases.h could be generated by the following script:
#!/usr/bin/env python
import csv, fileinput
# parse stdin or file(s) given at command-line as csv-file
rows = ((map(int, row[:-1]), row[-1])
for row in csv.reader(fileinput.input(), delimiter='|') if row)
# function that arranges indexes in C-order
# . any function that produces unique integers will do
# . -1 <= n <= 1
ind = lambda args, base=3: reduce(lambda acc, n: base*acc + (n+1), args, 0)
# print cases for switch(ind(a,b,c,d)) statement
print '\n'.join("case %d: return %s;" % (ind(indexes), value)
for indexes, value in rows if value)
The script accepts as an input the table from your question.

Related

Find product of integers at interval of X and update value at position 'i' in an array for N queries

I have given an array of integers of length up to 10^5 & I want to do following operation on array.
1-> Update value of array at any position i . (1 <= i <= n)
2-> Get products of number at indexes 0, X, 2X, 3X, 4X.... (J * X <= n)
Number of operation will be up to 10^5.
Is there any log n approach to answer query and update values.
(Original thought is to use Segment Tree but I think that it is not needed...)
Let N = 10^5, A:= original array of size N
We use 0-based notation when we saying indexing below
Make a new array B of integers which of length up to M = NlgN :
First integer is equal to A[0];
Next N integers is of index 1,2,3...N of A; I call it group 1
Next N/2 integers is of index 2,4,6....; I call it group 2
Next N/3 integers 3,6,9.... I call it group 3
Here is an example of visualized B:
B = [A[0] | A[1], A[2], A[3], A[4] | A[2], A[4] | A[3] | A[4]]
I think the original thoughts can be used without even using Segment Tree..
(It is overkill when you think for operation 2, we always will query specific range on B instead of any range, i.e. we do not need that much flexibility and complexity to maintain the data structure)
You can create the new array B described above, also create another array C of length M, C[i] := products of Group i
For operation 1 simply use O(# factors of i) to see which Group(s) you need to update, and update the values in both B and C (i.e. C[x]/old B[y] *new B[y])
For operation 2 just output corresponding C[i]
Not sure if I was wrong but this should be even faster and should pass the judge, if the original idea is correct but got TLE
As OP has added a new condition: for operation 2, we need to multiply A[0] as well, so we can special handle it. Here is my thought:
Just declare a new variable z = A[0], for operation 1, if it is updating index 0, update this variable; for operation 2, query using the same method above, and multiply by z afterwards.
I have updated my answer so now I simply use the first element of B to represent A[0]
Example
A = {1,4,6,2,8,7}
B = {1 | 4,6,2,8,7 | 6,8 | 2 | 8 | 7 } // O(N lg N)
C = {1 | 2688 | 48 | 2 | 8 | 7 } // O (Nlg N)
factorization for all possible index X (X is the index, so <= N) // O(N*sqrt(N))
opeartion 1:
update A[4] to 5: factors = 1,2,4 // Number of factors of index, ~ O(sqrt(N))
which means update Group 1,2,4 i.e. the corresponding elements in B & C
to locate the corresponding elements in B & C maybe a bit tricky,
but that should not increase the complexity
B = {1 | 4,6,2,5,7 | 6,5 | 2 | 5 | 7 } // O(sqrt(N))
C = {1 | 2688 | 48/8*5 | 2 | 8/8*5 | 7 } // O(sqrt(N))
update A[0] to 2:
B = {2 | 4,6,2,5,7 | 6,5 | 2 | 5 | 7 } // O(1)
C = {2 | 2688/8*5 | 48/8*5 | 2 | 8/8*5 | 7 } // O(1)
// Now A is actually {2,4,6,2,5,7}
operation 2:
X = 3
C[3] * C[0] = 2*2 = 4 // O(1)
X = 2
C[2] * C[0] = 30*2 = 60 // O(1)

what is the function of $value & 15

I have been going over a perl book i have recently purchased, and while reading I noticed a block of code that confused me..
use integer;
$value = 257;
while($value){
unshift #digits, (0..9,a..f)[$value & 15];
$value /= 16;
}
print digits;
the book mentions the purpose was to reverse the order of digits. however, new to perl I am having trouble figuring out what [$value & 15] is doing.
It's a bitwise and operation.
What it's doing is performing a bitwise and using the value of 15 and whatever value is contained in $value.
The resulting value is the decimal value that corresponds to the result of a bitwise and with the lower 4 bits of the value.
Ex:
$value = 21
which has a binary representation of: 0b10101
Performing a bitwise and with 15 means that any bits in $value will be zeroed if they are either outside the lower 4 bit range, or contain no 1's in the lower 4 bits.
The result is:
0b10101
&
0b 1111
-------
0b00101 = 5
Looking up the truth tables for performing bitwise operations will help with stuff like this in the future, but when performing an AND with any value, the result is only true, when both bits are 1, 0 otherwise.
V1 | V2 | V1 & V2
-----------------
0 | 0 | 0
0 | 1 | 0
1 | 0 | 0
1 | 1 | 1

C Programming - XOR Bitwise Operation

What operation does the following ā€˜Cā€™ statement perform?
star = star ^ 0b00100100;
(A) Toggles bits 2 and 5 of the variable star.
(B) Clears all bits except bits 2 and 5 of the variable star.
(C) Sets all bits except bits 2 and 5 of the variable star.
(D) Multiplies value in the variable star with 0b00100100.
I'm still clueless about this. Can someone help me out?
XOR operator (also called "logical addition") is defined like this:
a b a^b
-----------
0 0 0
0 1 1
1 0 1
1 1 0
So a^0 leaves a intact while a^1 toggles it.
For multiple-bit values, the operation is performed bitwise, i.e. between corresponding bits of the operands.
If you know how XOR works, and you know that ^ is XOR in C, then this should be pretty simple. You should know that XOR will flip bits where 1 is set, bits 2 and 5 of 0b00100100 are set, therefore it will flip those bits.
From an "during the test" standpoint, let's say you need to prove this to yourself, you really don't need to know the initial value of star to answer the question, If you know how ^ works then just throw anything in there:
00100100
^10101010 (star's made up value)
---------
10001110 (star's new value)
bit position: | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
|---|---|---|---|---|---|---|---
star's new v: | 1 | 0 | 0 | 0 | 1 | 1 | 1 | 0
|---|---|---|---|---|---|---|---
star's old v: | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0
Then check your answers again, did it:
(A) Toggles bits 2 and 5 of the variable star. (Yes)
(B) Clears all bits except bits 2 and 5 of the variable star. (Nope)
(C) Sets all bits except bits 2 and 5 of the variable star. (Nope)
(D) Multiplies value in the variable star with 0b00100100. (36x170 = 142? Nope)
It is (A) toggles bits 2 and 5.
The following is the truth table for the XOR operation:
x y x^y
0 0 0
1 0 1
0 1 1
1 1 0
You can see from the table that x XOR 0 = x and x XOR 1 = !x.
XOR is a bitwise operation, so it operates on individual bits. Therefore if you XOR star with some constant, it will toggle the 1 bits in the constant.
You can find some explanation e.g. here.
The exclusive OR has this truth table:
A B A^B
-----------
1 1 0
1 0 1
0 1 1
0 0 0
We can see that if B is true (1) then A is flipped (toggled), and if it's false (0) A is left alone. So the answer is (A).
XOR operator returns 0 if both inputs are same otherwise returns 1 if both inputs are different.For Example the Given Truth Table :-
a=1 b=1 => a^b=0,
a=0 b=0 => a^b=0,
a=0 b=1 => a^b=1,
a=1 b=0 => a^b=1.
well xor is binary operator that work on bits of 2 nos.
rule of xoring:for same bit ans is 0 and for different bit ans is 1
let
a= 1 0 1 0 1 1
b= 0 1 1 0 1 0
--------------
c= 1 1 0 0 0 1
--------------
compare bit of a and b bit by bit
if same put 0 else put 1
xor is basically used to find the unique in given set of duplicate no.
just xor all nos. and u will get the unique one(if only single unique is present)

how does it works "$_ & 1" in perl

I am perl beginner, I am reading upon grep function to filter a list. I came across the following program.
#!/usr/bin/perl
use strict;
use warnings;
# initialize an array
my #array = qw(3 4 5 6 7 8 9);
# first syntax form:
my #subArray = grep { $_ & 1 } #array;
the statement my #subArray = grep { $_ & 1 } #array; returns odd-numbers in #array. I didn't understand how the expression($_ & 1) works. I searched in Google but did not found any useful links.
Is that any kind of special operator ?
Are there any other variants of that EXPR ?
Thanks in Advance.
$_ is the variable holding the currently tested value, & is the binary AND operator, and 1 is just the number one. This expression combines all the bits of both $_ and 1 with each other by logical AND. So it returns 1 if the value is odd and 0 if the value is even.
As an example, lets assume $_ is 123 then it's binary representation would be 1111011. The decimal number 1 would be 00000001, so combining all bits by AND you get
123 = 1111011
1 = 0000001
- AND -
0000001 = 1
Another example 200 & 100
200 = 11001000
100 = 01100100
- AND --
01000000 = 64
As many have pointed out, & is the bitwise-and operator. This means that the two numbers that are compared are turned into bits and compared:
For example, 3 & 1 returns 1, which evaluates to true inside the grep:
Num | Bits
----+-----
3 | 1 1
& 1 | 0 1
----+-----
1 | 0 1 <- result of 'and'ing each bit column
Similarly, 4 & 1 returns 0, which is false:
Num | Bits
----+-------
4 | 1 0 0
& 1 | 0 0 1
----+-------
0 | 0 0 0 <- all zeros because no column contains 1 & 1
That said, An alternative way to filter odd numbers is to mod the number with 2:
my #odd = grep { $_ % 2 } 1 .. 7; # 1, 3, 5, 7
grep{ $_ & 1}
Will go over every element of your array and do a bit-wise match with 1
This means that grep will match any element that has a 1 as last (lsb) bit.
Since only odd numbers have a 1 as lsb this will only return odd numbers
& is the bitwise AND
$_ is the current expression. In this case each array element.
& is the binary AND operator.
So, in short, the grep will match any array element that is an odd number.
The use of $_ with grep is documented in the perldoc.
The meaning of & is also in the perldoc.
$_ is a variable set by the grep function. Most of the perl functions manipulate $_ if not specified otherwise. Grep calls the defined anonymous sub (which is { $_ & 1 }) for each elements of #array and makes a bitwise &. If the result is a true value, then it is added to the resulting array.

ANSI C + Numerical Linear Algebra - Using a linear solver to find an eigenvector given an eigenvalue (issue)

I have written a linear solver employing Householder reflections/transformations in ANSI C which solves Ax=b given A and b. I want to use it to find the eigenvector associated with an eigenvalue, like this:
(A-lambda*I)x = 0
The problem is that the 0 vector is always the solution that I get (before someone says it, yes I have the correct eigenvalue with 100% certainty).
Here's an example which pretty accurately illustrates the issue:
Given A-lambda*I (example just happens to be Hermitian):
1 2 0 | 0
2 1 4 | 0
0 4 1 | 0
Householder reflections/transformation will yield something like this
# # # | 0
0 # # | 0
0 0 # | 0
Back substitution will find that solution is {0,0,0}, obviously.
It's been a while since I've written an eigensolver, but I seem to recall that the trick was to refactor it from (A - lambda*I) * x = 0 to A*x = lambda*x. Then your Householder or Givens steps will give you something like:
# # # | #
0 # # | #
0 0 1 | 1
...from which you can back substitute without reaching the degenerate 0 vector. Usually you'll want to deliver x in normalized form as well.
My memory is quite rusty here, so I'd recommend checking Golub & Van Loan for the definitive answer. There are quite a few tricks involved in getting this to work robustly, particularly for the non-symmetric case.
This is basically the same answer as #Drew, but explained a bit differently.
If A is the matrix
1 2 0
2 1 4
0 4 1
then the eigenvalues are lambda = 1, 1+sqrt(20), 1-sqrt(20). Let us take for simplicity lambda = 1. Then the augmented matrix for the system (A - lambda*I) * x = 0 is
0 2 0 | 0
2 0 4 | 0
0 4 0 | 0
Now you do the Householder / Givens to reduce it to upper triangular form. As you say, you get something of the form
# # # | 0
0 # # | 0
0 0 # | 0
However, the last # should be zero (or almost zero). Exactly what you get depends on the details of the transformations you do, but if I do it by hand I get
2 0 4 | 0
0 2 0 | 0
0 0 0 | 0
Now you do backsubstitution. In the first step, you solve the equation in the last row. However, this equation does not yield any information, so you can set x[2] (the last element of the vector x) to any value you want. If you set it to zero and continue the back-substitution with that value, you get the zero vector. If you set it to one (or any nonzero value), you get a nonzero vector. The idea behind Drew's answer is to replace the last row with 0 0 1 | 1 which sets x[2] to 1.
Round-off error means that the last #, which should be zero, is probably not quite zero but some small value like 1e-16. This can be ignored: just take it as zero and set x[2] to one.
Obligatory warning: I assume you are implementing this for fun or educational purposes. If you need to find eigenvectors in serious code, you are better off using code written by others as this stuff is tricky to get right.

Resources