Perl Monk, Perl Meditation PerlMonks

5x6-bit values into/out of a 32-bit word

by BrowserUk (Pope)
 on Mar 18, 2007 at 00:39 UTC Need Help??
BrowserUk has asked for the wisdom of the Perl Monks concerning the following question:

How would you do this in Perl?

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.
• Comment on 5x6-bit values into/out of a 32-bit word

Replies are listed 'Best First'.
Re: 5x6-bit values into/out of a 32-bit word
by Thelonius (Priest) on Mar 18, 2007 at 01:26 UTC
```#!perl -w
use strict;
my \$fmt = "0b" . ("%06b" x 5);

sub b5ToInt { oct sprintf "0b%06b%06b%06b%06b%06b", @_ }

sub intToB5 {
map { oct "0b\$_" } unpack "(a6)5", sprintf "%030b", \$_[0]
}

my \$word = b5ToInt(1,2,3,4,5);
printf "word = %d = 0x%08x = 0b%030b\n", \$word, \$word, \$word;

my @out = intToB5(\$word);
print "out = ", join(", ", @out), "\n";
Output:
```word = 17314053 = 0x01083105 = 0b000001000010000011000100000101
out = 1, 2, 3, 4, 5
Okay, the C programmer in me rebelled against the inefficiency of my earlier reply. How about:
```sub b5ToInt {
use integer;
return     (\$_[4]||0)
+ ((\$_[3]||0)<<6)
+ ((\$_[2]||0)<<12)
+ ((\$_[1]||0)<<18)
+ ((\$_[0]||0)<<24);
}
sub intToB5 {
use integer;
my \$in = int(shift);
return map { \$_ & 0b111111 }
((\$in >> 24),
(\$in >> 18),
(\$in >> 12),
(\$in >>  6),
\$in);
}

The C programmer in you may rail against the inefficiency of your first solution, but this solution has you doing a pile of work that would be more efficiently handled by the computer. Get it to calculate those multiples of 6, it's better at that than you are. Factor that out, and your code will shrink.

And should the requirements ever change, you'll have much less code of your own to change. That's a much better form of effciency worth seeking.

• another intruder with the mooring in the heart of the Perl

Re: 5x6-bit values into/out of a 32-bit word
by ikegami (Pope) on Mar 18, 2007 at 01:30 UTC
Assuming the following bit layout:
```0055 5555 4444 4433 3333 2222 2211 1111
One way:
```# Get individual num:
\$num = (\$aggregate >> (\$i*6)) & 0b111111;

# Set individual num:
\$aggregate = (\$aggregate & ~(0x3F << (\$i*6))) | (\$num << (\$i*6));

Update: Added missing ~.
Update: Thelonius's newer post shows how to use this method to get/set all the nums at once.

Re: 5x6-bit values into/out of a 32-bit word
by grinder (Bishop) on Mar 18, 2007 at 09:22 UTC

I'd do it this way. Encapsulate and abstractulate as appropriate:

```my \$num = shift;
my \$bits = 6;
my \$mask = (1 << \$bits) - 1;

my @out = map {
(\$num & \$mask << \$_ * \$bits)
>> \$_ * \$bits
} 0..\$bits-1;

update: oops, the map 0 .. \$bits-1 is just a fortunate accident of 5 == 6-1. The following is better:

```my \$num    = shift;
my \$groups = 5;
my \$bits   = 6;
my \$mask   = (1 << \$bits) - 1;

my @out = map {
(\$num & \$mask << \$_ * \$bits)
>> \$_ * \$bits
} 0..\$groups-1;

2nd update: oh, and you want to go back the other way. That's even easier:

```my @in  = (30, 14, 27, 2, 17);
my \$width  = 6;

my \$offset = 0;
my \$out = 0;
\$out |= (\$_ << (\$offset++ * \$width)) for @in;

• another intruder with the mooring in the heart of the Perl

Re: 5x6-bit values into/out of a 32-bit word
by Skeeve (Vicar) on Mar 18, 2007 at 19:01 UTC

I'd use a 4 Byte String and vec.

Update: Sorry... Didn't notice that vec is just for powers of 2 :-(

s\$\$([},&%#}/&/]+}%&{})*;#\$&&s&&\$^X.(\$'^"%]=\&(|?*{%
+.+=%;.#_}\&"^"-+%*).}%:##%}={~=~:.")&e&&s""`\$''`"e

Create A New User
Node Status?
node history
Node Type: perlquestion [id://605324]
Approved by kyle
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others lurking in the Monastery: (6)
As of 2018-03-17 19:26 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
When I think of a mole I think of:

Results (225 votes). Check out past polls.

Notices?