in reply to Mysteries of unpack("a", ...)

Does this look right for the value in your example?

$n = unpack 'N', pack 'B32', '01000010001111000000000000000000';; ( $s, $c, $e ) = ( $n & 0x8000_0000, (( $n >> 24 ) & 0x7f) - 64, (($n & 0x00ffffff) / 0xffffff) * 16 );; print $s, $c, $e;; 0 2 3.75000022351743 $num = ($s? -1 : 1 ) * $e * 10**$c;; print $num;;

375.000022351743

If so, then the following modification of your subroutine may be what you need:

sub parse_E ($) { my $data = shift; ## The data comes in as a 4-byte string so... $data = unpack 'N', $data; ## We need to treat it as an unsigned i +nteger ## in order to do bitwise math on it my ($sign, $characteristic, $fraction); $sign = ($data & 0x80000000) ? -1 : 1; $characteristic = (($data >> 24) & 0x7f) - 64; $fraction = (($data & 0x00ffffff) / 0xffffff) * 16; ## Not the fraction raised to the power of the characteristic ## my $num = $sign * $fraction ** $characteristic; ## But rather, the fraction * 10 to the power of the characteristic my $num = $sign * $fraction * 10 ** $characteristic; printf("DEBUG: parse_E(%32s)\n\tsign: %d charisteristic: %d ". "fraction: %f = %f\n", unpack ("B32", $data), $sign, $characteristic, $fraction, $num); printf("DEBUG: unpacked characteristic %s\n", unpack ("B7", ($data >> 24) & 0x7f)); printf("DEBUG: unpacked fraction %7s%s\n", " ", unpack ("B24", $data & 0x00ffffff)); return $num; }

Some inferences drawn from here, though it could definitely be more clearly stated.


Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
"Too many [] have been sedated by an oppressive environment of political correctness and risk aversion."

Replies are listed 'Best First'.
Re^2: Mysteries of unpack("a", ...)
by pspinler (Novice) on Jan 03, 2009 at 06:26 UTC

    Yah, that looks right. It didn't occur to me to unpack something I've already unpacked. I ended up grabbing substr's of an unpacked bitstring of my original data, in a rather ugly form.

    And yes, I also had to correct my math. I'll change it back to (presumably more effecient) bit fiddling tomorrow. For now, here's what I've ended up with:

    sub parse_E ($) { my $data = shift; my $databs = unpack ("B32", $data); my $sign = oct ("0b" . substr ($databs, 0, 1)) ? -1 : 1; my $characteristic = oct ("0b" . substr ($databs, 1, 7)) - 64; my $exponent = 16 ** $characteristic; my $fraction = oct ("0b" . substr ($databs, 8, 24)) / 0xfffff +f; my $num = $sign * $fraction * $exponent; return $num; }

    Thanks much!

    -- Pat

      I don't know why you're dividing the fraction part by 0xFF_FFFF, if you want to do it that way you'd surely want to divide by 0x100_0000.

      The following:

      my $f = unpack('N', pack('B32', "01000010001111000000000000000000")) +; printf "0x%08X = %12.9f\n", $f, conv_HFP($f) ; sub conv_HFP { my ($f) = @_ ; my $s = ($f & 0x8000_0000) ? -1 : +1 ; my $e = (((($f >> 24) & 0x7F) - 0x40) * 4) - 24 ; return $s * ($f & 0xFF_FFFF) * (2 ** $e) ; } ;
      will convert 4 byte 360/370 style radix 16 floats (where b31 is sign, b30..b24 is exponent biased by 0x40, and b23..0 is the fraction with binary point to the left of b23). Using the one example I can see the result is:
        0x423C0000 = 60.000000000
      
      From a quick poke around, it appears that floats are stored big-endian.

      I note that you say these are "IBM 390 E format 4 byte floats". The ESA/390 supports both the old 360/370 HFP (hex floating point) and new newer BFP (binary floating point) which conforms to IEEE 754-1985. Converting BFP can be done so:

      my $f = unpack('N', pack('B32', "01000010001111000000000000000000")) +; printf "0x%08X = %12.9f\n", $f, conv_BFP($f) ; sub conv_BFP { my ($f) = @_ ; my $s = ($f & 0x8000_0000) ? -1 : +1 ; my $e = ((($f >> 23) & 0xFF) - 0x7F) - 23 ; return $s * (($f & 0x7F_FFFF) | 0x80_0000) * (2 ** $e) ; } ;
      in the unlikely event your native floating point is not IEEE 754-1985 !! (Otherwise unpack('f', ...), with suitable care over the byte ordering !)