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

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.

Related

Why must I use the ~ operator when clearing a bit? [duplicate]

This question already has answers here:
How do I set, clear, and toggle a single bit?
(27 answers)
Closed 5 years ago.
For example, if I want to set a bit in y at position n (in C)
y = y | (1 << n)
But if I want to delete a bit in y at position n I have to use the ~ operator after binary AND.
y = y & ~(1 << n);
My question: Why Must I use the ~ operator?
Is this because the result turns into negative area?
If you want to set a bit at third place from the right :
Y : 01001000
1 << 2 : 00000100
Y | (1 << 2) : 01001100 The | is OR, bits are set to 1 if any is 1.
If you want to remove the bit :
1 << 2 : 00000100
~(1 << 2) : 11111011 The ~ is NOT, bits are inversed
Y : 01001100
Y & ~(1 << 2) : 01001000 The & is AND, bits are set to 1 if both are 1.
I suggest you read more about Bitwise operators
No, ~ has nothing to do with interpreting the number as negative: tilde ~ operator interprets the number as a pattern of bits, which it then inverts (i.e. replaces zeros with ones and ones with zeros). In fact, if you apply ~ to an unsigned value, the result would remain positive.
Recall that 1 << k expression produces a pattern of all zeros and a single 1 at the position designated by k. This is a bit mask that can be used to force bit at position k to 1 by applying OR operation.
Now consider what happens when you apply ~ to it: all 0s would become 1s, and the only 1 would become zero. Hence, the result is a bit mask suitable for forcing a single bit to zero by applying AND operation.
The ~ operator turns all of the 0's to 1's and all of the 1's to 0's. In order to clear the bint in position n you want to and it will all ones and a zero in the nth position so shift a one to the nth position and ~ invert all the bits.
1 << n for n==3 (just an example) gives you a pattern 0000000...0001000. ~ negates the bit
pattern to 11111111....11110111. Using the bitwise AND operator (&) will
only set the required bit to 0, all other remain with the same value. It's using
the fact that for a bit b: b & 1 == b.
~ flips all bits, it has nothing to do with negative numbers.
A graphical representation for a sequence of k-bits
pos k-1 k-2 0
+---+---+-------------------+---+---+
1: | 0 | 0 | ··· | 0 | 1 |
+---+---+-------------------+---+---+
pos k-1 k-2 n n-1 0
+---+---+-----+---+---+---+-----+---+
1<<n | 0 | 0 | ··· | 1 | 0 | 0 | ··· | 0 |
+---+---+-----+---+---+---+-----+---+
pos k-1 k-2 n n-1 0
+---+---+-----+---+---+---+-----+---+
~(1<<n) | 1 | 1 | ··· | 0 | 1 | 1 | ··· | 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

How can I find the sum of the elements of an array in Bash?

