Diffing the bits of an integer - c#

I have a 32 bit integer which I fill with data by mapping the individual bits to various types of data.
For instance one section is used for oxygen level. It's a value from 0 to 128, so I use 7 bits for that.
Another section is used for the rotation of the object. Rotation is always either 0, 90, 180 or 270 degrees around the three axis x, y and z. Each angle is indexed with the values 0, 1, 2 and 3, so I only need 6 bits. Rotation is stored as 010101 for a rotation of 90 deg around x, y and z, or 100000 for a rotation of 180 deg around x.
Some of the sections are stored as integer values, like with oxygen level, but cast to enums when I need to use them.
Each of the sections are laid out next to each other in the data integer, filling the bits from right to left.
Type : ... | Oxygen | Rotation |
--------------------------
Bits: ... | 0000000 | 000000 |
--------------------------
Position: ... | 19-25 | 26-31 |
--------------------------
The problem
I would like to compare two integers and see what's changed.
When the oxygen level of one int is 16, and the other is 20, the difference is an increase of 4 units. When one rotation is 0 on all axis, and an other is 90 around x, the difference is a rotation around x of 90 deg.
I have extension methods on the data object that allows me to get the oxygen level as an int value, and the rotation as a quaternion. When using these on the delta data object, I would like to get the value 4 for oxygen level, and a quaternion for the rotation 90 deg around x.
Question
What's the most efficient way to get the difference in value of two integers?
Possible approaches
I've thought about a couple of different ways to approach this.
Integer comparing
Since the data is an integer, I tried to simply subtract one from the other. I started with an int with a value of 0 and set the bits for oxygen level to 16. I created a new int, set its oxygen level to 20, and subtracted the first from the last, and the oxygen level of the delta was 4. But as I added rotation and other data to the integers, the result after the subtraction changed the resulting oxygen level and rotation.
I need to verify that all my extension methods are working as intended. All unit tests succeeds, but the tests might not be good enough.
Bitwise comparing
Another approach was to compare each bit separately throughout the entire integer, using the various bitwise operators. I used an int with the rotation bits set to 90 deg around x (bits 01). Another int had the x rotation set to 180 deg (bits 10). The delta value I was looking for is 90 deg (bits 01), but I couldn't find any suitable operators to produce that result.
This test led me to believe that I can't compare bits separately. In the case of the rotation indexes, I need to look at a pair of bits as a single value.
BitArray
I read the documentation for .net's BitArray, but couldn't immediately see using that would make any difference.
Compare each section
Comparing each bit section would produce the result I'm looking for. The rotation bits would be converted to a quaternion before calculating the difference, and then converted back to bits before setting them in the data integer.
This is the approach I was hoping to find an alternative to. I didn't want the comparer to know the structure of the data, and I was hoping to find a more efficient solution.
Edit
I see now, after reading the comments and doing more testing, that it would be more beneficial for my case to get only the new value of a bit section, and not how much they changed. Any section that remains unchanged should be zeroed out. As far as I can see, my only option is to compare the data sectionwise.
Edit again
I'm not sure which answer to pick as the correct one. I don't think my question was specific enough, and am sorry for that.
The method given by #harold works when comparing bit by bit, and is independent of the data structure.
The answer by #Pikoh compares section by section, and can be made dynamic so that the method won't need to know about the data structure.

I am not exactly sure what you wanted, but it is certainly possible to compute the modular difference for all fields, using typical SWAR techniques:
z = ((x | H) - (y &~H)) ^ ((x ^~y) & H)
This is the general formula for SWAP subtraction. For 2-bit fields, H = 0xAAAAAAAA.
Since there are only two bits and SWAR usually treats the top bit differently (to prevent leaking into the next field), the bits are effectively totally separate.
With the new requirements it is also not necessary to do ugly splitting of the fields, for example: (not tested)
m = x ^ y;
m = (m | (m >> 1)) & 0x55555555;
m *= 3;
z = y & m; // maybe
The idea here is that a xor will produce a 1 somewhere in a field iff it has changed, then OR all bits of the field and put it in the lowest bit of the field, the multiplication by 3 broadcasts it to all bits of the field. & with the new value to get changed fields and zeroes elsewhere, but that means you cannot distinguish between "changed to 0" and "unchanged". Using m you can still distinguish them.

