I wrote a function to fix the problem stated above about floating point numbers. (this is especially useful for arithmetic coding, which is what I'm working on) It's not tremendously robust, but it gets the job done for "simple" float values.
function floatbin($myfloat, $precision=16, $return_int_part=true) {
//echo "complete: $myfloat\n";
$binary_string = "";
if($return_int_part) {
$binary_string = decbin($myfloat);
$binary_string .= ".";
$fractional_part = $myfloat-intval($myfloat);
} else {
$fractional_part = explode(".",$myfloat);
$fractional_part = ".".$fractional_part[1];
}
//echo "fractional: $fractional_part\n";
for ($i=1; $i < $precision+1; $i++) {
$binary_fraction = 1/pow(2,$i);
if($fractional_part >= $binary_fraction) {
$binary_string .= "1";
$fractional_part = $fractional_part - $binary_fraction;
} else {
$binary_string .= "0";
}
if($fractional_part == 0) {
break;
}
//echo "order: $binary_fraction\t\t";
//echo "state: $fractional_part\n";
}
return $binary_string;
}
// no problem
$myfloat = 1.5;
$decfloat = base_convert($myfloat,10,2);
echo "result: $decfloat\n"; // returns 1111 (wrong)
$decfloat = floatbin($myfloat, 32);
echo "result: $decfloat\n"; // returns 1.1 (correct)
$decfloat = floatbin($myfloat,16,false);
echo "result: $decfloat\n"; // returns 1 (correct)
// no problem
$myfloat = 4.125;
$decfloat = base_convert($myfloat,10,2);
echo "result: $decfloat\n"; // returns 1000000011101 (wrong)
$decfloat = floatbin($myfloat, 32);
echo "result: $decfloat\n"; // returns 100.001 (correct)
$decfloat = floatbin($myfloat,16,false);
echo "result: $decfloat\n"; // returns 001 (correct)
// will be truncated, so the inverse will not be ==
$myfloat = 12.3456;
$decfloat = base_convert($myfloat,10,2);
echo "result: $decfloat\n"; // returns 11110001001000000 (wrong)
$decfloat = floatbin($myfloat, 32);
echo "result: $decfloat\n"; // returns 1100.01011000011110010011110111011001 (correct, truncated)
$decfloat = floatbin($myfloat,16,false);
echo "result: $decfloat\n"; // returns 0101100001111001 (correct, truncated more)
// a case on where passing false is useful, so the inverse will not be ==
$myfloat = 777777777777.777777;
$decfloat = base_convert($myfloat,10,2);
echo "result: $decfloat\n"; // wrong
$decfloat = floatbin($myfloat, 32);
echo "result: $decfloat\n"; // wrong
$decfloat = floatbin($myfloat,16,false);
echo "result: $decfloat\n"; // correct, but truncated
Saturday, December 15, 2007
Base Convert
POSTED BY
Oriol
AT
9:19 AM