How does the formula x & (x - 1) works? - math

From Hacker's Delight: 2nd Edition:
The formula here seems a little bit awkward here. How is some x vector is subtracted from 1 vector (presumbly 0x1111 1111) when x is smaller than 1? (Like: (as given in example) 0x0101 1000 - 0x0000 0000 doesn't make any sense to me) The former is a smaller number than the first one and the words aren't storing signed vectors either. Is that something related to RISC specific here or what?
As specified in the notation section of the book. A bold letter corresponds a vector for word like x = 00000000. And a bold one differs from a light face 1. As bold 1 = 11111111 which is an 8 bit word.
Edit2: Special Thanks to Paul Hankin to figure out the unconventional notations used here. A bold faced one refers to 32 bit size word which is [00000001] and a light faced 1 refers to a number one as in C.

Subtracting 1
Since we're more familiar with decimal than with binary, it sometimes helps to look at what happens in decimal.
What happens when subtracting 1 in decimal? Take for example 1786000 - 1 = 1785999.
If you subtract 1 from a positive number x in decimal:
all the zeroes at the right of x become 9;
the rightmost nonzero digit of x becomes 1 less;
other digits are unaffected.
Now, in binary, it works exactly the same, except we only have 0 1 instead of 0 123456789.
If you subtract 1 from a number x in binary:
all the zeroes at the right of x become 1;
the rightmost nonzero bit of x becomes 0;
other bits are unaffected.
What about negative numbers? Happily, representation using 2's complement is such that negative numbers behave exactly like positive numbers. In fact, when looking at the bits of x, you can subtract 1 from x without needing to know whether x is a signed int or an unsigned int.
x & (x-1)
Let's start with an example: x = 01011000. We can subtract 1 the way I just explained:
x = 01011000
x-1 = 01010111
Now what's the result of the bitwise-and operation x & (x-1)? We take the two bits in each column; if they are both 1, we write 1; if at least one of them is 0, we write 0.
x = 01011000
x-1 = 01010111
x&(x-1) = 01010000
What happened?
all the zeroes at the right of x remain zero;
the rightmost 1 of x becomes a 0 because of x-1;
all other bits are unaffected, because they are the same in x and x-1.
Conclusion: we have zeroed the rightmost 1 of x, and left all other bits unaffected.

Let's take a look at an what x-1 does.
Assume x is a value '???? 1000 (? are 0 or 1)
=> x-1 = ???? 0111
=> x & (x-1) = ???? 0000
It's very similar no matter where the right most 1 is placed within x.
Requested example:
x=00001111
=> x-1=00001110
=> x & (x-1) = 00001110
P.s. x-1 = 00001110 - 00000001 (<=> 00001110 + 11111111)

Related

Convert a vector(x,y,z) coordinate into an integer between 0 and 32767

Pretty simple question - can someone provide a formula that takes 3 numbers (x,y,z) and converts them into a single integer between 0 and 32767.
1,1,2 and 2,1,1 shouldn't be the same resulting value (simply adding the numbers up isn't what I want) but compressing an infinite number of x,y,z into a small range of numbers obviously will get the same values back quite often.
The formula also needs to work on large numbers like 5000,5000,1000
If you need to go between 0 and 131068 that would be fine, but it shouldn't be much more than that.
One solution I can think of is to take each x,y,z and assign them each to a range of 5 bits in the 2^15 possible values in [0, 32767]. One way of doing this is taking each x,y,z modulo 2^5 (to compress them into the requisite 5 bits) and then set the bits of the result accordingly. The end result should look something like
def compress(x,y,z):
x %= 32
y %= 32
z %= 32
return x + (y<<5) + (z<<10)
print (compress(5000,5000,1000))
>>> 8456
Obviously this approach has colliding outputs very often (whenever x, y or z are the same modulo 32), but as you said this is pretty unavoidable.

Statistical probability of N contiguous true-bits in a sequence of bits?