Let's see if something like this helps you:
int data1 = Convert.ToInt32("00000000000000000000000000011100", 2); //sample data
int data2 = Convert.ToInt32("00000000000000000000000000101000", 2);
int xrotationposition = 26; //start positions of data
int yrotationposition = 28;
string xrotationmask = new string('0', xrotationposition) + "11" +
new string('0',30 - xrotationposition); //mask to extract the data
string yrotationmask = new string('0', yrotationposition) + "11" +
new string('0', 30 - yrotationposition);
int xrotation1 = data1 & Convert.ToInt32(xrotationmask, 2); //bit AND
int xrotation2 = data2 & Convert.ToInt32(xrotationmask, 2);
int yrotation1 = data1 & Convert.ToInt32(yrotationmask, 2);
int yrotation2 = data2 & Convert.ToInt32(yrotationmask, 2);
xrotation1 = (xrotation1 >> 30 - xrotationposition); //shift the bits
to the lowest part of byte
xrotation2 = (xrotation2 >> 30 - xrotationposition);
yrotation1 = (yrotation1 >> 30 - yrotationposition);
yrotation2 = (yrotation2 >> 30 - yrotationposition);
At the end of this execution, you'll get xrotation1=1, xrotation2=2,yrotation1=3 and yrotation2=2, that seems easy values to compare.
Hope this helps

Related

How to Split a byte into 2 parts and read it? [duplicate]

This question already has answers here:
How to work with the bits in a byte
(4 answers)
Closed 3 years ago.
I encountered this problem on a task given to me.
Here's the situation:
If the user clicks on "Vat First" then the value is 0.
Else, the value is 1.
Then, in this Textbox,
The range of the value permitted is 0 to 15.
Then the example values are saved like this:
"01" = since it's vat first and 1mm Z-axis Up height.
"11" = Platform First, 1mm Z-axis up
"015" = vat first, 15mm
"115" = platform first, 15mm
The reason why it is saved like this because it is the file protocol given to me, and I can't do anything about it. It says there that the value is "Platform Moving order and Z Axis Up height" in 1 byte value.
My problem now is reading the result afterwards for reloading it to the application. How do I know if it just uses 3 or 2 digits since the return of int disregards the 0 in the beginning. "015" = "15" so my application might treat it as Platform First, 5 mm rather than Vat first, 15mm.
Edit: So I just realized thanks to #BenVoigt, that it is saved into a byte and it has 8 bits. According to the protocol given to me, the first 4-bits is the moving order (0 or 1) and the rest is for the Z-Axis Up Height (0-15). For the real question, how do I separate the byte into 4 bits each and get the value?
the first 4-bits is the moving order (0 or 1) and the rest is for the Z-Axis Up Height (0-15).
This is a straightforward bit-shifting task.
Order = Combined >> 4;
Height = Combined & 0x0F;
And saving:
Combined = (Order << 4) | Height;
The << and >> are the bitshift operators.
Can’t you just make both results strings and just append them together for your result? It seems that the integer type is your issue.

Get random double (floating point) value from random byte array between 0 and 1 in C#?

