Mastering Algorithms with Perl

Errata for Mastering Algorithms with Perl

Submit your own errata for this product.

The errata list is a list of errors and their corrections that were found after the product was released.

The following errata were submitted by our customers and have not yet been approved or disproved by the author or editor. They solely represent the opinion of the customer.

Color Key: Serious technical mistake Minor technical mistake Language or formatting error Typo Question Note Update

Version Location Description Submitted by Date submitted
Printed Page 1,2
(4,2), and (5,4).

The magnitude of the cross product of the vectors [4,2]x[1,2] is the area of
that parallelogram, which is the determinant.

This *does* correspond to the area of a rectangle (still not a square), but
not one with vertices at (1,2), (4,2). Again, I'll illustrate with a simpler

Draw a parallelogram with vertices (0,0), (1,1), (3,1), (2,0). The area is,
again, given by a determinant built from the components of the vectors [1,1]
and [2,0].

| 1 1 |
| 2 0 |

If you shear the parallelogram top leftwards, you can create a rectangle with
the same area, with vertices at (0,0), (0,1), (2,1), (2,0).

Notice that this is not a rectangle with any vertex at (1,1).

The treatment of "Polygon Area" on pp. 430-432 assumes this section is
correct, and so also needs a rewrite.

Printed Page 1, 2, 2, 5, 3, 1, 2, 1
hangs the algorithm.

Printed Page 2, 3
(i.e. a reference to an anonymous array, effectively, since any private

variables will have passed out of scope), which would be more unwieldy than
returning the median. This would mean that either single modes would have to
be passed back in referenced arrays or as scalars, with the programmer than
differentiating between a reference and a numeric scalar themself, both of
which are somewhat more difficult than the current option. However, this
*would* be the correct answer, since the mode is *all* of the most common
values, and not just the median thereof.

I hope this is of some use, even if it means a far more unwieldy algorithm
being used, or presented as an alternative use.

PDF Page 2+3, prob. others too
Code section for BINARY-SEARCH algorithm, lines 2/3/4/6/8

The leftward arrows found in the printed version of the book aren't displayed correctly or at all in multiple PDF reader applications: Preview v5.0.3, Adobe Acrobat Pro v11.0.04, Adobe Acrobat Pro 10.1.8 on Mac OS X 10.6.8 = nothing displayed at all (looks like a double space there), iBooks v3.1.1 on iOS 5.1.1 = replaced with X in a rectangle symbol. Probably the same also in other code listings throughout the book where this arrow is used.

Julian R.  Sep 22, 2013 
Printed Page 3
pseudocode, line 6

"try" should be "try-1."

Printed Page 3,3
and (2,3) (d) (2,3), 0,3) and ((0,2). Now the areas of these triangles are 0.5,

2, 0.5 and 1 sq. units respectively. So the area of the pentagon is 9 - (0.5+2+0.5+1)
= 5.

Also, there is a better algorithm for finding the area of a polygon.
Stated simply, it is as follows:
1. List the points in order (clockwise or anti-clockwise)and append the first point
to the end of the list.
2. Against each point tabulate product of y value against the x value of the previous
3. Against each point tabulate the product of x value against the y value of the
previous point.
4. Sum the tabulations and take half of the diffrence of these sums,
which is the area of the polygon.

Example: Polygon (0,1), (1,0), (3,2), (2,3) and (0,2).

x y
0 1
1 1 0 0
0 3 2 2
0 2 3 9
4 0 2 4
0 0 1 0
5 15

The area of the polygon is abs(15 -5)/2 = 5.

This works all polygons, whether convex or concave.
This algorithm is quite easy to implement also!

Printed Page 9
last line

There's an extra "with".

Printed Page 12
Comment in quadratic() function

The comment "Compute the larger root of a quadratic polynomial" isn't correct.
The root found isn't necessarily the larger one. For instance:

f(x) = -x^2 + 2x + 3

The roots are 3 and -1, and the subroutine will return -1.

Printed Page 12
last line of the code sample

I believe the last line of the code sample contains an error. My copy of the
book has:

bruteforce => 'forloop(0, 1)' });

However, I believe that the word forloop should be changed to "bruteforce" so
the code looks like:

