How to convert bit to bit shift value - c#

I have a difficulty selector set as an enum (None=0, Easy = 1<<0, Medium = 1<<1, Hard = 1<<2, Expert = 1<<3). Along with this, I have an array of point values I want to assign to these difficulties. So the array has indexes as so. [0, 100, 133, 166, 200].
The tricky bit, is this. I want to grab the index of the array, that is equivalent to the bit shift of the difficulty. So None = 0 (0000)-> Index = 0. Easy = 1 (0001)-> Index = 1. Medium = 2 (0010)-> Index = 2. Hard = 4 (0100) -> Index = 3. Expert = 8 (1000) -> Index = 4.
I tried doing the Square root originally, as I thought that it was powers of two, but quickly realized that it's actually not RAISED to two, it's just a base of two. So that would never work.
I also know I can get this value via a forloop, where I start at 8 (1000) for instance, and keep a counter as I shift right, and keep that going until it hits 0.
int difficulty = (int)LevelSetup.difficulty;
int difficultyIndex = 0;
while(difficulty != 0)
{
difficultyIndex++;
difficulty = difficulty >> 1;
}
currScorePerQuestion = ScorePerQuestion[difficultyIndex];
IE. Counter = 0; val = 8. | SHIFT | Counter = 1; val = 4; |SHIFT| Counter = 2; val = 2; |SHIFT| Counter = 3; val = 1; |SHIFT| Counter = 4; val = 0; |END| and we end with a value of 4.
The problem with this is that it seems really messy and overkill, especially if you wanted to go up to 64 bits and have lots of indicies. I just know that there is some kind of algorithm that I could use to convert these very simply. I am just struggling to come up with what that equation is exactly.
Any help is super appreciated, thanks!

After asking my friends. They came up with and gave me this solution.
As binary works by raising 2 to the nth power. We always have a base of 2, raised to the number that the bit is. So 2^4 is 8 which is the same as 1000 in binary.
Then, using the properties of Logarithms. You can use Log of base 2, which matches our base 2 powers, and take the log of it's value to get the exponential. ie Log2(2^3) = 3. And Log2(2^7) = 7.
luckily for us, binary matches this pattern completely, so a bit mask of (1000) is 8, which is equal to 2^3, so Log2(8) => 3.
To convert a bit into an index, ie (1000) is the 4th bit, so we want an index of 4.
Log base 2 of 8 -> Math.Log2(8) = 3. Then to get up to our 0 based index, we just add 1.
This leaves us with the following algorithm:
int difficulty = (int)LevelSetup.difficulty;
currScorePerQuestion = ScorePerQuestion[Math.Log2(difficulty)+1];

Related

Linear interpolation between two numbers with steps

I've a little trouble finding out how to linearly interpolate between two numbers with a defined number of intermediate steps.
Let's say I want to interpolate between 4 and 22 with 8 intermediate steps like so : Example
It's easy to figure out that it's x+2 here. But what if the starting value was 5 and the final value 532 with 12 intermediate steps? (In my special case I would need starting and ending value with 16 steps in between)
If you have two fence posts and you put k fence posts between them, you create k + 1 spaces. For instance:
| |
post1 post2
adding one posts creates two spaces
| | |
post1 post2
If you want those k + 1 spaces to be equal you can divide the total distance by k + 1 to get the distance between adjacent posts.
d = 22 - 4 = 18
k = 8
e = d / (k + 1) = 18 / 9 = 2
In your other case example, the answer is
d = 532 - 5 = 527
k = 12
e = d / (k + 1) = 527 / 13 ~ 40.5
I hesitate to produce two separate answers, but I feel this methodology is sufficiently unique from the other one. There's a useful function which may be exactly what you need which is appropriately called Mathf.Lerp().
var start = 5;
var end = 532;
var steps = 13;
for (int i = 0; i <= steps; i++) {
// The type conversion is necessary because both i and steps are integers
var value = Mathf.Lerp(start, end, i / (float)steps);
Debug.Log(value);
}
For actually doing the linear interpolation, use Mathf.MoveTowards().
For figuring out your maximum delta (i.e. the amount you want it to move each step), take the difference, and then divide it by the number of desired steps.
var start = 4;
var end = 22;
var distance = end - start;
var steps = 9; // Your example technically has 9 steps, not 8
var delta = distance / steps;
Note that this conveniently assumes your distance is a clean multiple of steps. If you don't know this is the case and it's important that you never exceed that number of steps, you may want to explicitly check for it. Here's a crude example for an integer. Floating point methods may be more complicated:
if (distance % delta > 0) { delta += 1; }