Let's assume I have an N-bit stream of generated bits. (In my case 64kilobits.)
Whats the probability of finding a sequence of X "all true" bits, contained within a stream of N bits. Where X = (2 to 16), and N = (16 to 1000000), and X < N.
For example:
If N=16 and X=5, whats the likelyhood of finding 11111 within a 16-bit number.
Like this pseudo-code:
int N = 1<<16; // (64KB)
int X = 5;
int Count = 0;
for (int i = 0; i < N; i++) {
int ThisCount = ContiguousBitsDiscovered(i, X);
Count += ThisCount;
}
return Count;
That is, if we ran an integer in a loop from 0 to 64K-1... how many times would 11111 appear within those numbers.
Extra rule: 1111110000000000 doesn't count, because it has 6 true values in a row, not 5. So:
1111110000000000 = 0x // because its 6 contiguous true bits, not 5.
1111100000000000 = 1x
0111110000000000 = 1x
0011111000000000 = 1x
1111101111100000 = 2x
I'm trying to do some work involving physically-based random-number generation, and detecting "how random" the numbers are. Thats what this is for.
...
This would be easy to solve if N were less than 32 or so, I could just "run a loop" from 0 to 4GB, then count how many contiguous bits were detected once the loop was completed. Then I could store the number and use it later.
Considering that X ranges from 2 to 16, I'd literally only need to store 15 numbers, each less than 32 bits! (if N=32)!
BUT in my case N = 65,536. So I'd need to run a loop, for 2^65,536 iterations. Basically impossible :)
No way to "experimentally calculate the values for a given X, if N = 65,536". So I need maths, basically.
Fix X and N, obiously with X < N. You have 2^N possible values of combinations of 0 and 1 in your bit number, and you have N-X +1 possible sequences of 1*X (in this part I'm only looking for 1's together) contained in you bit number. Consider for example N = 5 and X = 2, this is a possible valid bit number 01011, so fixed the last two characteres (the last two 1's) you have 2^2 possible combinations for that 1*Xsequence. Then you have two cases:
Border case: Your 1*X is in the border, then you have (2^(N -X -1))*2 possible combinations
Inner case: You have (2^(N -X -2))*(N-X-1) possible combinations.
So, the probability is (border + inner )/2^N
Examples:
1)N = 3, X =2, then the proability is 2/2^3
2) N = 4, X = 2, then the probaility is 5/16
A bit brute force, but I'd do something like this to avoid getting mired in statistics theory:
Multiply the probabilities (1 bit = 0.5, 2 bits = 0.5*0.5, etc) while looping
Keep track of each X and when you have the product of X bits, flip it and continue
Start with small example (N = 5, X=1 - 5) to make sure you get edge cases right, compare to brute force approach.
This can probably be expressed as something like Sum (Sum 0.5^x (x = 1 -> 16) (for n = 1 - 65536) , but edge cases need to be taken into account (i.e. 7 bits doesn't fit, discard probability), which gives me a bit of a headache. :-)
#Andrex answer is plain wrong as it counts some combinations several times.
For example consider the case N=3, X=1. Then the combination 101 happens only 1/2^3 times but the border calculation counts it two times: one as the sequence starting with 10 and another time as the sequence ending with 01.
His calculations gives a (1+4)/8 probability whereas there are only 4 unique sequences that have at least a single contiguous 1 (as opposed to cases such as 011):
001
010
100
101
and so the probability is 4/8.
To count the number of unique sequences you need to account for sequences that can appear multiple times. As long as X is smaller than N/2 this will happens. Not sure how you can count them tho.

Logical left shift of 0

Here my question is why the logical left shift 0 is one.
1<<0 = 1, but how?
According to definition the logical left shift works by shifting the bits towards left by n bits.
Logical left shifts works by multiplying number with 2
n << number = 2*n*number; not in case of number=0;
Even if the 0 or the negative numbers are stored in two's complement, so for zero all the bits must be one, then how its logical left shift works.
1<<0 =1 1<<2=4
2<<0 =2 2<<2=8
3<<0 =3 3<<2=12
Bit shift left multiplies the right hand number by 2 to the power of the left hand side. For example: 1 << 2 is the same as 1 * 2^2 (where ^ represents exponent, not XOR).
1 in binary is 0001, then bitshifting it by 0 won't do anything, which aligns with what you observed.
So any number x << 0 is equivalent to x * 2^0, which is x * 1, which is just x.
you are doing a mistake by considering it "2 * n" but its "2^n". like 2*3=6 but 2^3 will be 8. secondly, if you have 0001 and you are shifting 0-bit than it wouldn't affect because 2^0=1 and 1*1 will be 1. but if you shift 1-bit it will multiply it with "2". for example, 0001 and you shifted 1-bit. it becomes 0010 which is 2.

how do I generate 2 random prime numbers that when multiplied, yield a number with X bits? (X given as argument))

I lack the math skills to make this function.
basically, i want to return 2 random prime numbers that when multiplied, yield a number of bits X given as argument.
for example:
if I say my X is 3 then a possible solution would be:
p = 2 and q = 3 becouse 2 * 3 = 6 (110 has 3 bits).
A problem with this statement is that it starts by asking for two "random" prime numbers. Without any explicit statement of the distribution of the required random primes, we are already stuck. (This is the beginning of a classic paradox, where we are asked to generate a "random" integer.)
But suppose that we change the statement to finding any two arbitrary primes, that yield the desired product with a given number of bits x. The answer is trivial.
The set of numbers that have exactly x bits in their binary representation is the half open set of integers [2^(x-1),2^x-1].
Choose an arbitrary prime number that is less than or equal to (2^x-1)/2. Call it p1.
Next, choose a second prime number that lies in the interval (2^(x-1)/p1,(2^x-1)/p1). Call it p2.
It must be true that p1*p2 will be in the desired interval.
For example, given x = 10, so the product must lie in the interval [512,1023], the set of integers with exactly 10 bits. (Note, there are apparently 147 such numbers in that interval, with exactly two prime factors.)
Step 1:
Choose p1 as any prime no larger than 1023/2 = 511.5. I'll pick p1 = 137. Then the second prime factor must be a prime that lies in the interval
[512 1023]/137
ans =
3.7372 7.4672
thus either 5 or 7.
dec2bin(137*[5 7])
ans =
1010101101
1110111111
If you know the number of bits, you can generate a number 2^(x-2) < x < 2^(x-1). Then take the square root and find the closest primes on either side of it. Multiplying them together will, in most cases, get you a number in the correct range. If it's too high, you can take the two primes directly on the lower side of it.
pseudocode:
x = bits
primelist[] = makeprimelist()
rand = randnum between 2^(x-2) and 2^(x-1)
n = findposition(primelist, rand)
do
result = primelist[n]*primelist[n+1]
n--
while result > 2^(x-1)
Note that numbers generated this way will allways have '1' as the highest significant bit, so would be possible to generate a number of x-1 bits and just tack the 1 onto the end.

Adding negative and positive binary?

X = 01001001 and Y = 10101010
If I want to add them together how do I do that? They are "Two's Complement"...
I have tried a lots of things but I am not quite sure I am getting the right answer since there seems to be different type of rules.
Just want to make sure it is correct:
1. Add them as they are do not convert the negative
2. Convert the negative number you get and that's the sum.
f.eks
01001001+10101010 = 11110011 => 00001100 => 1101 => -13
Or?
1. Convert the negative
2. Add them together and convert the negative
f.eks
01001001+10101010 => 01001001 + 01010110 => 10011111 => 01100001 => -97
So basically what I want to do is to take: X-Y, and X+Y
Can someone tell me how to do that?
Some resource sites:
student-binary
celtickane
swarthmore
The beauty of two's complement is that at the binary level it's a matter of interpretation rather than algorithm - the hardware for adding two signed numbers is the same as for unsigned numbers (ignoring flag bits).
Your first example - "just add them" - is exactly the right answer. Your example numbers
01001001 = 73
10101010 = -86
So, the correct answer is indeed -13.
Subtracting is just the same, in that no special processing is required for two's complement numbers: you "just subtract them".
Note that where things get interesting is the handling of overflow/underflow bits. You can't represent the result of 73 - (-86) as an 8-bit two's complement number...
Adding in two's complement doesn't require any special processing when the signs of the two arguments are opposite. You just add them as you normally would in binary, and the sign of the result is the sign you keep.
And just to make sure you understand two's complement, to convert from a positive to a negative number (or vice versa): invert each bit, then add 1 to the result.
For example, your positive number X = 01001001 becomes 10110101+1=10110110 as a negative number; your negative number Y = 10101010 becomes 01010101+1=01010110 as a positive number.
To subtract Y from X, negate Y and add. I.E. 01001001 + 01010110.
Your confusion might be because of the widths of the numbers involved. To get a better feel for this you could try creating a signed integer out of your unsigned integer.
If the MSB of your unsigned integer is already 0, then you can read it as signed and get the same result.
If the MSB is 1 then you can append a 0 to the left to get a signed number. You should sign-extend (that is, add 0s if the MSB is 0, add 1s if the MSB is 1) all the signed numbers to get a number of the same width so you can do the arithmetic "normally".
For instance, using your numbers:
X = 01001001: Unsigned, MSB is 0, do nothing.
Y = 10101010: Signed, did nothing with X, still do nothing.
But if we change the MSB of X to 1:
X = 11001001: Unsigned, MSB is 1, Add a 0 --> 011001001
Y = 10101010: Signed, extended X, so sign-extend Y --> 110101010
Now you have two signed numbers that you can add or subtract the way you already know.
01001001 + 10101010 = 11110011 => 00001100 => 1101 => -13
The first addend is 73. The second addend is -86. 86 = 101010. Padding to 8 bits including the 1 for the negative sign, -86 = 10101010
Both addends are in Sign-bit representation.
Solving them their sum is 1 1 1 1 0 0 1 1 which is an encoded binary (equivalent to having undergone One's Complement by inversion then Two's Complement by adding 1).
So do the reverse to have the decimal number. This time do first subtract 1 as inverse of Two's Complement = 1 1 1 1 0 0 1 1 - 1
= 1 1 1 1 0 0 1 0 then invert as in One's Complement = 0 0 0 0 1 1 0 1 which is equal to 13. Having done such reversal or having acknowledged One's complement and Two's Complement, the answer is negative. So affix the negative sign = -13

Resources