I have a 16-bit number, like 0x789A and I want to change the 2 most significant bits to 10 (setting the highest and clearing the second-highest) to end up with 0x989A.
I know that I can set the first bit using n | 0x8000 and I can unset the second bit (in php) using n & ~0x4000 but is there a way to "cast" the two bits to 10 in one operation without affecting the lesser bits?
Similarly, I have another 16-bit number, like 0xABCD that I want to change the byte value of the first byte to a different hex value, for instance 5 so that I end up with 0x5BCD. Is there a way to set bytes using bitwise operations? I'm not even sure how to begin for this.
This will set the 2 most significant bits to binary 10:
0x8000 | ($n & 0x3fff)
This will set the most signigicant byte to hex 5:
0x5000 | ($n & 0x0fff)
The general idea is that you use 0 bits in the mask to specify the bits you want to replace, 1 to specify the bits to keep, and then OR in the replacement.
Do it exactly as you had, just do it two bits at a time, e.g
(0x789A & ~0xC000) | 0xC000
0111100010011010 0x789A
& 0011111111111111 ~0xC000 ---clear the two relevant bits
------------------
= 0011100010011010 0x389A
| 1000000000000000 0xC000 --- set their new values
------------------
= 1111100010011010 0xF89A
Related
I have the necessity to store many numbers (i can decide which numbers) as a single unique number from which i should be able to retrieve the original number.
I already know 2 ways to do this:
1) Fundamental theorem of arithmetic (Prime Numbers)
Say i have 5 values, i assign a prime number other than 1 to each value
a = 2
b = 3
c = 5
d = 7
e = 13
If i want to store a, b and c i can multiply them 2*3*5=30 and i know no other product of primes can be 30. Then to check if a value contains, for example, b, all i need to do is 30 % b == 0
2) Bitmask
Just like Linux permissions, use powers of 2 and sum each value
But these 2 methods grow up fast (1st way faster than 2nd), and using prime numbers requires me to have a lot of primes.
Is there any other method to do this efficiently when you have, for example, a thousand values?
If you are storing, say, base 10 numbers, then do a conversion through base 11 numbers. With the increased base, you have an extra 'digit'. Use that digit as a separator. So, three base 10 numbers "10, 42, 457" become "10A42A457": a single base 11 number (with 'A' as the additional digit).
Whatever base your original numbers are in, increase the base by 1 and concatenate, using the extra digit as a separator. That will give you a single number in the increased base.
That single number can be stored in whatever number base you find convenient: binary, denary or hex for example.
To retrieve your original numbers just convert to base 11 (or whatever) and replace the extra digit with separators.
ETA: You don't have to use base 11. The single number "10A42A457" is also a valid hexadecimal number, so any base of 11 or above could be used. Hex may be easier to work with than base 11.
Is there any other method to do this efficiently when you have, for example, a thousand values?
I an not a mathematician but it's basic math, all depends on range
Range 0-1: You want to store 4 numbers 0-1 - it's basically binary system
Number1 + Number2 * 2^1 + Number3 * 2^2 + Number4 * 2^3
Range 0-50 You want to store 4 numbers 0-49
Number1 + Number2 * 50^1 + Number3 * 50^2 + Number4 * 50^3
Range 0-X You want to store N numbers 0-X
Number1 + Number2 * (X+1)^1 + Number3 * (X+1)^2 + ... + NumberN * (X+1)^(N-1)
If you have no pattern for your numbers (so it can get compressed in some way) there is really no other way.
It's also super easy for computer to resolve the number unlike the prime numbers
Predetermined values
#FlorainK comment pointed me to fact I missed
(i can decide which numbers)
The only logical solution is give your numbers references
0 is 15342
1 is 6547
2 is 76234
3 is "i like stack overflow"
4 is 42141
so you'll work range 0-4 (5 options) and whatever combination length. Use reference when "encoding" and "decoding" the number
a thousand values?
so you'll work with Range 0-999
0 is 62342
1 is 7456345653
2 is 45656234532
...
998 is 7623452
999 is 4324234326453
Let's say you use 64-bit system and programming/db language that works with 64-bit integers
2^64 = 18446744073709551616
your max range is 1000^X < 18446744073709551616 where X is number of numbers you can store in one single 64-bit integer number
Which is only 6.
You can store only 6 separate numbers 0-999 that will fit one 64-bit integer number.
0,0,0,0,0,0 is 0
1,0,0,0,0,0 is 1
0,1,0,0,0,0 is 1000
999,999,999,999,999,999 is ~1e+18
Ok so you want to store "a,b,c" or "a,b" or "a,b,c,d" or "a" etc. (thanks #FlorianK)
in such case just could use bitwise operators and powers of two
$a = 1 << 0; // 1
$b = 1 << 1; // 2
$c = 1 << 2; // 4
$d = 1 << 3; // 8
.. etc
let's say $flag has $a and $c
$flag = $a | $c; // $flag is integer here
now check it
$ok = ($flag & $a) && ($flag & $c); // true
$ok = ($flag & $a) && ($flag & $b); // false
so in 64 bit system/language/os you can use up to 64 flags which gives you a 2^64 combinations
there is no really other option. prime numbers are much worse for this as you skip many numbers in-between while binary system uses every single number.
I see you are using database and you want to store this in DB.
I really think we are dealing here with XY Problem and you should reconsider your application instead of making such workarounds.
I am trying to decode a supposedly hex string. In MS SQL Server (11.0.2100) the data has the type of char(8).
In the manuals there was no clear way of decoding the data but it documents what it contains:
Given a hex string ie. 0001003F with a length of 4. The lower byte
is on the right, the higher byte is on the left. For each of the 4
'bytes' a reference table that maps a 'bit' to a certain truthy
value was given. A bit order is also given having the bit 0 or the bit
in right most being the 1st bit, ..., etc.
The table looks like this:
1st 'byte':
|Bit Order | Description | 1 | 0 | trigger |
|-----------|---------------|-------------------|-------------------|---------------|
|BIT0 | state foo | state foo is ON | State foo is OFF | high level |
|BIT1 | state bar | in state bar | not in state bar | high level |
| ...
|BIT7 | state bazz | in state bazz | not in state bazz | high level |
(3 more tables follows for the next 3 other 'byte's ..., each of the 4 'byte's supposedly has 8 equal number of 'bits')
I thought the way of decoding this data is to split the hex string into 4 parts and convert them into a binary string width a fixed with of 8.
In PHP, taken the example hex '0001003F', the first byte was '3F', having the converted to binary, 0011 1111 (space for clarity). Then, inferred that the value for the first byte was:
'state foo is on', 'in state bar', ..., 'not in state bazz'.
I also tried to do: hex2bin("0001003F") but it outputs strin(4) " # ".
Is this the correct way of decoding this data?
(I beg your pardon if the tags are incorrect.)
Since 4 bytes fit into the storage for integer type on almost all platforms (32-bit and higher), you can convert the hex string to integer, then use the bitwise operators to check if specific bit is set:
$hex_str = '0001003F';
$flags = base_convert($hex_str, 16, 10);
foreach (range(0, 31) as $bit) {
printf("Bit %d: %d\n", $bit, (bool) ($flags & (1 << $bit)));
}
Output
Bit 0: 1
Bit 1: 1
Bit 2: 1
Bit 3: 1
Bit 4: 1
Bit 5: 1
Bit 6: 0
...
Bit 15: 0
Bit 16: 1
Bit 17: 0
...
Bit 31: 0
If bit $bit is set (1), then the state corresponding to this bit is on.
The code converts the hex string $hex_str to an integer $flags with the help of base_convert function. The loop iterates bit numbers in range [0;31] (starting from the least significant bit). The (1 << $bit) expression is the value 1 shifted to the left by $bit bits. Thus, if bit number $bit is set, then the result of the bitwise AND operation is a non-zero integer. The result is cast to boolean type to produce 1, if the result is non-zero, and 0 otherwise.
It is easy to see that you can test a number of bits with a single bitwise AND operation, e.g.:
// Check if at least one of three bits is set, 3rd, 10th, or 11th
$mask = (1 << 3) | (1 << 10) | (1 << 11);
if ($flags & $mask)
printf("At least one of the bits from mask 0x%x is set\n", $mask);
Output
At least one of the bits from mask 0xc08 is set
I'm getting into compression algorithms and my native language is PHP, and I can understand that PHP is a language that you wouldn't normally make a big algorithm in, but I was wondering if it was possible. (of course it's possible - more so efficient and powerful)
The first type of algorithm I'd attempt to make is a simple adaptive algorithm, by taking in the most used bytes (chars) and converting them into binary types, (ex: a = 0001, b = 0010, c = 0011) - tho there is no real way to do that in PHP that I am familiar with, before this I was using simple ASCII conversions like a = chr(33), b = chr(34) that would get the least valued ASCII values use them as the smallest -> largest operators for the compression definitions.
So what I am asking is that if there's a way to assign binary values to a variable instead of it being represented as ASCII, if I go:
$string_after_compression = 000100100011;
#split it by 4 bits per = 0001 | 0010 | 0011
That would be interpreted as an int - therefore making an over-large int therefore most likely running out of available ram with a simple sentence, then if I try to store the value in a string instead, that removes the point of compressing as it's just making a string like:
$string_after_compression = "000100100011";
#split it by 4 bits per = "0001" . "0010" . "0011";
-----
This question is a bit confusing but the aim is: Is there a way to assign a PHP variable using a PHP intigers
Example solution:
$binary_var = (binary) 0001;
To work with binary in PHP, your data type of choice is a string. Because strings are mere byte arrays:
$bytes = '';
There's no simple base 2 notation for binary in PHP (0100101), usually the next best option to work with binary is hex notation:
$bytes = "\x42"; // 0100 0010
You'll need to convert between base 2 and base 16 notation back and forth in your head, but once you get used to that it's typically easier to follow and work with than long strings of 1s and 0s.
To test or manipulate binary data you'll want to get used to the binary operators:
if (($bytes[3] & "\x02") === "\x02") {
// the second bit of the forth byte in the sequence is set (0000 0010)
}
$bytes[6] |= "\x02"; // setting the second bit of the seventh byte
This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 5 years ago.
$a = '35';
$b = '-34.99';
echo ($a + $b);
Results in 0.009999999999998
What is up with that? I wondered why my program kept reporting odd results.
Why doesn't PHP return the expected 0.01?
Because floating point arithmetic != real number arithmetic. An illustration of the difference due to imprecision is, for some floats a and b, (a+b)-b != a. This applies to any language using floats.
Since floating point are binary numbers with finite precision, there's a finite amount of representable numbers, which leads accuracy problems and surprises like this. Here's another interesting read: What Every Computer Scientist Should Know About Floating-Point Arithmetic.
Back to your problem, basically there is no way to accurately represent 34.99 or 0.01 in binary (just like in decimal, 1/3 = 0.3333...), so approximations are used instead. To get around the problem, you can:
Use round($result, 2) on the result to round it to 2 decimal places.
Use integers. If that's currency, say US dollars, then store $35.00 as 3500 and $34.99 as 3499, then divide the result by 100.
It's a pity that PHP doesn't have a decimal datatype like other languages do.
Floating point numbers, like all numbers, must be stored in memory as a string of 0's and 1's. It's all bits to the computer. How floating point differs from integer is in how we interpret the 0's and 1's when we want to look at them.
One bit is the "sign" (0 = positive, 1 = negative), 8 bits are the exponent (ranging from -128 to +127), 23 bits are the number known as the "mantissa" (fraction). So the binary representation of (S1)(P8)(M23) has the value (-1^S)M*2^P
The "mantissa" takes on a special form. In normal scientific notation we display the "one's place" along with the fraction. For instance:
4.39 x 10^2 = 439
In binary the "one's place" is a single bit. Since we ignore all the left-most 0's in scientific notation (we ignore any insignificant figures) the first bit is guaranteed to be a 1
1.101 x 2^3 = 1101 = 13
Since we are guaranteed that the first bit will be a 1, we remove this bit when storing the number to save space. So the above number is stored as just 101 (for the mantissa). The leading 1 is assumed
As an example, let's take the binary string
00000010010110000000000000000000
Breaking it into it's components:
Sign Power Mantissa
0 00000100 10110000000000000000000
+ +4 1.1011
+ +4 1 + .5 + .125 + .0625
+ +4 1.6875
Applying our simple formula:
(-1^S)M*2^P
(-1^0)(1.6875)*2^(+4)
(1)(1.6875)*(16)
27
In other words, 00000010010110000000000000000000 is 27 in floating point (according to IEEE-754 standards).
For many numbers there is no exact binary representation, however. Much like how 1/3 = 0.333.... repeating forever, 1/100 is 0.00000010100011110101110000..... with a repeating "10100011110101110000". A 32-bit computer can't store the entire number in floating point, however. So it makes its best guess.
0.0000001010001111010111000010100011110101110000
Sign Power Mantissa
+ -7 1.01000111101011100001010
0 -00000111 01000111101011100001010
0 11111001 01000111101011100001010
01111100101000111101011100001010
(note that negative 7 is produced using 2's complement)
It should be immediately clear that 01111100101000111101011100001010 looks nothing like 0.01
More importantly, however, this contains a truncated version of a repeating decimal. The original decimal contained a repeating "10100011110101110000". We've simplified this to 01000111101011100001010
Translating this floating point number back into decimal via our formula we get 0.0099999979 (note that this is for a 32-bit computer. A 64-bit computer would have much more accuracy)
A Decimal Equivalent
If it helps to understand the problem better, let's look decimal scientific notation when dealing with repeating decimals.
Let's assume that we have 10 "boxes" to store digits. Therefore if we wanted to store a number like 1/16 we would write:
+---+---+---+---+---+---+---+---+---+---+
| + | 6 | . | 2 | 5 | 0 | 0 | e | - | 2 |
+---+---+---+---+---+---+---+---+---+---+
Which is clearly just 6.25 e -2, where e is shorthand for *10^(. We've allocated 4 boxes for the decimal even though we only needed 2 (padding with zeroes), and we've allocated 2 boxes for signs (one for the sign of the number, one of the sign of the exponent)
Using 10 boxes like this we can display numbers ranging from -9.9999 e -9 to +9.9999 e +9
This works fine for anything with 4 or fewer decimal places, but what happens when we try to store a number like 2/3?
+---+---+---+---+---+---+---+---+---+---+
| + | 6 | . | 6 | 6 | 6 | 7 | e | - | 1 |
+---+---+---+---+---+---+---+---+---+---+
This new number 0.66667 does not exactly equal 2/3. In fact, it's off by 0.000003333.... If we were to try and write 0.66667 in base 3, we would get 0.2000000000012... instead of 0.2
This problem may become more apparent if we take something with a larger repeating decimal, like 1/7. This has 6 repeating digits: 0.142857142857...
Storing this into our decimal computer we can only show 5 of these digits:
+---+---+---+---+---+---+---+---+---+---+
| + | 1 | . | 4 | 2 | 8 | 6 | e | - | 1 |
+---+---+---+---+---+---+---+---+---+---+
This number, 0.14286, is off by .000002857...
It's "close to correct", but it's not exactly correct, and so if we tried to write this number in base 7 we would get some hideous number instead of 0.1. In fact, plugging this into Wolfram Alpha we get: .10000022320335...
These minor fractional differences should look familiar to your 0.0099999979 (as opposed to 0.01)
There's plenty of answers here about why floating point numbers work the way they do...
But there's little talk of arbitrary precision (Pickle mentioned it). If you want (or need) exact precision, the only way to do it (for rational numbers at least) is to use the BC Math extension (which is really just a BigNum, Arbitrary Precision implementation...
To add two numbers:
$number = '12345678901234.1234567890';
$number2 = '1';
echo bcadd($number, $number2);
will result in 12345678901235.1234567890...
This is called arbitrary precision math. Basically all numbers are strings which are parsed for every operation and operations are performed on a digit by digit basis (think long division, but done by the library). So that means it's quite slow (in comparison to regular math constructs). But it's very powerful. You can multiply, add, subtract, divide, find modulo and exponentiate any number that has an exact string representation.
So you can't do 1/3 with 100% accuracy, since it has a repeating decimal (and hence isn't rational).
But, if you want to know what 1500.0015 squared is:
Using 32 bit floats (double precision) gives the estimated result of:
2250004.5000023
But bcmath gives the exact answer of:
2250004.50000225
It all depends on the precision you need.
Also, something else to note here. PHP can only represent either 32 bit or 64 bit integers (depending on your install). So if an integer exceeds the size of the native int type (2.1 billion for 32bit, 9.2 x10^18, or 9.2 billion billion for signed ints), PHP will convert the int into a float. While that's not immediately a problem (Since all ints smaller than the precision of the system's float are by definition directly representable as floats), if you try multiplying two together, it'll lose significant precision.
For example, given $n = '40000000002':
As a number, $n will be float(40000000002), which is fine since it's exactly represented. But if we square it, we get: float(1.60000000016E+21)
As a string (using BC math), $n will be exactly '40000000002'. And if we square it, we get: string(22) "1600000000160000000004"...
So if you need the precision with large numbers, or rational decimal points, you might want to look into bcmath...
bcadd() might be useful here.
<?PHP
$a = '35';
$b = '-34.99';
echo $a + $b;
echo '<br />';
echo bcadd($a,$b,2);
?>
(inefficient output for clarity)
First line gives me 0.009999999999998.
Second gives me 0.01
Because 0.01 can't be represented exactly as sum of series of binary fractions. And that is how floats are stored in memory.
I guess it is not what you want to hear, but it is answer to question. For how to fix see other answers.
Every number will be save in computer by binary value such as 0, 1. In Single-precision numbers occupy 32 bits.
The floating point number can be presented by: 1 bit for sign, 8 bit for exponent and 23 bit called mantissa (fraction).
Look the example below:
0.15625 = 0.00101 = 1.01*2^(-3)
sign: 0 mean positive number, 1 mean negative number, in this case it is 0.
exponent: 01111100 = 127 - 3 = 124.
Note: the bias = 127 so biased exponent = −3 + the "bias". In single precision, the bias is ,127, so in this example the biased exponent is 124;
At fraction part, we have: 1.01 mean: 0*2^-1 + 1*2^-2
Number 1 (first position of 1.01) do not need to save because when present the floating number in this way the first number always be 1.
For example convert: 0.11 => 1.1*2^(-1), 0.01 => 1*2^(-2).
Another example show always remove the first zero: 0.1 will be presented 1*2^(-1). So the first alwasy be 1.
The present number of 1*2^(-1) will be:
0: positive number
127-1 = 126 = 01111110
fraction: 00000000000000000000000 (23 number)
Finally: The raw binary is:
0 01111110 00000000000000000000000
Check it here: http://www.binaryconvert.com/result_float.html?decimal=048046053
Now if you already understand how a floating point number are saved. What happen if the number cannot save in 32 bit (simple precision).
For example: in decimal. 1/3 = 0.3333333333333333333333 and because it is infinite I suppose we have 5 bit to save data. Repeat again this is not real. just suppose. So the data saved in computer will be:
0.33333.
Now when the number loaded the computer calculate again:
0.33333 = 3*10^-1 + 3*10^-2 + 3*10^-3 + 3*10^-4 + 3*10^-5.
About this:
$a = '35';
$b = '-34.99';
echo ($a + $b);
The result is 0.01 ( decimal). Now let show this number in binary.
0.01 (decimal) = 0 10001111 01011100001010001111 (01011100001010001111)*(binary)
Check here: http://www.binaryconvert.com/result_double.html?decimal=048046048049
Because (01011100001010001111) is repeat just like 1/3. So computer cannot save this number in their memory. It must sacrifice. This lead not accuracy in computer.
Advanced
( You must have knowledge about mathematics )
So why we can easily show 0.01 in decimal but not in binary.
Suppose the fraction in binary of 0.01 (decimal) is finite.
So 0.01 = 2^x + 2^y... 2^-z
0.01 * (2^(x+y+...z)) = (2^x + 2^y... 2^z)*(2^(x+y+...z)). This expression is true when (2^(x+y+...z)) = 100*x1. There are not integer n = x+y+...+z exists.
=> So 0.01 (decimal) must be infine in binary.
Use PHP's round() function: http://php.net/manual/en/function.round.php
This answer solves problem, but not explains why. I thought that it is obvious [I am also programming in C++, so it IS obvious for me ;]], but if not, let's say that PHP has it's own calculating precision and in that particular situation it returned most complying information regarding that calculation.
wouldn't it be easier to use number_format(0.009999999999998, 2) or $res = $a+$b; -> number_format($res, 2);?
What's the correct way to handle two distinct values being stored in one byte of data. I have a byte that contains two nibbles each containing their own data. I want to read the top nibble and the bottom nibble into their own variables.
11110000 = High 4 bits throttle, to be read into $throttle, and should be a value from 0 to 15.
00001111 = Low 4 bits brake, to be read into $brake, and should be a value from 0 to 15.
Don't forget, drivers can apply the throttle and the brake at the same time, so you might get a value like 11000111. I've myself come up with a solution for the high 4 bits, and it's as simple as pushing the lower 4 bits out of the way with the >> (bit shift right) operator 4 times. $Throttle = $ThrBrk >> 4, but as I can't do that in one move for the lower four bits it looks kinda bad in my source code.
Use ANDoperators for both and shift the top nibble four bits to the right.
$brake = $value & 0x0F;
$throttle = ($value & 0xF0) >> 4;
Check out the & operator, which is a bitwise AND. To get the first (least significant bit), do this:
$lsb = $bits & 1;
So, to get the whole "nibble":
$break = $bits & 15;