=head1 NAME
-perlfaq4 - Data Manipulation ($Revision: 1.3 $, $Date: 2001/10/03 23:08:02 $)
+perlfaq4 - Data Manipulation ($Revision: 1.9 $, $Date: 2001/12/07 21:17:58 $)
=head1 DESCRIPTION
machines) will work pretty much like mathematical integers. Other numbers
are not guaranteed.
-=head2 How do I convert bits into ints?
+=head2 How do I convert between numeric representations:
-To turn a string of 1s and 0s like C<10110110> into a scalar containing
-its binary value, use the pack() and unpack() functions (documented in
-L<perlfunc/"pack"> and L<perlfunc/"unpack">):
+As always with Perl there is more than one way to do it. Below
+are a few examples of approaches to making common conversions
+between number representations. This is intended to be representational
+rather than exhaustive.
- $decimal = unpack('c', pack('B8', '10110110'));
+Some of the examples below use the Bit::Vector module from CPAN.
+The reason you might choose Bit::Vector over the perl built in
+functions is that it works with numbers of ANY size, that it is
+optimized for speed on some operations, and for at least some
+programmers the notation might be familiar.
-This packs the string C<10110110> into an eight bit binary structure.
-This is then unpacked as a character, which returns its ordinal value.
+=item B<How do I convert Hexadecimal into decimal:>
-This does the same thing:
+Using perl's built in conversion of 0x notation:
+
+ $int = 0xDEADBEEF;
+ $dec = sprintf("%d", $int);
+
+Using the hex function:
+
+ $int = hex("DEADBEEF");
+ $dec = sprintf("%d", $int);
+
+Using pack:
+
+ $int = unpack("N", pack("H8", substr("0" x 8 . "DEADBEEF", -8)));
+ $dec = sprintf("%d", $int);
+
+Using the CPAN module Bit::Vector:
+
+ use Bit::Vector;
+ $vec = Bit::Vector->new_Hex(32, "DEADBEEF");
+ $dec = $vec->to_Dec();
+
+=item B<How do I convert from decimal to hexadecimal:>
+
+Using sprint:
+
+ $hex = sprintf("%X", 3735928559);
+
+Using unpack
+
+ $hex = unpack("H*", pack("N", 3735928559));
+
+Using Bit::Vector
+
+ use Bit::Vector;
+ $vec = Bit::Vector->new_Dec(32, -559038737);
+ $hex = $vec->to_Hex();
+
+And Bit::Vector supports odd bit counts:
+
+ use Bit::Vector;
+ $vec = Bit::Vector->new_Dec(33, 3735928559);
+ $vec->Resize(32); # suppress leading 0 if unwanted
+ $hex = $vec->to_Hex();
+
+=item B<How do I convert from octal to decimal:>
+
+Using Perl's built in conversion of numbers with leading zeros:
+
+ $int = 033653337357; # note the leading 0!
+ $dec = sprintf("%d", $int);
+
+Using the oct function:
+
+ $int = oct("33653337357");
+ $dec = sprintf("%d", $int);
+
+Using Bit::Vector:
+
+ use Bit::Vector;
+ $vec = Bit::Vector->new(32);
+ $vec->Chunk_List_Store(3, split(//, reverse "33653337357"));
+ $dec = $vec->to_Dec();
+
+=item B<How do I convert from decimal to octal:>
+
+Using sprintf:
+
+ $oct = sprintf("%o", 3735928559);
+
+Using Bit::Vector
+
+ use Bit::Vector;
+ $vec = Bit::Vector->new_Dec(32, -559038737);
+ $oct = reverse join('', $vec->Chunk_List_Read(3));
+
+=item B<How do I convert from binary to decimal:>
+
+Using pack and ord
$decimal = ord(pack('B8', '10110110'));
-Here's an example of going the other way:
+Using pack and unpack for larger strings
+
+ $int = unpack("N", pack("B32",
+ substr("0" x 32 . "11110101011011011111011101111", -32)));
+ $dec = sprintf("%d", $int);
+
+ # substr() is used to left pad a 32 character string with zeros.
+
+Using Bit::Vector:
+
+ $vec = Bit::Vector->new_Bin(32, "11011110101011011011111011101111");
+ $dec = $vec->to_Dec();
+
+=item B<How do I convert from decimal to binary:>
+
+Using unpack;
+
+ $bin = unpack("B*", pack("N", 3735928559));
+
+Using Bit::Vector:
+
+ use Bit::Vector;
+ $vec = Bit::Vector->new_Dec(32, -559038737);
+ $bin = $vec->to_Bin();
+
+The remaining transformations (e.g. hex -> oct, bin -> hex, etc.)
+are left as an exercise to the inclined reader.
- $binary_string = unpack('B*', "\x29");
=head2 Why doesn't & work the way I want it to?
=head2 How can I output Roman numerals?
-Get the http://www.perl.com/CPAN/modules/by-module/Roman module.
+Get the http://www.cpan.org/modules/by-module/Roman module.
=head2 Why aren't my random numbers random?
Computers are good at being predictable and bad at being random
(despite appearances caused by bugs in your programs :-).
-http://www.perl.com/CPAN/doc/FMTEYEWTK/random , courtesy of Tom
+http://www.cpan.org/doc/FMTEYEWTK/random , courtesy of Tom
Phoenix, talks more about this. John von Neumann said, ``Anyone who
attempts to generate random numbers by deterministic means is, of
course, living in a state of sin.''
If not, you can use this:
- # fisher_yates_shuffle( \@array ) :
- # generate a random permutation of @array in place
+ # fisher_yates_shuffle
+ # generate a random permutation of an array in place
+ # As in shuffling a deck of cards
+ #
sub fisher_yates_shuffle {
- my $array = shift;
- my $i = @$array;
+ my $deck = shift; # $deck is a reference to an array
+ my $i = @$deck;
while (--$i) {
my $j = int rand ($i+1);
- @$array[$i,$j] = @$array[$j,$i];
+ @$deck[$i,$j] = @$deck[$j,$i];
}
}
- fisher_yates_shuffle( \@array ); # permutes @array in place
+And here is an example of using it:
+
+ #
+ # shuffle my mpeg collection
+ #
+ my @mpeg = <audio/*/*.mp3>;
+ fisher_yates_shuffle( \@mpeg ); # randomize @mpeg in place
+ print @mpeg;
Note that the above implementation shuffles an array in place,
unlike the List::Util::shuffle() which takes a list and returns
This can be conveniently combined with precalculation of keys as given
above.
-See http://www.perl.com/CPAN/doc/FMTEYEWTK/sort.html for more about
+See http://www.cpan.org/doc/FMTEYEWTK/sort.html for more about
this approach.
See also the question below on sorting hashes.
$vec = '';
foreach(@ints) { vec($vec,$_,1) = 1 }
-And here's how, given a vector in $vec, you can
+Here's how, given a vector in $vec, you can
get those bits into your @ints array:
sub bitvec_to_list {
This method gets faster the more sparse the bit vector is.
(Courtesy of Tim Bunce and Winfried Koenig.)
-Here's a demo on how to use vec():
+Or use the CPAN module Bit::Vector:
+
+ $vector = Bit::Vector->new($num_of_bits);
+ $vector->Index_List_Store(@ints);
+ @ints = $vector->Index_List_Read();
+
+Bit::Vector provides efficient methods for bit vector, sets of small integers
+and "big int" math.
+
+Here's a more extensive illustration using vec():
# vec demo
$vector = "\xff\x0f\xef\xfe";
=head2 How can I know how many entries are in a hash?
If you mean how many keys, then all you have to do is
-take the scalar sense of the keys() function:
+use the keys() function in a scalar context:
- $num_keys = scalar keys %hash;
+ $num_keys = keys %hash;
-The keys() function also resets the iterator, which in void context is
-faster for tied hashes than would be iterating through the whole
-hash, one key-value pair at a time.
+The keys() function also resets the iterator, which means that you may
+see strange results if you use this between uses of other hash operators
+such as each().
=head2 How do I sort a hash (optionally by value instead of key)?
=head2 How can I use a reference as a hash key?
-You can't do this directly, but you could use the standard Tie::Refhash
+You can't do this directly, but you could use the standard Tie::RefHash
module distributed with Perl.
=head1 Data: Misc
=head2 How do I keep persistent data across program calls?
For some specific applications, you can use one of the DBM modules.
-See L<AnyDBM_File>. More generically, you should consult the FreezeThaw,
-Storable, or Class::Eroot modules from CPAN. Starting from Perl 5.8
-Storable is part of the standard distribution. Here's one example using
-Storable's C<store> and C<retrieve> functions:
+See L<AnyDBM_File>. More generically, you should consult the FreezeThaw
+or Storable modules from CPAN. Starting from Perl 5.8 Storable is part
+of the standard distribution. Here's one example using Storable's C<store>
+and C<retrieve> functions:
use Storable;
store(\%hash, "filename");