How to get binary representation of floating-point number in PHP?

前端 未结 4 1195
长情又很酷
长情又很酷 2021-01-17 16:18

Is there any way to get the binary representation of a floating point number in PHP? Something like Java\'s Double.doubleToRawLongBits().

Given a positive floating p

相关标签:
4条回答
  • 2021-01-17 16:37

    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);
    }
    
    0 讨论(0)
  • 2021-01-17 16:41

    As an additional answer not to the whole question but to the title:

    If you want to see how your floats looks as a binary:

    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;
    

    Output:

    0011100010001010100101011010010110110111111110000111101000001111
    0011111111010000000000000000000000000000000000000000000000000000
    0011111111100000000000000000000000000000000000000000000000000000
    1011111111100000000000000000000000000000000000000000000000000000
    
    0 讨论(0)
  • 2021-01-17 16:42

    Here is a solution I came up with using Peter Bailey's suggestion. It requires 64-bit version of PHP. I don't claim this to be production-quality in any way, but I'm sharing in case anyone wants to build upon it. (In fact I ended up doing something different entirely after I posted the question, but I leave it here as an intellectual exercise.)

    // 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];
    }
    
    0 讨论(0)
  • 2021-01-17 16:49

    This isn't a full answer, but the only way I know of to put a float into binary is with pack()

    0 讨论(0)
提交回复
热议问题