I am trying to add the elements of an array that is defined by user input from the read -a command. How can I do that?
read -a array
tot=0
for i in ${array[#]}; do
let tot+=$i
done
echo "Total: $tot"
Given an array (of integers), here's a funny way to add its elements (in bash):
sum=$(IFS=+; echo "$((${array[*]}))")
echo "Sum=$sum"
e.g.,
$ array=( 1337 -13 -666 -208 -408 )
$ sum=$(IFS=+; echo "$((${array[*]}))")
$ echo "$sum"
42
Pro: No loop, no subshell!
Con: Only works with integers
Edit (2012/12/26).
As this post got bumped up, I wanted to share with you another funny way, using dc, which is then not restricted to just integers:
$ dc <<< '[+]sa[z2!>az2!>b]sb1 2 3 4 5 6 6 5 4 3 2 1lbxp'
42
This wonderful line adds all the numbers. Neat, eh?
If your numbers are in an array array:
$ array=( 1 2 3 4 5 6 6 5 4 3 2 1 )
$ dc <<< '[+]sa[z2!>az2!>b]sb'"${array[*]}lbxp"
42
In fact there's a catch with negative numbers. The number '-42' should be given to dc as _42, so:
$ array=( -1.75 -2.75 -3.75 -4.75 -5.75 -6.75 -7.75 -8.75 )
$ dc <<< '[+]sa[z2!>az2!>b]sb'"${array[*]//-/_}lbxp"
-42.00
will do.
Pro: Works with floating points.
Con: Uses an external process (but there's no choice if you want to do non-integer arithmetic — but dc is probably the lightest for this task).
My code (which I actually utilize) is inspired by answer of gniourf_gniourf. I personally consider this more clear to read/comprehend, and to modify. Accepts also floating points, not just integers.
Sum values in array:
arr=( 1 2 3 4 5 6 7 8 9 10 )
IFS='+' sum=$(echo "scale=1;${arr[*]}"|bc)
echo $sum # 55
With small change, you can get the average of values:
arr=( 1 2 3 4 5 6 7 8 9 10 )
IFS='+' avg=$(echo "scale=1;(${arr[*]})/${#arr[#]}"|bc)
echo $avg # 5.5
gniourf_gniourf's answer is excellent since it doesn't require a loop or bc. For anyone interested in a real-world example, here's a function that totals all of the CPU cores reading from /proc/cpuinfo without messing with IFS:
# Insert each processor core count integer into array
cpuarray=($(grep cores /proc/cpuinfo | awk '{print $4}'))
# Read from the array and replace the delimiter with "+"
# also insert 0 on the end of the array so the syntax is correct and not ending on a "+"
read <<< "${cpuarray[#]/%/+}0"
# Add the integers together and assign output to $corecount variable
corecount="$((REPLY))"
# Echo total core count
echo "Total cores: $corecount"
I also found the arithmetic expansion works properly when calling the array from inside the double parentheses, removing the need for the read command:
cpuarray=($(grep cores /proc/cpuinfo | awk '{print $4}'))
corecount="$((${cpuarray[#]/%/+}0))"
echo "Total cores: $corecount"
Generic:
array=( 1 2 3 4 5 )
sum="$((${array[#]/%/+}0))"
echo "Total: $sum"
I'm a fan of brevity, so this is what I tend to use:
IFS="+";bc<<<"${array[*]}"
It essentially just lists the data of the array and passes it into BC which evaluates it. The "IFS" is the internal field separate, it essentially specifies how to separate arrays, and we said to separate them with plus signs, that means when we pass it into BC, it receives a list of numbers separated by plus signs, so naturally it adds them together.
Another dc & bash method:
arr=(1 3.88 7.1 -1)
dc -e "0 ${arr[*]/-/_} ${arr[*]/*/+} p"
Output:
10.98
The above runs the expression 0 1 3.88 7.1 _1 + + + + p with dc. Note the dummy value 0 because there's one too many +s, and also note the usual negative number prefix - must be changed to _ in dc.
arr=(1 2 3) //or use `read` to fill the array
echo Sum of array elements: $(( ${arr[#]/%/ +} 0))
Sum of array elements: 6
Explanation:
"${arr[#]/%/ +}" will return 1 + 2 + 3 +
By adding additional zero at the end we will get 1 + 2 + 3 + 0
By wrapping this string with BASH's math operation like this$(( "${arr[#]/%/ +} 0")), it will return the sum instead
This could be used for other math operations.
For subtracting just use - instead
For multiplication use * and 1 instead of 0
Can be used with logic operators too.
BOOL AND EXAMPLE - check if all items are true (1)
arr=(1 0 1)
if [[ $((${arr[#]/%/ &} 1)) -eq 1 ]]; then echo "yes"; else echo "no"; fi
This will print: no
BOOL OR EXAMPLE - check if any item is true (1)
arr=(1 0 0)
if [[ $((${arr[#]/%/ |} 0)) -eq 1 ]]; then echo "yes"; else echo "no"; fi
This will print: yes
A simple way
function arraySum
{
sum=0
for i in ${a[#]};
do
sum=`expr $sum + $i`
done
echo $sum
}
a=(7 2 3 9)
echo -n "Sum is = "
arraySum ${a[#]}
I find this very simple using an increasing variable:
result2=0
for i in ${lineCoffset[#]};
do
result2=$((result2+i))
done
echo $result2

Logic Proof of Associative Property for XOR

I came across a common programming interview problem: given a list of unsigned integers, find the one integer which occurs an odd number of times in the list. For example, if given the list:
{2,3,5,2,5,5,3}
the solution would be the integer 5 since it occurs 3 times in the list while the other integers occur even number of times.
My original solution involved setting up a sorted array, then iterating through the array: For each odd element I would add the integer, while for each even element I would subtract; the end sum was the solution as the other integers would cancel out.
However, I discovered that a more efficient solution existed by simply performing an XOR on each element -- you don't even need a sorted array! That is to say:
2^3^5^2^5^5^3 = 5
I recall from a Discrete Structures class I took that the Associate Property is applicable to the XOR operation, and that's why this solution works:
a^a = 0
and:
a^a^a = a
Though I remember that the Associative Property works for XOR, I'm having trouble finding a logical proof for this property specific to XOR (most logic proofs on the Internet seem more focused on the AND and OR operations). Does anyone know why the Associative Property applies to the XOR operation?
I suspect it involves an XOR identity containing AND and/or OR.
The associative property says that (a^b)^c = a^(b^c). Since XOR is bitwise (the bits in the numbers are treated in parallel), we merely need to consider XOR for a single bit. Then the proof can be done by examining all possibilities:
abc (a^b) (a^b)^c (b^c) a^(b^c)
000 0 0 0 0
001 0 1 1 1
010 1 1 1 1
011 1 0 0 0
100 1 1 0 1
101 1 0 1 0
110 0 0 1 0
111 0 1 0 1
Since the third column, (a^b)^c, is identical to the fifth column, a^(b^c), the associative property holds.
As long as a ^ b == ~a & b | a & ~b, you can proove that :
(a ^ b) ^ c = ~((~a & b) | (a & ~b)) & c | ((~a & b) | (a & ~b)) & ~c
and
a ^ (b ^ c) = a & ~((~b & c) | (b & ~c)) | ~a & ((~b & c) | (b & ~c))
Are equals.

4-variable mapping into an array

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.

Resources