bruteforce => bruteforce(0, 1)' });

Other Digital Version 21
Online code sample

The correction of the constant from 1.5... to 6.28318530718 has not been made in the code "factorial" provided online.

Also, the recursive and approximate versions return 0 for the value of 0!, rather than 1.

(I will try to provide corrected code later.)

Anonymous  May 14, 2012 
Other Digital Version 21

Revised version of "factorial_recursive" and "factorial_approx"

#! /usr/bin/perl
use 5.10.0;

my $n = 3;
say factorial($n);
say factorial_recursive($n);
say factorial_approx($n);

## factorial($n) computes the factorial of $n,
# using an iterative algorithm.
sub factorial {
my ($n) = shift;
my ($result, $i) = (1, 2);
for ( ; $i <= $n; $i++) {
$result *= $i;
return $result;

# factorial_recursive($n) computes the factorial of $n,
# using a recursive algorithm.
sub factorial_recursive {
my ($n) = shift;

return $n * factorial_recursive($n - 1) if $n > 2;
return 1 if $n == 0;
return $n if $n <= 2;

sub factorial_approx {
return 1 if $_[0] == 0;
return sqrt (6.28318530718 * $_[0]) *
(($_[0] / 2.71828182845905) ** $_[0]);

Anonymous  May 14, 2012 
Printed Page 84

Original print

# ? $cmp->($val, $tree->{val})
# : $val <=> $tree->{val};

should be

? $cmp->($tree->{val},$val)
: $tree->{val} <=> $val;
if ( $relation != 0 ) {
# Not this node, go down the tree.

Anonymous  Mar 20, 2012 
Printed Page 85
5th line from top

The comment says "node" could be undef, but it can't.

Printed Page 112
Fourth code block:

need a space before the closing paren.

Printed Page 129
Source code for Insertion Sort

The source code for Insertion Code has Theta(N^2) best-case performance, not Theta(N) as described in the paragraph below. The outer loop ALWAYS runs from 0 to N-1 and, for each iteration, the inner loop runs from i+1 to N-1, for a total of N*(N-1)/2 comparisons (regardless of the distribution of the input data).

Carlos Joa  Jan 09, 2015 
Printed Page 133
middle of figure 4-6

caption for "d" should be "shell = 2"

Printed Page 136

The statements "my $high = $index * 2 + 1" and "my $try = $index * 2" should be changed to instead read "my $high = $index *2 + 2" and "my $try = $index * 2 + 1".

When I run the sample code that I downloaded from the site, it produces the correct final output. But upon closer inspection, the intermediate state is wrong. Check the order of @$array after the first pass in heapsort(), but before the second pass (that is, after the first foreach loop containing the first call to heapify(), but before the second foreach loop containing the second call to heapify()). There are two instances where the parent is not larger than one of its children, but should be.

In case the sample code on the site has changed, the sample input it was using (when I downloaded it) was, "I have a holographic chocolate bar. No really. I'm supposed to save it because it's like art or something. But I'm really hungry and I've been checking these examples all day. I think I deserve a reward."

I'm not sure whether minor errors the intermediate state ultimately don't matter, and if the second heapify() pass will always smooth them out, or if we just got lucky with the sample input that was chosen.

Paul DeLong  Jul 20, 2009 
Printed Page 146
the fourth line of the source code

for ( my $i = length $array->[ 0 ] - 1; $i >= 0; $i-- ) {
seems should be
for ( my $i = length ($array->[ 0 ]) - 1; $i >= 0; $i-- ) {

Printed Page 156
It says that Shell's sort is stable, it isn't unless the only h-sort

pass is h=1, which would then be called Insertion Sort, and that is not
Shell's sort. If you don't believe me, se Table 1 P.382 of "The Art...,
Volume 3: Sorting and Searching", 2nd Ed. Also, there is a missing ')' on the
Shell's sort line of Table 4-2.

Printed Page 163
source code in

The @keywords array is not sorted even when they say on page 162:

The prerequisite for a binary search is that the
collection must be already sorted.

Printed Page 163
sub binary_string function

In the subroutine binary_string:

my ($low, $high) = (0, calar@$array));

should be:

my ($low, $high = (0, scalar(@$array));

Printed Page 196
middle of table

30km should be 12km.

Printed Page 196
middle of table

20 min. should be 8 min.

Anonymous  Feb 16, 2015 
Printed Page 200
Chart and first line of text following chart

The conclusion for the branch and bound algorithm states that the best route
goes thru Wolfbane Corners. It should be Sula Junction. Also, the run chart
shows the cost of urchin -> wolfbane corners -> sula center to be 44, it
should be 46.

Printed Page 200
1st paragraph

Best route from Urchin to Sula Center is to go through "Sula Junction", not
through "Wolfbane Corners." And, on the chart right above the paragraph, the
'Cost So Far' column of the route Urchin->Wolfbane Corners -> Sula Center
should be 56, not 44 as in the book, nor 46 which a reader pointed out on the
unconfirmed errata.

Printed Page 205
4th line from bottom

delete $Mammal { platypus } # Nor is platypus a mammal

This is incorrect; the Platypus is a mammal. It is warm blooded, has fur and

Printed Page 215
middle of the page

The second and third versions of sub union() are wrong.

The expected return value is a hashref where
the keys are the elements of the set and the
values are either undef or 1 or anything - it does not matter.

The anonymous hash that is returned from the
second and third versions of union() is initialized
with keys only, no values. The value of
the first key would be the second key. Not what
was intended!

Something like this would be correct:

sub union {+{
map { $_, () }
map { keys %$_ }

Printed Page 245
3rd paragraph

The line:

(Perl Data Language) module, a huge package...

should be

PDL (Perl Data Language) module, a huge package...

Anonymous  Feb 16, 2015 
Printed Page 246
last two lines

"$row" and "$column" should be switched.

should read:

$elem = at($matrix, $column, $row); # access

set($matrix, $column, $row, $value); # modify

Printed Page 262
3rd paragraph under "Computing the Determinant"

"A 2x2 matrix defines a square (and the determinant gives
its area)"

I think this is confused.

A 2x2 matrix defines a parallelogram. The easiest ones to think about are
ones with only positive values for the coordinates, so I'll do that case.

The pair (1,2), (4,2) defines a parallelogram whose vertices are at (0,0),

Printed Page 277
I think the display of ASCII representation on the graph

print "g = $g

should be:

print "g = $g

Printed Page 277
2nd paragrah

I also agree with another readers' comment that the ASCII representation for Figure 8-4 should be:

g = a-c,b-c,c-d

There's no edge defined between vertices a and b. The inclusion of a-b in the list of edges is incorrect.

Printed Page 290
Figure 8-24

Found this in the August 1999 edition of the book:

The {Pred} part in the Perl representation of Graph G is possibly incorrect, IMHO.

It should be:

$G->{Pred}->{c} = ['a']


$G->{Pred}->{d} = ['c', 'c', 'b']

instead of

$G->{Pred}->{c} = ['a', 'b']


$G->{Pred}->{d} = ['c', 'c']

Printed Page 299
Final paragraph

The "" operator is not overloaded in the base class. Delete
from the word "all" to the end of the line in the first sentence
of the final paragraph. The complete first sentence of the
final paragraph should read:

We overload the "" operator in the two derived classes, Graph::Directed
and Graph::Undirected.

Printed Page 311
Paragraph 3

Now reads:

"at most two of the vertex degrees If there are...",

Should read:

"at most two of the vertices have odd degrees. If there are..."

Printed Page 315
Figure 8-17

error in the First Edition, Aug 1999

Since there is no node 'f' in the picture,
there should be no node 'f' mentioned in the annotations.

Printed Page 321
sample code articulation_points

Code fragment below is in Error. The line:

my $v = $T[ -$i ];

is wrong, should be:

my $v = $S[ -$i ];

I tested and works fine.

my $articulate =
sub {
my ( $u, $T ) = @_;

my $ap = $T->{ vertex_found }->{ $u };

my @S = @{ $T->{ active_list } }; # Current stack.

$T->{ articulation_point }->{ $u } = $ap
unless exists $T->{ articulation_point }->{ $u };

# Walk back the stack marking the active DFS branch
# (below $u) as belonging to the articulation point $ap.
for ( my $i = 1; $i < @S; $i++ ) {
my $v = $T[ -$i ];

last if $v eq $u;

$T->{ articulation_point }->{ $v } = $ap
if not exists $T->{ articulation_point }->{ $v } or
$ap < $T->{ articulation_point }->{ $v };

Printed Page 326-329
Reading through the section on Kruskal's Algorithm (also known as

the Greedy Algoithm), I was perusing the pseudo-code for it, page 326. The
worked example, on page 328, does not appear to be in error, but the
pseudo-code is, somewhat.

Assuming that I have the following graph:

A-B 2
A-B 4
A-C 2
B-C 2

Using the pseudo-code, I take an edge in my graph, G, that would not create a
cycle - I choose A-B with a weight of 4, which is perfectly legitimate by the
pseudo-code, which specifies nothing else. As my next edge, I choose A-C with
a weight of 2. Both of the other edges create cycles, so I finish. I now
have my Minimum Spanning Tree with a total weight of 6, which is clearly
wrong, since A-C 2 and B-C 2 (as one option) create an MST with a weight of 4.

The pseudo-code needs to be altered to reflect the fact that, when passing
through the list of edges, they need to be taken in weight order, starting
with the least and working upwards, with any edges of equal weight having an
arbitrary order (e.g. if I were to be listing my edges above in weight order,
it would be inconsequential whether I listed B-C 2 before A-C 2).

As I say, the worked example on 328 reflects this perfectly, and the code
MST_Kruskal on page 329 contains the section "Sort by weights", so hopefully
no-one has been confused, but I thought I should submit this for completeness
sake, given that some of those reading the section may never have encountered
Kruskal's algorithm in a non-computer based setting and so may be confused by
the disparity. I hope this is of use.

Printed Page 343
transitive-closure pseudocode

n[ i ][ j ] =
m[ i ][ k ] ||
( m[ i ][ k ] && m[ k ][ j ] )

should be:

n[ i ][ j ] =
m[ i ][ j ] ||
( m[ i ][ k ] && m[ k ][ j ] )

Printed Page 344
After the comment # Do the O(N**3) loop

I think there is a significant optimization to be had in

The speedup is sufficient (hours become minutes, in my case), that it could be
construed as an error.

Consider the central loop:

# Do the O(N**3) loop.
for ( my $k = 0; $k < @V; $k++ ) {
my @nC = ( '' ) x @V; # new @C

for ( my $i = 0; $i < @V; $i++ ) {
for ( my $j = 0; $j < @V; $j++ ) {
vec( $nC[ $i ], $j, 1 ) =
vec( $C[ $i ], $j, 1 ) |
vec( $C[ $i ], $k, 1 ) & vec( $C[ $k ], $j, 1 );

@C = @nC; # Update the closure.

I believe that

1) The adjacency matrix C can be modified in-place, and more significantly: 2)
The the vec( $C[ $], $k, 1) test can be broken out of the innermost loop. This
can be much faster.

The modified code would look something like:

# Do the O(N**3) loop.
for ( my $k = 0; $k < @V; $k++ ) {
for ( my $i = 0; $i < @V; $i++ ) {
next unless vec( $C[ $i ], $k, 1 );
for ( my $j = 0; $j < @V; $j++ ) {
vec( $C[ $i ], $j, 1 ) |= vec( $C[ $k ], $j, 1 );

Printed Page 362
2nd paragraph of Rabin-Karp

256**80 is shown as about 4.6e193, should be 4.6e192.

(It's still large.)

Ben Nathanson  Jun 15, 2016 
Printed Page 366
Figure 9-1

Modulus in figure 9-1 is different from the modulus in the text (8355961 vs 8355967).

Ben Nathanson  Jun 15, 2016 
Printed Page 369
The authors appear to claim that the unpack('%32C*', $P) construct is

equivalent to Rabin-Karp. In fact, the Perl construct only sums the ascii
values of each character in the string and is thus much weaker than RK.

Printed Page 370
penult paragraph ("We will implement...")

"We define next[$j]...such that the suffix of length $k-1 is still a proper suffix of the pattern." Should the second "suffix" be "prefix"? And might be clearer if "text" were inserted before the first "suffix".

Ben Nathanson  Jun 15, 2016 
Printed Page 370
last paragraph

"In Figure 9-3..." Suspect that's a typo for Figure 9-2 (9-3 shows the result after the skip).

Ben Nathanson  Jun 15, 2016 
Printed Page 372
2nd section of code ... knuth_morris_pratt


my $m = knuth_morris_pratt_next( $P );
my ($n, $i, $j) = (length($T), 0, 0);
my @next;


my ($m, @next) = knuth_morris_pratt_next( $P );
my ($n, $i, $j) = (length($T), 0, 0);

Printed Page 389
This isn't so much errata as just out of date. Text::Metaphone is listed

as "still experimental". It has been out of alpha and stable since January.
If you would remove the note about it being experimental I'd appreciate it,

Printed Page 389
In the code example for using Text::Metaphone, the function is

Metaphone() with a capital M.

$metaphone_a = Metaphone $a;
$metaphone_b = Metaphone $b;

Printed Page 389

Now reads:

Soundex trades precision for space/time simplicity

Shouldn't it be:

Soundex trades precision for space/time/simplicity

Printed Page 399
first paragraph

the source of p. 403:

- does not give most error messages.

- does not work with the example query of p.399 abc and not (def or ghi)

- when you type a non-gramatical string or simply a query with (), it hungs up
and does not process any other string from <STDIN>.

Printed Page 403
the code

The url:


...on the errata web page should change to:


Anonymous  Feb 10, 2015 
Printed Page 406
3/5 down the page, definition of @token

The token INTEGER will not match 0. Perhaps this is an old example supplied
with the module, or perhaps it could be renamed to POSITIVE_INTEGER (or
NATURAL) to match its function.

Printed Page 415
second example

#!/usr/bin/perl -pi.bak
s/(x10)(.)(.)/ $2 x (ord($3) || 256) /eg;
should be:
#!/usr/bin/perl -pi.bak
s/(x10)(.)(.)/ $2 x (ord($3) || 256) /seg;

Printed Page 419
next to last line of code

The code snippet:

$a->{value} <=> $b->{value}

gives a warning (non-numeric in ncmp) because the value is sometimes a string,
not a single character. [This is online in the file ch9/huffman.]

Also, in the online example, in ch9/huffman-example, sub get_bit is defined as:

sub get_bit {
return $bit{shift @bits};

but this generates a "Use of unitialized value" warning when it runs off the
end of @bits. Instead, something like this is warranted:

sub get_bit {
defined( @bits ) ? return $bit{shift @bits} : undef;

Printed Page 420
top picture

The picture erroneously has an "a" in the left child of the root node where it
should apparently be an "f".

Printed Page 421
1st paragraph

If my memory serves, gzip/pkzip and compress are two entirely different algorithms. The former is based on the 1977 paper. The latter is based on their 1978 paper and Welch's 1984 paper. I don't recall if someone proved that the two algorithms are equivalent; but at the very least, Welch's 1984 paper isn't revising the 1977 paper -- they're different algorithms.

Printed Page 432
Paragraph 5 from bottom. Area of example pentagon.

The area of example pentagon formed by points (0,1), (1,0), (3,2), (2,3) and (0.2) is
5 and not 2 as stated. It is quite easy to verify that. The pentagon given is
enclosed in a square formed by (0,0), (3,0), (3,3) and (0,3) whose area is, of
course, 9. In this square, apart from the pentagon, there are 4 right angled
trianlges given by (a) (0,0),(1,0) and (0,1) (b) (1,0), (3,0) and (3,2) (c) (3,2),

Printed Page 455
Code Block Near: "# Backtrack: while there are right turns or no turns, shrink

the hull.";
while (
clockwise( $x[ $h[ $#h - 1 ] ],
$y[ $h[ $#h - 1 ] ],
$x[ $h[ $#h ] ],
$y[ $h[ $#h ] ],
$x[ $i ],
$y[ $i ] ) < epsilon

Should read:

while (
clockwise( $x[ $h[ $#h - 1 ] ],
$y[ $h[ $#h - 1 ] ],
$x[ $h[ $#h ] ],
$y[ $h[ $#h ] ],
$x[ $i ],
$y[ $i ] ) > epsilon

Note greater than/less than symbols

clockwise returns negative for left and positive for right, thus if the code reads
"less than epsilon", and epsilon is an non negative value, the code will pop elements
of the hull.

Printed Page 455
Code block near: "# Interlace x's and y's of the hull back into one list, and

return map { ( $x[ $_ ], $y[ $_ ] ) } 0 .. $#h;

Should read:

return map { ( $x[ $_ ], $y[ $_ ] ) } @h;

In the first case the wrong values are used, namely all elements of @x and @y up to
$#h. The correct version uses the values contained in @h as the indices into @x and
@y as desired.

Printed Page 461
9th line from bottom

The if() statement lacks a check for the "equality" case, so closest_points

Printed Page 465
GD Section

GD no longer works with GIF files. PNG is the new format.

Printed Page 465
within GD subsection, second last line of code example

print GIF $gif;

should read:

print GIF $gif->gif;

Otherwise, the file will not correctly as a GIF. It will just write as ascii
with jibberish.

Printed Page 473
both blocks of code


Use of epsilon in comparing two floating point numbers for (approximate)
equality is incorrect in both code blocks and for the same reason each
time. Also there is textual error.

This refers to the August 1999 first edition of the book.


The authors write

if (abs($value1 - $value2) < epsilon) { # They match ...

However the correct code is

if (abs($value1 - $value2) < abs($value1 * epsilon)) {

It is incorrect to compare a raw difference to epsilon. Rather one must
compare a scaled difference (ie., divide the difference by $value1 or
$value2). That's what my correction accomplishes (and does so in a way that
is not subject to divide by zero errors).

Technically, epsilon is the smallest distinguishable difference relative to
one (not zero, as the claimed in the book -- middle of p. 473 -- this is
another error to correct). Thus for comparison to epsilon, one needs to use
differences normalized or scaled to one.

For more about epsilon, see Numerical Recipes in C (2nd ed.). Also, see
Bruce Bush's The Perils of Floating Point HTML page

Printed Page 474
2nd code block, the floor function

According to the definition in my ancient K&R: "largest integer not greater
than x, as a double"

The sub provided rounds UP for negative numbers. This is not a direct
replacement for the POSIX floor/ceil functions as implied in the text.

Printed Page 482
<INFO> There's a program snippit for calculating how many of the bits in

your computer are ones. Other than the obvious "you need to be root to do
this", on some hardware architechtures this is a *really bad idea* that will
cause you pain. I once spent several hours pounding my head into a wall with
an hp300, where the machine would crash when trying to use its serial card,
but only if the X server had been started. I had to resort to my guru to
figure this one out, and he had to scratch his head for a minute before he
figured it out.

Turns out the hp300 maps device memory into the first 16 mb of /dev/mem, and
the serial card in question uses activate on read registers. X's magic cookie
auth generates its random number seed by checksumming /dev/mem. Reading from
/dev/mem caused the card to change state without the OS knowing about it. Oops.

Printed Page 483
sub base { }

print base(17, 9, 2) ,"
print base(10000,2,9) ,"


print base("fff", 16, 3) ,"
print base(12121200,3,16),"


print base("g", 17, 10) ,"
print base(16 , 10, 17) ,"


print base(121,10,15),"
print base(132,10,15),"


====> get result as below




# May change as below

# Convert the number form base 10 to $outbase.
# logbase() is defined below.
for($i=int(logbase($realnum, $outbase)); $i>= 0; $i--) {
$digit = int($realnum / ($outbase ** $i));
$realnum -= $digit * ($outbase ** $i);
if($digit >=10)
#if(ord($digit) >57 )
# {
# $digit = ord($digit +49) ;
# }
$output .=$digit;

# To Get the result as below:





Printed Page 518
exp_fast subroutine code

In the code for the non-recursive exponential subroutine "exp_fast" there is a
block that tests whether or not the variable representing the power is odd. At
the end of this conditional block the variable ($j) is decremented, which
would cause it to become an even number. Presumably this is done so that the
division by 2 which immediately follows does not coerce $j into a
floating-point number. This would be Perl's normal behavior, however, since
the entire subroutine falls under the scope of a "use integer" pragma there is
no danger of integer-to-float conversion. Consequently, the $j-- is not needed.

Printed Page 523
sub collatz routine

$seen{$n} should be 'my'-ed in the subroutine.

Printed Page 540
within sub one_time_pad ()

The expression:

seek PAD, 2, -$pos or return undef;

is wrong. The order of the arguments to seek are transposed. The correct
expression is:

seek PAD, -$pos, 2 or return undef;

Also, since the sub makes use of sysread (), the appropriate seek function
is sysseek (). Therefore, the expression should be:

sysseek PAD, -$pos, 2 or return undef;

Better would be:

return undef unless sysseek( PAD, -$pos, 2 );
return undef unless sysread( PAD, $key, $len ) == $len;

Good practice is to always check the return value of system calls.

Wm. Schmidt  Jun 22, 2020 
Printed Page 541
bottom, subroutine rot13

Instead of:
$val = tr/a-zA-Z/n-za-mN-ZA-M/;
should be:
$val =~ tr/a-zA-Z/n-za-mN-ZA-M/;

Printed Page 557
code block at top of page

The extract subroutine builds up the extracted message in the lexical variable
$message, but doesn't return it. This line should be inserted at the end of
the extract subroutine:

return $message;

Printed Page 584

smartie_weight = 0;
@smartie_order = sort { $dist->{$a} <=> $dist->{$b} } keys %smartie_weights;
for (@smartie_order) { $smartie_weight += $smartie_weight{$_} }

As it is right now, @smartie_order would contain nothing since $dist is a part
of the subroutine rand_dist_weighted.

It should read:

@smartie_order = sort { $smartie_weights{$a} <=> $smartie_weights{$b} } keys

Printed Page 584
sub rand_dist_weighted() code at top of page

While not an error, the linear search in this routine can be made a tad faster by
sorting the large weights first:

$key_order = [ sort { $dist->{$b} <=> $dist->{$a} } keys %$dist ]

Likewise for the "@smartie_order =" line at the bottom of the page.

Printed Page 585
sub binomial, first two return statements

replace with

return(0) if ((($p == 0) && ($k != 0)) || (($p == 1) && ($k != $n)));
return(1) if ((($p == 1) && ($k == $n)) || (($p == 0) && ($k == 0)));

or something equivalent but more beautiful. At present some cases

$p==1, $k!=$n gets return1 rather than 0
$p==1, $k==$n gets undefined rather than 1
$p==0, $k!=$n gets undefined rather than 0

tested on Perl 5.005_03 built for i686-linux

Printed Page 592
2nd to last paragraph

The authors egregiously misinterpret the probability density (mass) function
for continuous distributions. To compute probabilities from a density
function, it is necessary to integrate the function over some range, not
simply to evaluate the density at a point. As an example of the sort of
nonsense that can result from the authors' error, if we reduce the variance in
the example on page 592 to 0.1 and compute gaussian(0, 0, 0.1), we arrive at
the conclusion that 126% of leaflets will hit the target. Let r be the sum of
the radii of the target and a leaflet; the correct answer is the integral of
the Gaussian(0, 0.1) density from -r to +r.

Printed Page 596
Hypergeometric DIstributions

my $val = hypergeometric(3,5,53,48);
print "Hyper = $val
"; # will give: 0.00393074501208321

Proposed changes to:
sub hypergeometric {
my ($x,$k,$m,$n) = @_;
return unless $m>0 && $m == int($m) && $n > 0 && $n == int($n) &&
$k > 0 && $k <= $m+$n;
return 0 unless $x <= $k && $x == int($x);
return choose($k,$x) * choose($n, $k-$x)/ choose($m,$k); # changes here


Such that

my $val = hypergeometric(3,5,53,48);
print "Hyper = $val
"; # will give: 0.00393074501208321

The proposed changes follows the example from this link:

Printed Page 600
First full paragraph

The Statistics::Descriptive module is by Colin Kuskie and Jason Kastner, not

Neither Colin, Jason, nor S::D show up in the index.

Printed Page 603

The line:
my @array = sort @$arrayref;

Should be written:

my @array = sort { $a <=> $b } @$arrayref;

Otherwise the array is not numerically sorted and the answer is wrong.

Printed Page 603

If there are two or more equally common elements, there
are two options: declare that there is no mode (that is,
return *undef*), or return the median of the modes. The
following subroutine does the latter."

Neither of these options is mathematically correct, though the latter hints at
the correct answer, in that you return the median of the 'modes'. In a
sequence such as 1, 2, 2, 3, 3, 4, the mode is in actual fact both 2 and 3,
the distribution being a 'multi-modal' distribution.

I appreciate that in this instance, returning both 2 and 3 would probably
require a heavy alteration of the subroutine. As it stands, it currently
returns a scalar, whereas in this instance it would probably have to return

Printed Page 605
The "equivalent formulation of the standard deviation" at the bottom of

the page is mathematically, but _NOT_ numerically equivalent to the formula on
p. 604. In fact, an understanding of the differences between these two
formulae is a common screening question for hiring scientific programmers.
Since many readers may try to implement the second formula, it would be a
service if the text provided a warning that the two methods can give different

Printed Page 606
3rd paragraph

actually this is the error of the errata web page:

Change -10 to 16 and 10 to 16;
change -5 to 8 and 5 to 8;

....should be:

Change -10 to -16 and 10 to 16;
change -5 to -8 and 5 to 8;

Anonymous  Feb 12, 2015 
Printed Page 611
5th line of the 1st code block

$confidence += binomial ($trials, $hits, $probability)

should read

$confidence += binomial ($trials, $_, $probability)

Printed Page 613

The formula given for computation of the z statistic is:

(mean of data - expected mean)/standard deviation.

It seems to me that it should be:

(mean of data - expected mean)/(standard deviation / sqrt (sample size)).

(The code presented in the middle of the page is right, since it uses the
good formula).

Printed Page 614
bottom (after the t formula)

It is written that "the estimate of the standard error of the mean is the
square root of the estimate of the population variance". It seems to me that
this is false. The estimate of the standard error of the mean is the square
root of the estimate of the population variance, divided by the square root of
the sample size.

Printed Page 622
2nd paragraph

The mistake of

In the correlation sub, the following line is present:

sqrt(((@$array1ref * $sum1_squared) - ($sum1 ** 2)) *
((@$array1ref * $sum2_squared) - ($sum2 ** 2)));

The second mention of @$array1ref should be @$array2ref.

is mentioned in the errata section, but is not corrected in the downloadable sample code. I downloaded the code and spent quite a buit of time trying to troubleshoot the problem in my code when actually it was a problem in your sample code. Could you please make this change in the downloadable examples so that others do not have the same problem that I did.

Printed Page 630
third row of matrix

On page 629 appears the following equation:

h(x, y, z) = xyz

On page 630, the partial derivatives of this equation are listed as (x - 4)(y
+ 2), (x - 4)(z + 7), and (x - 4)(y + 2).

These partial derivatives should be listed as yz, xz, and xy, respectively.

Printed Page 631
upper third of page

An equation has a missing term.

@jacobian = jacobian( [&f, &g], [3, 4, -2] );

should be modified to read as follows:

@jacobian = jacobian( [&f, &g, &h], [3, 4, -2] );

Printed Page 635
1st code block

$b/abs($b) will fail if $b is 0. As a replacement, $b <=> 0 will not fail and
is about 20% faster on my machine. It might need an explanation in the prose,

The code on p. 637 includes $sgn = $b/abs($b) if $b, which doesn't fail but
could also be sped up.

Printed Page 646
The 5th line from the comment "# Decompositon phase ..." in the code

$coeffs[$i] = ($delta - 1) / @points;

should read

$coeffs[$i] = ($delta - 1) / $temp;

Accordingly, the example on the next page 647 should be:

Spline coefficients: 0 -8.8 11.2 0
[-1.00, 1.00]
[-0.50, 2.05]
[0.00, 2.00]
[0.50, 0.35]
[1.00, -1.00]
[1.50, -0.20]
[2.00, 2.00]
[2.50, 4.20]
[3.00, 5.00]

The error is so minor that the difference is invisible in Figure 16-3, however.

Printed Page 647

On line 2, the code reads:

my $coeffs = spline_generate @points;

It should read:

my $coeffs = spline_generate(@points);