Assume I have an array of bytes which are truly random (e.g. captured from an entropy source).
byte[] myTrulyRandomBytes = MyEntropyHardwareEngine.GetBytes(8);
Now, I want to get a random double precision floating point value, but between the values of 0 and positive 1 (like the Random.NextDouble() function performs).
Simply passing an array of 8 random bytes into BitConverter.ToDouble() can yield strange results, but most importantly, the results will almost never be less than 1.
I am fine with bit-manipulation, but the formatting of floating point numbers has always been mysterious to me. I tried many combinations of bits to apply randomness to and always ended up finding the numbers were either just over 1, always VERY close to 0, or very large.
Can someone explain which bits should be made random in a double in order to make it random within the range 0 and 1?
Though working answers have been given, I'll give an other one, that looks worse but isn't:
long asLong = BitConverter.ToInt64(myTrulyRandomBytes, 0);
double number = (double)(asLong & long.MaxValue) / long.MaxValue;
The issue with casting from an ulong to double is that it's not directly supported by hardware, so it compiles to this:
vxorps xmm0,xmm0,xmm0
vcvtsi2sd xmm0,xmm0,rcx ; interpret ulong as long and convert it to double
test rcx,rcx ; add fixup if it was "negative"
jge 000000000000001D
vaddsd xmm0,xmm0,mmword ptr [00000060h]
vdivsd xmm0,xmm0,mmword ptr [00000068h]
Whereas with my suggestion it will compile more nicely:
vxorps xmm0,xmm0,xmm0
vcvtsi2sd xmm0,xmm0,rcx
vdivsd xmm0,xmm0,mmword ptr [00000060h]
Both tested with the x64 JIT in .NET 4, but this applies in general, there just isn't a nice way to convert an ulong to a double.
Don't worry about the bit of entropy being lost: there are only 262 doubles between 0.0 and 1.0 in the first place, and most of the smaller doubles cannot be chosen so the number of possible results is even less.
Note that this as well as the presented ulong examples can result in exactly 1.0 and distribute the values with slightly differing gaps between adjacent results because they don't divide by a power of two. You can change them exclude 1.0 and get a slightly more uniform spacing (but see the first plot below, there is a bunch of different gaps, but this way it is very regular) like this:
long asLong = BitConverter.ToInt64(myTrulyRandomBytes, 0);
double number = (double)(asLong & long.MaxValue) / ((double)long.MaxValue + 1);
As a really nice bonus, you can now change the division to a multiplication (powers of two usually have inverses)
long asLong = BitConverter.ToInt64(myTrulyRandomBytes, 0);
double number = (double)(asLong & long.MaxValue) * 1.08420217248550443400745280086994171142578125E-19;
Same idea for ulong, if you really want to use that.
Since you also seemed interested specifically in how to do it with double-bits trickery, I can show that too.
Because of the whole significand/exponent deal, it can't really be done in a super direct way (just reinterpreting the bits and that's it), mainly because choosing the exponent uniformly spells trouble (with a uniform exponent, the numbers are necessarily clumped preferentially near 0 since most exponents are there).
But if the exponent is fixed, it's easy to make a double that's uniform in that region. That cannot be 0 to 1 because that spans a lot of exponents, but it can be 1 to 2 and then we can subtract 1.
So first mask away the bits that won't be part of the significand:
x &= (1L << 52) - 1;
Put in the exponent (1.0 - 2.0 range, excluding 2)
x |= 0x3ff0000000000000;
Reinterpret and adjust for the offset of 1:
return BitConverter.Int64BitsToDouble(x) - 1;
Should be pretty fast, too. An unfortunate side effect is that this time it really does cost a bit of entropy, because there are only 52 but there could have been 53. This way always leaves the least significant bit zero (the implicit bit steals a bit).
There were some concerns about the distributions, which I will address now.
The approach of choosing a random (u)long and dividing it by the maximum value clearly has a uniformly chosen (u)long, and what happens after that is actually interesting. The result can justifiably be called a uniform distribution, but if you look at it as a discrete distribution (which it actually is) it looks (qualitatively) like this: (all examples for minifloats)
Ignore the "thicker" lines and wider gaps, that's just the histogram being funny. These plots used division by a power of two, so there is no spacing problem in reality, it's only plotted strangely.
Top is what happens when you use too many bits, as happens when dividing a complete (u)long by its max value. This gives the lower floats a better resolution, but lots of different (u)longs get mapped onto the same float in the higher regions. That's not necessarily a bad thing, if you "zoom out" the density is the same everywhere.
The bottom is what happens when the resolution is limited to the worst case (0.5 to 1.0 region) everywhere, which you can do by limiting the number of bits first and then doing the "scale the integer" deal. My second suggesting with the bit hacks does not achieve this, it's limited to half that resolution.
For what it's worth, NextDouble in System.Random scales a non-negative int into the 0.0 .. 1.0 range. The resolution of that is obviously a lot lower than it could be. It also uses an int that cannot be int.MaxValue and therefore scales by approximately 1/(231-1) (cannot be represented by a double, so slightly rounded), so there are actually 33 slightly different gaps between adjacent possible results, though the majority of the gaps is the same distance.
Since int.MaxValue is small compared to what can be brute-forced these days, you can easily generate all possible results of NextDouble and examine them, for example I ran this:
const double scale = 4.6566128752458E-10;
double prev = 0;
Dictionary<long, int> hist = new Dictionary<long, int>();
for (int i = 0; i < int.MaxValue; i++)
{
long bits = BitConverter.DoubleToInt64Bits(i * scale - prev);
if (!hist.ContainsKey(bits))
hist[bits] = 1;
else
hist[bits]++;
prev = i * scale;
if ((i & 0xFFFFFF) == 0)
Console.WriteLine("{0:0.00}%", 100.0 * i / int.MaxValue);
}
This is easier than you think; its all about scaling (also true when going from a 0-1 range to some other range).
Basically, if you know that you have 64 truly random bits (8 bytes) then just do this:
double zeroToOneDouble = (double)(BitConverter.ToUInt64(bytes) / (decimal)ulong.MaxValue);
The trouble with this kind of algorithm comes when your "random" bits aren't actually uniformally random. That's when you need a specialized algorithm, such as a Mersenne Twister.
I don't know wether it's the best solution for this, but it should do the job:
ulong asLong = BitConverter.ToUInt64(myTrulyRandomBytes, 0);
double number = (double)asLong / ulong.MaxValue;
All I'm doing is converting the byte array to a ulong which is then divided by it's max value, so that the result is between 0 and 1.
To make sure the long value is within the range from 0 to 1, you can apply the following mask:
long longValue = BitConverter.ToInt64(myTrulyRandomBytes, 0);
longValue &= 0x3fefffffffffffff;
The resulting value is guaranteed to lay in the range [0, 1).
Remark. The 0x3fefffffffffffff value is very-very close to 1 and will be printed as 1, but it is really a bit less than 1.
If you want to make the generated values greater, you could set a number higher bits of an exponent to 1. For instance:
longValue |= 0x03c00000000000000;
Summarizing: example on dotnetfiddle.
If you care about the quality of the random numbers generated, be very suspicious of the answers that have appeared so far.
Those answers that use Int64BitsToDouble directly will definitely have problems with NaNs and infinities. For example, 0x7ff0000000000001, a perfectly good random bit pattern, converts to NaN (and so do thousands of others).
Those that try to convert to a ulong and then scale, or convert to a double after ensuring that various bit-pattern constraints are met, won't have NaN problems, but they are very likely to have distributional problems. Representable floating point numbers are not distributed uniformly over (0, 1), so any scheme that randomly picks among all representable values will not produce values with the required uniformity.
To be safe, just use ToInt32 and use that int as a seed for Random. (To be extra safe, reject 0.) This won't be as fast as the other schemes, but it will be much safer. A lot of research and effort has gone into making RNGs good in ways that are not immediately obvious.
Simple piece of code to print the bits out for you.
for (double i = 0; i < 1.0; i+=0.05)
{
var doubleToInt64Bits = BitConverter.DoubleToInt64Bits(i);
Console.WriteLine("{0}:\t{1}", i, Convert.ToString(doubleToInt64Bits, 2));
}
0.05: 11111110101001100110011001100110011001100110011001100110011010
0.1: 11111110111001100110011001100110011001100110011001100110011010
0.15: 11111111000011001100110011001100110011001100110011001100110100
0.2: 11111111001001100110011001100110011001100110011001100110011010
0.25: 11111111010000000000000000000000000000000000000000000000000000
0.3: 11111111010011001100110011001100110011001100110011001100110011
0.35: 11111111010110011001100110011001100110011001100110011001100110
0.4: 11111111011001100110011001100110011001100110011001100110011001
0.45: 11111111011100110011001100110011001100110011001100110011001100
0.5: 11111111011111111111111111111111111111111111111111111111111111
0.55: 11111111100001100110011001100110011001100110011001100110011001
0.6: 11111111100011001100110011001100110011001100110011001100110011
0.65: 11111111100100110011001100110011001100110011001100110011001101
0.7: 11111111100110011001100110011001100110011001100110011001100111
0.75: 11111111101000000000000000000000000000000000000000000000000001
0.8: 11111111101001100110011001100110011001100110011001100110011011
0.85: 11111111101011001100110011001100110011001100110011001100110101
0.9: 11111111101100110011001100110011001100110011001100110011001111
0.95: 11111111101110011001100110011001100110011001100110011001101001