Counting runs/set of 1's in a binary number

I want to count the runs of 1's in a binary sequence with the help of bitwise operators.
I have searched for similar topics but found different answers from what I'm looking for. Hamming weight is also different as it counts the number of 1's in the binary.
For example, if I have the binary 001101011101, I should have 4 runs of 1's as they are the sets/group of 1's divided by 0's in between them.
I know how to use bitwise operators in C# but I am not really able to use them collectively inside one program.
if you have a string representation of your binary number, then you just need to split the string on "0":
var binaryString = "0011011101110001";
var count = binaryString
.Split(new [] { '0' }, StringSplitOptions.RemoveEmptyEntries)
.Count();
If your number is stored in an int then it's a simple matter to convert to a string:
int value = 12345;
var binaryString = Convert.ToString(value, 2);
The leftmost 1 in a run of ones has the properties that it occurs exactly once per run, it is a 1 itself, and it has a zero to the left of it (or nothing, but that's an implied zero).
We can isolate all the leftmost ones of runs using the last two properties:
uint leftmost = x & ~(x >> 1);
And then the ones can be counted using any bit counting algorithm.
The same sort of thing can be done with the rightmost ones of every group as well, of course.
Shift though all the bits. Do this 32 times and analyze the first bit every time. It is becomes 1, the numbers of groups is increased. If the bit becomes 0, a new group could start.
bool found = false;
int numberOfGroups = 0;
int bits = 0x035D;
for(int i = 0; i < 32; i++)
{
int bit = bits & 1;
if (!found && bit == 1)
{
numberOfGroups++;
found = true;
}
else if (found && bit == 0)
{
found = false;
}
bits >>= 1;
}

C# Rotate bits to left overflow issue

I've been trying to get this to work for several days now, I've read a thousand guides and people's questions, but still, I can't find a way to do it properly.
What I want to do is to rotate the bits to the left, here's an example.
Original number = 10000001 = 129
What I need = 00000011 = 3
I have to rotate the bits to left a certain amount of times (it depends on what the user types), here's what I did:
byte b = (byte)129;
byte result = (byte)((byte)b << 1);
Console.WriteLine(result);
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
The issue with this it that it causes an error (OverflowException) when I try to use the (<<) operator with that number (note that if I put a number which first bit is a 0; example: 3 = 00000011; it works as intended and it returns a 6 as a result.
The problem is, if the first bit is a 1, it gives me the (OverflowException) error. I know this isn't rotating, its just a shifting, the first bit goes away and on the end of the byte a 0 pops up, and I can then change it with an OR 000000001 operation to make it a 1 (if the first bit was a 1, if it was a 0 I just leave it there).
You're getting an overflow exception because you're operating in a checked context, apparently.
You can get around that by putting the code in an unchecked context - or just by making sure you don't perform the cast back to byte on a value that can be more than 255. For example:
int shifted = b << rotateLeftBits;
int highBits = shifted & 0xff;
int lowBits = shifted >> 8; // Previously high bits, rotated
byte result = (byte) (highBits | lowBits);
This will work for rotate sizes of up to 8. For greater sizes, just use rotateLeftBits % 8 (and normalize to a non-negative number if you might sometimes want to rotate right).
<< is a shift operator, not a rotate one.
If you want to rotate, you can use (with suitable casting):
b = (b >> 7) | ((b & 0x7f) << 1);
The first part of that gets the leftmost bit down to the rightmost, the second part shifts all the other left.
The or-ing them with | combines the two.
Thanks for your answers!
Shortly after i made this post i came up with an idea to solve this problem, let me show you (Before you ask, it works!):
byte b = (byte)129;
b = (byte)((byte)b & 127);
byte result = (byte)((byte)b << 1);
result = (byte)((byte)result | 1);
Console.WriteLine(result);
What this does is, removes the first bit (in case if it is a 1) it shifts to the left that zero (doesnt generate overflow) and once the shift is over, it changes that 0 back to 1. If that first bit was a 0, it will just move that zero (note that this is just a piece of the whole code, and as it is partially written in spanish (the comments and variables) i doubt you will understand most of it, so i decided to take out the problematic part to show it to you guys!
I will still try the things you told me and see how it goes, again, thanks a lot for your answers!
please try this function - rotates in both directions (left and right rotation of an 8 bit value) [I didn't tested that function!]
// just for 8Bit values (byte)
byte rot(byte value, int rotation)
{
rotation %= 8;
int result;
if(rotation < 0)
{
result = value << (8 + rotation);
}
else
{
result = value << rotation;
}
byte[] resultBytes = BitConverter.GetBytes(result);
result = resultBytes[0] | resultBytes[1];
return (byte)result;
}
short rot(short value, int rotation) { ... }
int rot(int value, int rotation) { ... }

C# formula to determine index

I have a maths issue within my program. I think the problem is simple but I'm not sure what terms to use, hence my own searches returned nothing useful.
I receive some values in a method, the only thing I know (in terms of logic) is the numbers will be something which can be duplicated.
In other words, the numbers I could receive are predictable and would be one of the following
1
2
4
16
256
65536
etc
I need to know at what index they appear at. In othewords, 1 is always at index 0, 2 at index 1, 4 at index 3, 16 is at index 4 etc.
I know I could write a big switch statement but I was hoping a formula would be tidier. Do you know if one exists or any clues as the names of the math forumula's I'm using.
The numbers you listed are powers of two. The inverse function of raising a number to a power is the logarithm, so that's what you use to go backwards from (using your terminology here) a number to an index.
var num = 256;
var ind = Math.Log(num, 2);
Above, ind is the base-2 logarithm of num. This code will work for any base; just substitute that base for 2. If you are only going to be working with powers of 2 then you can use a special-case solution that is faster based on the bitwise representation of your input; see What's the quickest way to compute log2 of an integer in C#?
Try
Math.Log(num, base)
where base is 2
MSDN: http://msdn.microsoft.com/en-us/library/hd50b6h5.aspx
Logarithm will return to You power of base from you number.
But it's in case if your number really are power of 2,
otherwise you have to understand exactly what you have, what you need
It also look like numbers was powered to 2 twice, so that try this:
private static int getIndexOfSeries(UInt64 aNum)
{
if (aNum == 1)
return 0;
else if (aNum == 2)
return 1;
else
{
int lNum = (int)Math.Log(aNum, 2);
return 1+(int)Math.Log(lNum, 2);
}
}
Result for UInt64[] Arr = new UInt64[] { 1, 2, 4, 16, 256, 65536, 4294967296 } is:
Num[0] = 1
Num[1] = 2
Num[2] = 4
Num[3] = 16
Num[4] = 256
Num[5] = 65536
Num[6] = 4294967296 //65536*65536
where [i] - index
You should calculate the base 2 logarithm of the number
Hint: For the results:
0 2
1 4
2 16
3 256
4 65536
5 4294967296
etc.
The formula is, for a give integer x:
Math.Pow(2, Math.Pow(2, x));
that is
2 to the power (2 to the power (x) )
Once the formula is known, one could solve it for x (I won't go through that since you already got an answer).

Invert 1 bit in C#

I have 1 bit in a byte (always in the lowest order position) that I'd like to invert.
ie given 00000001 I'd like to get 00000000 and with 00000000 I'd like 00000001.
I solved it like this:
bit > 0 ? 0 : 1;
I'm curious to see how else it could be done.
How about:
bit ^= 1;
This simply XOR's the first bit with 1, which toggles it.
If you want to flip bit #N, counting from 0 on the right towards 7 on the left (for a byte), you can use this expression:
bit ^= (1 << N);
This won't disturb any other bits, but if the value is only ever going to be 0 or 1 in decimal value (ie. all other bits are 0), then the following can be used as well:
bit = 1 - bit;
Again, if there is only going to be one bit set, you can use the same value for 1 as in the first to flip bit #N:
bit = (1 << N) - bit;
Of course, at that point you're not actually doing bit-manipulation in the same sense.
The expression you have is fine as well, but again will manipulate the entire value.
Also, if you had expressed a single bit as a bool value, you could do this:
bit = !bit;
Which toggles the value.
More of a joke:
Of course, the "enterprisey" way would be to use a lookup table:
byte[] bitTranslations = new byte[256];
bitTranslations[0] = 1;
bitTranslations[1] = 0;
bit = bitTranslations[bit];
Your solution isn't correct because if bit == 2 (10) then your assignment will yield bit == 0 (00).
This is what you want:
bit ^= 1;

Categories

Resources