PHPで浮動小数点数のバイナリ表現を取得する方法はありますか?JavaのDouble.doubleToRawLongBits()のようなもの。
正の浮動小数点数が与えられた場合、その数よりも小さい、表現可能な最大の浮動小数点数を取得したいと思います。Javaでは、次のように実行できます。
double x = Double.longBitsToDouble(Double.doubleToRawLongBits(d) - 1);
しかし、PHPで似たようなものは見当たりません。
PHPで浮動小数点数のバイナリ表現を取得する方法はありますか?JavaのDouble.doubleToRawLongBits()のようなもの。
正の浮動小数点数が与えられた場合、その数よりも小さい、表現可能な最大の浮動小数点数を取得したいと思います。Javaでは、次のように実行できます。
double x = Double.longBitsToDouble(Double.doubleToRawLongBits(d) - 1);
しかし、PHPで似たようなものは見当たりません。
Peter Baileyの提案を使用して思いついたソリューションを次に示します。64 ビット版の PHP が必要です。私はこれが製品品質であるとは決して主張しませんが、誰かがそれに基づいて構築したい場合に備えて共有しています. (実際、質問を投稿した後、まったく別のことをすることになりましたが、知的演習としてここに残します。)
// Returns the largest double-precision floating-point number which
// is less than the given value. Only works for positive values.
// Requires integers to be represented internally with 64 bits (on Linux
// this usually means you're on 64-bit OS with PHP built for 64-bit OS).
// Also requires 64-bit double-precision floating point numbers, but I
// think this is the case pretty much everywhere.
// Returns false on error.
function prevDouble($d) {
$INT32_MASK = 0xffffffff;
if((0x1deadbeef >> 32) !== 1) {
echo 'error: only works on 64-bit systems!';
return false;
}
if($d <= 0) {
return false;
}
$beTest = bin2hex(pack('d', 1.0)); //test for big-endian
if(strlen($beTest) != 16) {
echo 'error: system does not use 8 bytes for double precision!';
return false;
}
if($beTest == '3ff0000000000000') {
$isBE = true;
}
else if($beTest == '000000000000f03f') {
$isBE = false;
}
else {
echo 'error: could not determine endian mode!';
return false;
}
$bin = pack('d', $d);
//convert to 64-bit int
$int = 0;
for($i = 0; $i < 8; $i++)
$int = ($int << 8) | ord($bin[$isBE ? $i : 7 - $i]);
$int--;
//convert back to double
if($isBE)
$out = unpack('d', pack('N', ($int >> 32) & $INT32_MASK) . pack('N', $int & $INT32_MASK));
else
$out = unpack('d', pack('V', $int & $INT32_MASK) . pack('V', ($int >> 32) & $INT32_MASK));
return $out[1];
}
質問全体ではなく、タイトルに対する追加の回答として:
フロートがバイナリとしてどのように見えるかを確認したい場合:
function floatToBinStr($value) {
$bin = '';
$packed = pack('d', $value); // use 'f' for 32 bit
foreach(str_split(strrev($packed)) as $char) {
$bin .= str_pad(decbin(ord($char)), 8, 0, STR_PAD_LEFT);
}
return $bin;
}
echo floatToBinStr(0.0000000000000000000000000000000000025).PHP_EOL;
echo floatToBinStr(0.25).PHP_EOL;
echo floatToBinStr(0.5).PHP_EOL;
echo floatToBinStr(-0.5).PHP_EOL;
出力:
0011100010001010100101011010010110110111111110000111101000001111
0011111111010000000000000000000000000000000000000000000000000000
0011111111100000000000000000000000000000000000000000000000000000
1011111111100000000000000000000000000000000000000000000000000000
これは完全な答えではありませんが、フロートをバイナリに入れる唯一の方法はpack()を使用することです