I was tinkering around with working in binary again, for a project I may or may not follow through on – still deciding. Along the way I was dealing with floating point numbers, and how to work with their individual bits in PHP. It’s definitely not as nice as in C, where you can just typecast into the raw binary representation. Unless there’s a better way I haven’t seen, you have to pack() a float, then unpack() it as an unsigned int, before you can use bitwise operators on it to pick out information.
/**
* Takes a single-precision floating point number, and returns it as a
* sequence of bits in the form of an unsigned integer.
*
* @param float $float
* @return int
*/
function floatToIntBits($float)
{
$s = unpack('Vval', pack('f', $float));
return $s['val'];
}
/**
* Takes a sequence of bits representing a float in the form of an unsigned
* integer, and returns an associative array of information about the float.
*
* The returned array has the keys:
* - sign: 0 if positive, 1 if negative
* - exp: exponent, with 127 exponent bias applied
* - mant: decoded mantissa
*
* Using these you can reconstruct the float with (1 - 2*sign) * mant * 2^exp
*
* @param int $bits
* @return array
*/
function floatInfo($bits)
{
$exponent = ($bits & 0x7f800000) >> 23;
$mantissa = $bits & 0x7fffff;
// if the exponent is nonzero, the mantissa gets a leading bit
if ($exponent !== 0) {
$mantissa |= 1 << 23;
}
// decode the mantissa
// bit 23 = 1.0
// bit 22 = 0.5
// bit 21 = 0.25
// etc
$decoded = 0;
for ($i = 23; $i >= 0; $i--) {
if (($mantissa >> $i) & 1) {
$decoded += pow(2, $i - 23);
}
}
return array(
// sign would otherwise be -1 on 32bit systems
'sign' => abs(($bits & 0x80000000) >> 31),
'exp' => $exponent - 127,
'mant' => $decoded,
);
}
$bits = floatToIntBits(25.0);
var_dump(floatInfo($bits));
// array(3) {
// ["sign"]=>
// int(0)
// ["exp"]=>
// int(4)
// ["mant"]=>
// float(1.5625)
// }