Unix shell bit select - shell

How can I calculate bit selection from shell?
Suppose I've got something like: i[m:l]
i is an integer, m is the MSB portion of the bit select and l is the LSB portion of the bit select, e.g.:
250[1:0] - would return the 2 LSB bits of "250", and answer will be "2"
250[7:2] - would return the 6 MSB bits of "250", and answer will be "62"

Not sure how portable this is, but Bash and KSH at least support bitwise operations (left & right shift, bitwise AND and OR), and exponentiation. So you can use those directly to do bitmasks.
#! /bin/sh
extract_bits() {
msb=$1 ; lsb=$2 ; num=$3
# Number of bits required
len=$(( $msb + 1 - $lsb ))
# Bitmask == 2^len - 1
mask=$(( 2 ** $len - 1 ))
# Left-shift mask, bitand, right-shift result
echo $(( ( num & ( $mask << $lsb ) ) >> $lsb ))
}
extract_bits 1 0 250
extract_bits 7 2 250
(As to whether it's a good idea to be doing this at all in a shell script, well, I'm not convinced.)

Related

How to generate a random decimal number from 0 to 3 with bash?

I want to generate a random decimal number from 0 to 3, the result should look like this:
0.2
1.5
2.9
The only command I know is:
echo "0.$(( ($RANDOM%500) + 500))"
but this always generates 0.xxx. How do I do that ?
Bash has no support for non-integers. The snippet you have just generates a random number between 500 and 999 and then prints it after "0." to make it look like a real number.
There are lots of ways to do something similar in bash (generating the integer and decimal parts separately). To ensure a maximally even distribution, I would just decide how many digits you want after the decimal and pick a random integer with the same precision, then print the digits out with the decimal in the right place. For example, if you just want one digit after the decimal in the half-open range [0,3), you can generate an integer between 0 and 30 and then print out the tens and ones separated by a period:
(( n = RANDOM % 30 ))
printf '%s.%s\n' $(( n / 10 )) $(( n % 10 ))
If you want two digits after the decimal, use % 300 in the RANDOM assignment and 100 in the two expressions on the printf. And so on.
Alternatively, see the answer below for a number of solutions using other tools that aren't bash builtins:
https://stackoverflow.com/a/50359816/2836621
$RANDOM gives random integers in the range 0..32767
Knowing this, you have many options. Here are two:
Using bc:
$ bc <<< "scale=3; 3 * $RANDOM / 32767"
2.681
Constructing a number with two $RANDOMs:
$ echo "$(( $RANDOM % 3 )).$(( $RANDOM % 999 ))"
0.921
I have limited the precision to 3 decimal digits. Increasing/decreasing it should be trivial.

Computation time of a bash script scales horribly

I have the following code that is addressing the Project Euler problem below:
2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder.
What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?
My script works fine, generates me 2520 as it should do for 1-10, I also have an answer for 1-17 of 12252240, it looks like so:
#!/bin/bash
for ((i=1; i<10000000000; i++))
do
if (( i%2 == 0 )) && (( i%3 == 0 )) && (( i%4 == 0 )) && (( i%5 == 0 )) &&
(( i%6 == 0 )) && (( i%7 == 0 )) && (( i%8 == 0 )) && (( i%9 == 0 )) &&
(( i%10 == 0 )) && (( i%11 == 0 )) && (( i%12 == 0 )) && (( i%13 == 0 )) &&
(( i%14 == 0 )) && (( i%15 == 0 )) && (( i%16 == 0 )) && (( i%17 == 0 )); then
# remaning terms to factor && (( i%18 == 0 )) && (( i%19 == 0 )) && (( i%20 == 0 )); then
int=$i
fi
if [[ $int ]]; then
echo "Lowest integer = '$int'"
break
else
continue
fi
done
However, the jump from factoring around 12 terms (about 3/4th of a second real time), to factoring 17 (6 mins real time), in computational time is huge.
I've yet to let the full 20 factors run, but all Project Euler problems are supposed to be solvable in a few minutes on medium power home computers.
So my question is 2 fold: 1) Am I on the right track in terms of how I approached programming this, and 2) how else could/should I have done it to make it as efficient as possible?
Without abandoning the brute-force approach, running the inner loop in reverse order roughly halves the running time.
for ((i=1; i<100000000; ++i)); do
for ((j=17; j>1; --j)); do
(( i%j != 0 )) && break
done
((j==1)) && echo "$i" && break
done
Informally speaking, almost no numbers are divisible by 17, and out of those, almost no numbers are divisible by 16. Thus, running the inner loop in reverse order removes 16 iterations of the inner loop for most numbers, and 15 for most of the rest.
Additional optimizations are obvious; for example, the inner loop could end at 4, because 2, 3, and 4 are already covered by their respective squares (all numbers which are divisible by 9 are also divisible by 3, etc). However, that's small potatoes compared to the main optimization.
(You did not have an explicit inner loop, and in fact, unrolling the loop like you did probably achieves a small performance gain. I rolled it into an explicit loop mainly out of laziness as well as for aesthetic reasons.)
So my question is 2 fold:
1) Am I on the right track in terms of how I approached programming this, and
I'm afraid you're not. You're using the wrong tools, namely a shell scripting language, to solve mathematical problems, and wonder why that doesn't perform well. "being solvable in a couple of minutes on a home computer" doesn't mean it's supposed to be like that, no matter how unusual your choice of tool is.
2) how else could/should I have done it to make it as efficient as possible?
Don't use bash's arithmetics. Bash is a shell, which means it's an interpreter to its core. Which means that it'll spend very little time calculating, and very much time understanding what it should do. To illustrate: Your complicated formula first has to be parsed into a tree that tells bash in which order to execute things, then these things have to be identified, then bash needs to work through that tree and save all the results for the next level of the tree. The few arithmetic instructions that it does cost next to no computational time.
Have a look at numpy, which is a python module for mathematics; it does things faster. If you're not afraid to compile your stuff, look at C++ or C, both for which very very fast math libraries exist.
Arithmetic conditions support logical operators. The speed gain is not huge, but there's some:
if (( i % 2 == 0 && i % 3 == 0 && ... ))
Also note, that testing i % 10 == 0 when you already know that i % 2 == 0 and i % 5 == 0 is not needed.
There's a much faster way how to get the number without iterating over all the numbers.
The answer is not a faster programming language. The answer is a more clever algorithm.
You know your end answer has to be divisible by all of the numbers, so start with your largest number and only check multiples of it. Find the smallest number that is a multiple of your two biggest numbers, and then check only multiples of that for the next number.
Let's look at how this works for 1 to 10:
10 // not divisible by 9, keep adding 10's until divisible by 9
20
30
40
50
60
70
80
90 // divisible by 9, move on to 8, not divisible by 8, keep adding 90's
180
270
360 // divisible by 8, not divisible by 7, keep adding 360's
720
1080
1440
1800
2160
2520 // divisible by 7, 6, 5, 4, 3, 2, 1 so you're done!
So in only 17 steps, you have your answer.
This algorithm implemented in Ruby (not known for its speed) found the answer for 1-5000 in 4.5 seconds on a moderately fast laptop.

