[comp.lang.perl] Even Parity Table Generation

rbj@uunet.UU.NET (Root Boy Jim) (02/09/91)

I needed an even parity table, so I decided to generate it recursively.
I thought people might be interested in my solution, and or
commenting on how it might be done better. And while I'm at it,
I hereby request another function: chr(), the opposite of ord().
Either that, or get rid of ord. Anyway, here it is:

print time,"\n"; &mkEven(7);
print time,"\n"; &prtEven;
print time,"\n"; exit(0);

sub mkEven # global %even (level)
{
    local($_,$k) = @_;
    $_ || return $even{"\0"} = "\0";            # bottom out
    &mkEven(--$_);                              # lower half
    $_ = 1 << $_;                               # next bit
    for $k (keys %even) {                       # key loop
        $even{pack('c',$_^ord($k))} =           # new key
            pack('c',128^$_^ord($even{$k}));    # new value
    }
}

sub prtEven
{
    for (sort keys(%even)) {
        printf("%x %x\n",ord($_),ord($even{$_}));
    }
}
-- 
	Root Boy Jim Cottrell <rbj@uunet.uu.net>
	I got a head full of ideas
	They're driving me insane

lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (02/12/91)

In article <121817@uunet.UU.NET> rbj@uunet.UU.NET (Root Boy Jim) writes:
: I needed an even parity table, so I decided to generate it recursively.
: I thought people might be interested in my solution, and or
: commenting on how it might be done better. And while I'm at it,
: I hereby request another function: chr(), the opposite of ord().
: Either that, or get rid of ord.

How 'bout:

	sub chr {sprintf("%c",$_[0]);}

: Anyway, here it is:
[recursive solution omitted]

I'd just say:

    #!/usr/bin/perl
    for (0 .. 127) {
	$bits = unpack('B8',pack('C',$_));
	printf "%x %x\n", $_, $_ | ((($bits =~ tr/1/1/) & 1) << 7);
    }

or maybe

for (0 .. 127) {
    $bits = unpack(B8,pack(C,$_));
    $bits =~ s/0/1/ if $bits =~ tr/1// & 1;
    printf "%x %x\n", $_, unpack(C,pack(B8, $bits));
}

(Requires 3.0 patchlevel 44.)

Larry

rbj@uunet.UU.NET (Root Boy Jim) (02/12/91)

In article <11387@jpl-devvax.JPL.NASA.GOV> lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) writes:
>In article <121817@uunet.UU.NET> rbj@uunet.UU.NET (Root Boy Jim) writes:
>: I hereby request another function: chr(), the opposite of ord().
>: Either that, or get rid of ord.
>
>How 'bout:
>
>	sub chr {sprintf("%c",$_[0]);}

Yes, I know that it can be done that way, or I can use pack, as I did.
I suppose I can use use vec. Which is most efficient?

However, I would rather have one primitive to SAY WHAT I MEAN rather than
having to simulate it from a subroutine call and a more general primitive.

I have heard that ord preceded pack/unpack and that's why it's there.

>: Anyway, here it is:
>[recursive solution omitted]
>
>I'd just say:
>
>[iterative solution deleted]

Well, if we want to slice bits, how about:

#!/usr/bin/perl  
for (0 .. 127) { 
	$x = $_; 
	$_ ^= $_>>4; 
	$_ ^= $_>>2; 
	$_ ^= $_>>1;  
	printf "%x %x\n", $x, $x ^ (($_ & 1) << 7);
} 
-- 
	Root Boy Jim Cottrell <rbj@uunet.uu.net>
	I got a head full of ideas
	They're driving me insane

allbery@NCoast.ORG (Brandon S. Allbery KB8JRR) (02/14/91)

As quoted from <121817@uunet.UU.NET> by rbj@uunet.UU.NET (Root Boy Jim):
+---------------
| I hereby request another function: chr(), the opposite of ord().
| Either that, or get rid of ord. Anyway, here it is:
+---------------

sub chr { pack('c', @_[$[]); }

++Brandon
-- 
Me: Brandon S. Allbery			    VHF/UHF: KB8JRR on 220, 2m, 440
Internet: allbery@NCoast.ORG		    Packet: KB8JRR @ WA8BXN
America OnLine: KB8JRR			    AMPR: KB8JRR.AmPR.ORG [44.70.4.88]
uunet!usenet.ins.cwru.edu!ncoast!allbery    Delphi: ALLBERY

ccplumb@rose.uwaterloo.ca (Colin Plumb) (02/14/91)

rbj@uunet.UU.NET (Root Boy Jim) wrote:
>I needed an even parity table, so I decided to generate it recursively.
>I thought people might be interested in my solution, and or
>commenting on how it might be done better. And while I'm at it,
>I hereby request another function: chr(), the opposite of ord().
>Either that, or get rid of ord. Anyway, here it is:

Yes, I'd like chr() (or whatever someone wants to call it), too.

Anyway, there's a simple iterative way to generate bit-couting tables,
parity tables, etc.

bits[0] = 0;
for (i = 1; i < 256; i++)
	bits[i] = bits[i>>1] + (i&1);

For your parity application, it's just:

even[0] = 0;
for (i = 1; i < 128; i++)
	even[i] = i + ((even[i>>1]&128) ^ (i & 1 ? 128 : 0));

There are various tricky ways of rewriting that last line.  I think
	even[i] = i + (128 & (-(i & 1) ^ even[i>>1]));
is rather fun on a non-sign-magnitude machine.

In (untested) perl, that becomes:

sub mkEven # global %even
{
	local($i);
	$even{"\0"} = "\0";
	for $i (1..127) {
		$even{pack('c',$i)} = pack('c',$i +
		  (($i & 1) ? 128 : 0) ^ (128 & $even{pack('c',$i>>1)}));
	}
}

Well, okay, it's hideous...  Using a temporary array,
sub mkEven # global %even
{
	local($i,@even);
	$even[0] = 0;
	$even{"\0"} = "\0";
	for $i (1..127) {
		$even[$i] = ((i & 1) << 7) ^ $even[$i >> 1];
		$even{pack('c',$i)} = pack('c', $i + $even[$i]);
	}
}
-- 
	-Colin

shaw@paralogics.UUCP (Guy Shaw) (03/12/91)

One non-recursive way to generate a parity table is to count through the
character set in (binary reflected) Gray code order.  Since the successor
of any Gray code number changes only one binary digit, the parity will
flip back and forth between even and odd.

#! /usr/local/bin/perl

# For purposes of demonstration,
# print out the first 32 Gray code numbers

print "bin gray\n";
print "--- ---\n";
for $i (0..31) {
    printf "%3x %3x\n", $i,$i^($i>>1);
    }
print "\n";

&MakeEvenParityTable;

# Generate full 256-entry even parity table,
# but just print the first 32

for $i (0..31) {
    printf "%3x %3x\n", $i,$even[$i];
    }
exit 0;

sub MakeEvenParityTable {
    local($bin,$gray,$parity);
    $even[0] = 0;
    $parity = 0;
    for $bin (1..255) {
        $gray = $bin ^ ($bin>>1);
        $parity = $parity ^ 128;
        $even[$gray] = $gray | $parity;
        }
    }
-- 
Guy Shaw
Paralogics
paralogics!shaw@uunet.uu.net  or  uunet!paralogics!shaw