How to scale a range of values from 0-1 to 0-10

I have developed a app which is allowed to play a recording on iOS. On iOS, the volume range is from 0 - 1 ie it returns either 0 or 1. For representational purpose I would like to scale that range to 0-10. How can I do that?
Assuming you want to scale it linearly(a), it's a simple matter of multiplying it by ten. I hesitate to state the obvious (i.e., don't want to sound condescending) but, on the rather unlikely chance you don't know how to do that:
scaledValue = inputValue * 10;
Of course, if the input is what you desire to be in the range 0..10, then you'd need to divide it by ten when passing it to the iOS functions that need 0..1.
Just be certain that you're using floating point values of some description for both the input and output scales, otherwise you may run into issues where the scaling will not work as you expect (if you want an integer value from zero to ten, convert it to an integer as the final step, after all scaling has been done).
(a) If the scaling you want is non-linear, you'll need to tell us the formula you want to use, keeping in mind that the C# expression will be remarkably similar to what you give. And of course, as any Spinal Tap fan will tell you, the best amplifiers go up to 11 :-)
Assuming your number is float
float map(float x, float in_min, float in_max, float out_min, float out_max
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
in_min -> in_max is your input range
out_min -> out_max is your output range
Usage
float mappedValue = map(VALUE, 0, 1, 0, 10);
Referenced from https://www.arduino.cc/en/Reference/Map
Scaling is typically associated with multiplication. Here, you just have to apply a scale factor of 10, hence, multiply all your values by 10.

Function returning random double with exponential distribution in range (a,b)

I want to generate a random number from a to b. The problem is, the number has to be given with exponential distribution.
Here's my code:
public double getDouble(double low, double high)
{
double r;
(..some stuff..)
r = rand.NextDouble();
if (r == 0) r += 0.00001;
return (1 / -0.9) * Math.Log(1 - r) * (high - low) + low;
}
The problem is that (1 / -0.9) * Math.Log(1 - r) is not between 0 and 1, so the result won't be between a and b. Can someone help? Thanks in advance!
I missunderstood your question in the first answer :) You are already using the inversion sampling.
To map a range into another range, there is a typical mathematical approach:
f(x) = (b-a)(x - min)/(max-min) + a
where
b = upper bound of target
a = lower bound of target
min = lower bound of source
max = upper bound of source
x = the value to map
(this is linear scaling, so the distribution would be preserved)
(You can verify: If you put in min for x, it results in a, if you put in max for x, you'll get b.)
The Problem now: The exponential distribution has a maximum value of inf. So, you cannot use this equation, because it always wold be whatever / inf + 0 - so 0. (Which makes sense mathematically, but ofc. does not fit your needs)
So, the ONLY correct answer is: There is no exponential distribution possible between two fixed numbers, cause you can't map [0,inf] -> [a,b]
Therefore you need some sort of trade-off, to make your result as exponential as possible.
I wrapped my head around different possibilities out of curiosity and I found that you simple can't beat maths on this :P
However, I did some test with Excel and 1.4 Million random records:
I picked a random number as "limit" (10) and rounded the computed result to 1 decimal place. (0, 0.1, 0.2 and so on) This number I used to perform the linear transformation with an maximum of 10, ingoring any result greater than 1.
Out of 1.4 Million computations (generated it 10-20 times), only 7-10 random numbers greater than 1 have been generated:
(Probability density function, After mapping the values: Column 100 := 1, Column 0 := 0)
So:
Map the values to [0,1], using the linear approach mentioned above, assume a maximum of 10 for the transformation.
If you encounter a value > 1 after the transformation - just draw another random number, until the value is < 1.
With only 7-10 occurences out of 1.4 Million tests, this should be close enough, since the re-drawn number will again be pseudo-exponential-distributed.
If you want to build a spaceship, where navigation depends on perfectly exponential distributed numbers between 0 and 1 - don't do it, else you should be good.
(If you want to cheat a bit: If you encounter a number > 1, just find the record that has the biggest variance (i.e. Max(occurrences < expected occurrences)) from it's expected value - then assume that value :P )
Since the support for the exponential distribution is 0 to infinity, regardless of the rate, I'm going to assume that you're asking for an exponential that's truncated below a and above b. Another way of expressing this would be an exponential random variable X conditioned on a <= X <= b.
You can derive the inversion algorithm for this by calculating the cumulative distribution function (CDF) of the truncated distribution as the integral from a to x of the density for your exponential. Scale the result by the area between a and b (which is F(b) - F(a) where F(x) is the CDF of the original exponential distribution) to make it a valid distribution with an area of 1. Set the derived CDF to U, a uniform(0,1) random number, and solve for X to get the inversion.
I don't program C#, but here's the result expressed in Ruby. It should translate pretty transparently.
def exp_in_range(a, b, rate = 1.0)
exp_rate_a = Math.exp(-rate * a)
return -Math.log(exp_rate_a - rand * (exp_rate_a - Math.exp(-rate * b))) / rate
end
I put a default rate of 1.0 since you didn't specify, but clearly you can override that. rand is Ruby's built-in uniform generator. I think the rest is pretty self-explanatory. I cranked out several test sets of 100k observations for a variety of (a,b) values, loaded the results into my favorite stats package, and the results are as expected.
The exponential distribution is not limited on the positive side, so values can go from 0 to inf. There are many ways to scale [0,infinity] to some finite interval, but the result would not be exponential distributed.
If you just want a slice of the exponential distribution between a and b, you could simply draw r from [ra rb] such that -log(1-ra)=a and -log(1-rb)=b , i,e,
r=rand.NextDouble(); // assume this is between 0 and 1
ra=Math.Exp(-a)-1;
rb=Math.Exp(-b)-1;
rbound=ra+(rb-ra)*r;
return -Math.Log(1 - rbound);
Why check for r==0? I think you would want to check for the argument of the log to be >0, so check for r (or rbound int this case) ==1.
Also not clear why the (1/-.9) factor??

Fastest way to calculate an X-bit bitmask?

I have been trying to solve this problem for a while, but couldn't with just integer arithmetic and bitwise operators. However, I think its possible and it should be fairly easy. What am I missing?
The problem: to get an integer value of arbitrary length (this is not relevant to the problem) with it's X least significant bits sets to 1 and the rest to 0. For example, given the number 31, I need to get an integer value which equals 0x7FFFFFFF (31 least significant bits are 1 and the rest zeros).
Of course, using a loop OR-ing a shifted 1 to an integer X times will do the job. But that's not the solution I'm looking for. It should be more in the direction of (X << Y - 1), thus using no loops.
Try this: (1 << X) - 1
Try this:
uint.MaxValue >> (32 - something)
I think the following should work:
int mask = (int)Math.Pow(2, 31) - 1;
This is a single mathematical expression, but it isn't particularly efficient because calculating the power in this way is not really a good idea. However, since we're calculating a power of 2, we can do the same thing using shift:
int mask = (1 << 31) - 1;

Categories