Need help with pack

K

kj

I want to write the function to_bits that takes a floating point
number as argument and returns an array of 32 ones or zeroes,
corresponding to the bits of the input argument.

I have been staring at the docs for pack and unpack for a while
now trying to figure out how to use them to do this and I am as
clueless about it as I was when I first started. Also, perlpacktut
was no help either [1].

If someone could please tell me how to generate an array of one's
and zeros corresponding to the bits in a floating point number I'd
be very grateful.

kj

[1] Lest I appear very lazy or very stupid, I should point out that
I generally have *no problem* understanding the documentation for
Perl built-in functions. pack is a very exceptional case. It is
the only Perl function that I consider mysterious in the least.
I wish I could convey my bewilderment upon reading the docs for
pack. From the very first sentences it is as if I were reading
some English-like code in which all words mean something different
from what I think they should mean. As I said, the tutorial is no
help, because ultimately the tutorial just gives cookbook recipes
which I can follow, but I have no idea what I'm doing. If what I
need to do is not described in one of the recipes, then *I have no
idea* of how to devise my own recipe.
 
J

John W. Krahn

kj said:
I want to write the function to_bits that takes a floating point
number as argument and returns an array of 32 ones or zeroes,
corresponding to the bits of the input argument.

I have been staring at the docs for pack and unpack for a while
now trying to figure out how to use them to do this and I am as
clueless about it as I was when I first started. Also, perlpacktut
was no help either [1].

If someone could please tell me how to generate an array of one's
and zeros corresponding to the bits in a floating point number I'd
be very grateful.


$ perl -le' print for unpack q/a/ x 32, unpack q/b*/, pack q/f/, 5.678 '
1
0
1
1
0
1
0
0
0
1
0
0
1
1
0
1
1
0
1
0
1
1
0
1
0
0
0
0
0
0
1
0



John
 
T

tlm

I want to write the function to_bits that takes a floating point
number as argument and returns an array of 32 ones or zeroes,
corresponding to the bits of the input argument.

How about this (untested):

sub to_bits {
my $f = pack 'f', shift;
return reverse map vec( $f, $_, 1 ), 0 .. 31;
}

HTH,

tlm
 
A

A. Sinan Unur

kj said:
I want to write the function to_bits that takes a floating point
number as argument and returns an array of 32 ones or zeroes,
corresponding to the bits of the input argument.

I have been staring at the docs for pack and unpack for a while
now trying to figure out how to use them to do this and I am as
clueless about it as I was when I first started. Also, perlpacktut
was no help either [1].

If someone could please tell me how to generate an array of one's
and zeros corresponding to the bits in a floating point number I'd
be very grateful.

#!/usr/bin/perl

use strict;
use warnings;

print unpack 'b*', pack 'f', 3.45;


Sinan
 
A

Anno Siegel

kj said:
I want to write the function to_bits that takes a floating point
number as argument and returns an array of 32 ones or zeroes,
corresponding to the bits of the input argument.

I have been staring at the docs for pack and unpack for a while
now trying to figure out how to use them to do this and I am as
clueless about it as I was when I first started. Also, perlpacktut
was no help either [1].

If someone could please tell me how to generate an array of one's
and zeros corresponding to the bits in a floating point number I'd
be very grateful.

I'll show how to generate a string (not an array) of zeroes and ones.

You need two steps. First use the "f" template (single-precision float)
to get the four bytes that make up a 32-bit float into a string. If
the number is in $_:

my $str = pack 'f', $_;

Next, unpack the result as a bit string, using the "b" template

my $bits = unpack 'b32', $str;

Run it for a few examples

printf "%.3f -> %s\n", $_, unpack 'b32', pack 'f', $_ for
1/8, 1/4, 1/2, 1, 2, 4, 8;

and see if you can make heads or tails of the output. The bytes may not
be in the expected order. On my machine, I get:

0.125 -> 01111100000000000000000000000000
0.250 -> 01111100000000010000000000000000
0.500 -> 11111100000000000000000000000000
1.000 -> 11111100000000010000000000000000
2.000 -> 00000010000000000000000000000000
4.000 -> 00000010000000010000000000000000
8.000 -> 10000010000000000000000000000000

If you want an array, either split the result in single characters, or
use

map vec( $str, $_, 1), 0 .. 31

instead of unpacking with "b".

Anno
 
K

kj

In said:
kj <[email protected]> wrote in comp.lang.perl.misc:
I'll show how to generate a string (not an array) of zeroes and ones.
You need two steps. First use the "f" template (single-precision float)
to get the four bytes that make up a 32-bit float into a string. If
the number is in $_:
my $str = pack 'f', $_;
Next, unpack the result as a bit string, using the "b" template
my $bits = unpack 'b32', $str;
Run it for a few examples
printf "%.3f -> %s\n", $_, unpack 'b32', pack 'f', $_ for
1/8, 1/4, 1/2, 1, 2, 4, 8;
and see if you can make heads or tails of the output. The bytes may not
be in the expected order. On my machine, I get:
0.125 -> 01111100000000000000000000000000
0.250 -> 01111100000000010000000000000000
0.500 -> 11111100000000000000000000000000
1.000 -> 11111100000000010000000000000000
2.000 -> 00000010000000000000000000000000
4.000 -> 00000010000000010000000000000000
8.000 -> 10000010000000000000000000000000
If you want an array, either split the result in single characters, or
use
map vec( $str, $_, 1), 0 .. 31
instead of unpacking with "b".


Thank you very much. That was very helpful.

BTW, I was surprised to discover that the vec alternative is about
2.5x faster than unpack+split:

0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.1.1.1.1.1.1.0.0
0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.1.1.1.1.1.1.0.0
Rate unp vec
unp 26305/s -- -61%
vec 67622/s 157% --

I give the code below.

kj


use Benchmark 'cmpthese';

$::f = pack 'f', 1;

my $subs = {vec => 'map vec($::f, $_, 1), 0..31',
unp => 'split "", unpack "b32", $::f'};

# check that both work and produce the same result
{
local ($\, $,) = ("\n", '.');
print eval('sub {'.$subs->{ $_ }.'}')->(), "\n" for qw(vec unp);
}

# benchmark
cmpthese -1, $subs;

__END__
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,175
Messages
2,570,942
Members
47,490
Latest member
Finplus

Latest Threads

Top