2011-01-18 78 views
7

有什麼辦法在PHP中獲得浮點數的二進制表示?像Java的Double.doubleToRawLongBits()如何在PHP中獲取浮點數的二進制表示?

給定一個正的浮點數,我想得到最大的可表示的浮點數小於該數。在Java中,我可以這樣做:

double x = Double.longBitsToDouble(Double.doubleToRawLongBits(d) - 1); 

但我沒有看到任何類似的PHP。

+0

我敢肯定你的Java代碼是馬車。只有低位被設置時會發生什麼?我懷疑忽略指數不起作用......或者當你從指數0到-1,你是否破壞了NaN等位? – derobert 2011-01-19 00:15:23

+1

@derobert:如果你可以發現我的Java代碼不工作的情況,除了±0,±Inf或NaN,讓我知道(用負值給出的最小值大於給定值)。將正IEEE浮點數轉換爲整數時,將被排序。 (負值是逆向排序的)。指數存儲爲帶有偏移量的無符號值,而不是二進制補碼,所以-1實際上是1小於0.如果只設置了低位,則您查看Double.MIN_VALUE的等效值,然後減1得到0 ,這是正確的答案。 – Jenni 2011-01-19 02:00:44

+1

關於此的一篇非常好的文章可以在這裏找到:http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm – Jenni 2011-01-19 02:01:16

回答

2

這不是一個完整的答案,但我知道的唯一辦法浮法成二進制是pack()

4

這裏是我想出了利用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]; 
} 
3

作爲一個附加的應答不整的問題,但到標題:

如果你想看到你的彩車的樣子爲二進制:

​​

輸出:

0011100010001010100101011010010110110111111110000111101000001111 
0011111111010000000000000000000000000000000000000000000000000000 
0011111111100000000000000000000000000000000000000000000000000000 
1011111111100000000000000000000000000000000000000000000000000000 
0

的java:

long lnBits = Double.doubleToLongBits(longValue); 
Byte[] bits = new byte [] { 
    (byte) ((value << 56) >>> 56), 
    (byte) ((value << 48) >>> 56), 
    (byte) ((value << 40) >>> 56), 
    (byte) ((value << 32) >>> 56), 
    (byte) ((value << 24) >>> 56), 
    (byte) ((value << 16) >>> 56), 
    (byte) ((value << 8) >>> 56), 
    (byte) (value >>> 56)} 

PHP:

$bits = $bitsFromJava; 
$str=""; 
for($i=0;$i<8;i++){ 
    $str.=chr($bits[$i]); 
} 
$longValue=unpack('d',$str); 

$bitsToJava=array(); 
for(str_split(pack($longValue)) as $chr){ 
    $bitsToJava[]=ord($chr); 
} 
相關問題