How to find largest power of 2 a number is divisible by using logic functions?

How do you find the largest power of 2 a number is divisible by using logic function
for example 144 is divisible by 16 which is 2^4.
How would one do this.
I know 144 in binary is 1001 0000 and I have to use a bitwise function.
But what would I use (and or andn orn ?) or perhaps something else and what can I use as my mask?
I know you have to look at the right most number to tell if it is divisible by 2.
Any help is appreciated
I would go with n & -n or with n & (~n + 1), in case you are worried about running across one's complement arithmetic, given the latter works with both arithmetics.
E.g.,
> 144 & (~144 + 1)
< 16
Now a short explanation.
The bitwise NOT (i.e., ~ operator) of a number n gives -(n + 1). It inverts all the bits of n. The number 2 is represented by 00000010 while its negation is 11111101 which equals to -3 (i.e., , see the two's complement representation of signed numbers).
Do not to confuse it with logical negation.
E.g., ~144 = -(144 + 1) = -145.
The bitwise AND (i.e., & operator) compares two bits of the inputs and generates a result of 1 if both are 1, otherwise it returns 0.
Now the main topic.
This is an old tricks that gives the highest power of 2 that n is divisible by. This means that it returns a number with a single one bit, specifically the bottom bit that was set in n.
For example the binary representation of 144 is 010010000. Its bottom 1 bit is the bit in fourth position (counting backward from right and starting at position 0). Thus the higher power of 2 that divides 144 is 16 (i.e., 00010000).
144 & (~144 + 1) = 144 & -144 = 16
16 & ( ~16 + 1) = 16 & - 16 = 16
10 & ( ~10 + 1) = 10 & - 10 = 2
12 & ( ~12 + 1) = 12 & - 12 = 4
11 & ( ~11 + 1) = 11 & - 11 = 1
3 & ( ~ 3 + 1) = 3 & - 3 = 1
Note that if n is not divisible by any power of 2 it returns 1.
Why it works?
The negative of n is produced by inverting its bits via ~, then adding 1 (again, see two's complement definition). This sum causes every 1 bit (starting from the bottom) to overflow until a 0 bit is encountered (let us call it the bit x). Here the overflow process stops, leaving remaining bits (those beyond the current x bit) unchanged. Thus performing & between n and its inverse will result in a binary string containing only the x bit.
An example follows.
010010000 | +144 ~
----------|-------
101101111 | -145 +
1 |
----------|-------
101110000 | -144
101110000 | -144 &
010010000 | +144
----------|-------
000010000 | 16

Convert int to binary, the perform bitwise operations on it

I'm trying to convert an int to binary, and then perform bitwise operations on the binary.
My current method is to take the int, call to_s(2) on it, but then I'm left with a binary string.
Any advice on what I should do?
Simple integers are stored as binary in nearly every major programming language (including Ruby). So, you can do your bitwise operations on the integers themselves:
>> 6 | 5 # bitwise or
=> 7
>> 6 & 5 # bitwise and
=> 4
>> 6 ^ 5 # bitwise xor
=> 3
>> 6 >> 2 # right shift
=> 1
>> 6 << 2 # left shift
=> 24
(Edit: this appears to be my 1000th answer.)
the_number.to_s(2).split('').map { |x| x.to_i } # convert the number to binary array

extract bit in Ruby Integers

I need to get the n-th bit of an Integer, either signed or unsigned, in Ruby.
x = 123 # that is 1111011
n = 2 # bit 2 is ...0
The following piece of code doesn't work in the general case:
x.to_s(2)[-(n+1)] #0 good! but...
because of negative numbers not represented as 2-complement:
-123.to_s(2) # "-1111011"
So how to proceed?
x = 123 # that is 1111011
n = 2 # bit 2 is ...0
x[n] # => 0
-123[2] # => 1
def f x, bit
(x & 1 << bit) > 0 ? 1 : 0
end
You could try the Bindata lib.
There is a function to represent an integer's binary representation as a string, and after that, you can do what you like with it.

Resources