This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Deobfuscate Fisher-Yates example code
[perl5.git] / pod / perlfaq4.pod
index cf27c0f..bf24254 100644 (file)
@@ -51,19 +51,36 @@ See L<perlop/"Floating-point Arithmetic">.
 =head2 Why isn't my octal data interpreted correctly?
 
 Perl only understands octal and hex numbers as such when they occur
-as literals in your program.  If they are read in from somewhere and
-assigned, no automatic conversion takes place.  You must explicitly
-use oct() or hex() if you want the values converted.  oct() interprets
+as literals in your program.  Octal literals in perl must start with 
+a leading "0" and hexadecimal literals must start with a leading "0x".
+If they are read in from somewhere and assigned, no automatic 
+conversion takes place.  You must explicitly use oct() or hex() if you 
+want the values converted to decimal.  oct() interprets
 both hex ("0x350") numbers and octal ones ("0350" or even without the
 leading "0", like "377"), while hex() only converts hexadecimal ones,
 with or without a leading "0x", like "0x255", "3A", "ff", or "deadbeef".
+The inverse mapping from decimal to octal can be done with either the
+"%o" or "%O" sprintf() formats.  To get from decimal to hex try either 
+the "%x" or the "%X" formats to sprintf().
 
 This problem shows up most often when people try using chmod(), mkdir(),
-umask(), or sysopen(), which all want permissions in octal.
+umask(), or sysopen(), which by widespread tradition typically take 
+permissions in octal.
 
-    chmod(644,  $file);        # WRONG -- perl -w catches this
+    chmod(644,  $file);        # WRONG
     chmod(0644, $file);        # right
 
+Note the mistake in the first line was specifying the decimal literal 
+644, rather than the intended octal literal 0644.  The problem can
+be seen with:
+
+    printf("%#o",644); # prints 01204
+
+Surely you had not intended C<chmod(01204, $file);> - did you?  If you
+want to use numeric literals as arguments to chmod() et al. then please
+try to express them as octal constants, that is with a leading zero and 
+with the following digits restricted to the set 0..7.
+
 =head2 Does Perl have a round() function?  What about ceil() and floor()?  Trig functions?
 
 Remember that int() merely truncates toward 0.  For rounding to a
@@ -232,23 +249,6 @@ L<perlfunc/"localtime">):
 
     $day_of_year = (localtime(time()))[7];
 
-or more legibly (in 5.7.1 or higher):
-
-    use Time::Piece;
-    $day_of_year = localtime->day_of_year();
-
-You can find the week of the year by using Time::Piece's strftime():
-
-    $week_of_year = localtime->strftime("%U");
-    $iso_week = localtime->strftime("%V");
-
-The difference between %U and %V is that %U assumes that the first day
-of week 1 is the first Sunday of the year, whereas ISO 8601:1988 uses
-the first week that has at least 4 days in the current year, and with
-Monday as the first day of the week. You can also use %W, which will
-return the week of the year with Monday as the first day of week 1. See
-your strftime(3) man page for more details.
-
 =head2 How do I find the current century or millennium?
 
 Use the following simple functions:
@@ -278,10 +278,6 @@ your dates, then you should probably use either of the Date::Manip and
 Date::Calc modules from CPAN before you go hacking up your own parsing
 routine to handle arbitrary date formats.
 
-Also note that the core module Time::Piece overloads the addition and
-subtraction operators to provide date calculation options. See
-L<Time::Piece/Date Calculations>.
-
 =head2 How can I take a string and turn it into epoch seconds?
 
 If it's a regular enough string that it always has the same format,
@@ -291,19 +287,15 @@ and Date::Manip modules from CPAN.
 
 =head2 How can I find the Julian Day?
 
-Use Time::Piece as follows:
-
-    use Time::Piece;
-    my $julian_day = localtime->julian_day;
-    my $mjd = localtime->mjd; # modified julian day
+Use the Time::JulianDay module (part of the Time-modules bundle
+available from CPAN.)
 
 Before you immerse yourself too deeply in this, be sure to verify that
 it is the I<Julian> Day you really want.  Are you interested in a way
 of getting serial days so that you just can tell how many days they
 are apart or so that you can do also other date arithmetic?  If you
 are interested in performing date arithmetic, this can be done using
-Time::Piece (standard module since Perl 5.8), or by modules
-Date::Manip or Date::Calc.
+modules Date::Manip or Date::Calc.
 
 There is too many details and much confusion on this issue to cover in
 this FAQ, but the term is applied (correctly) to a calendar now
@@ -326,14 +318,6 @@ epoch.  Take twenty-four hours off that:
 Then you can pass this to C<localtime()> and get the individual year,
 month, day, hour, minute, seconds values.
 
-Alternatively, you can use Time::Piece to subtract a day from the value
-returned from C<localtime()>:
-
-    use Time::Piece;
-    use Time::Seconds; # imports seconds constants, like ONE_DAY
-    my $today = localtime();
-    my $yesterday = $today - ONE_DAY;
-
 Note very carefully that the code above assumes that your days are
 twenty-four hours each.  For most people, there are two days a year
 when they aren't: the switch to and from summer time throws this off.
@@ -1214,14 +1198,21 @@ lists, or you could just do something like this with an array:
 
 =head2 How do I shuffle an array randomly?
 
-Use this:
+If you either have Perl 5.8.0 or later installed, or if you have
+Scalar-List-Utils 1.03 or later installed, you can say:
+
+        use List::Util 'shuffle';
+
+       @shuffled = shuffle(@list);
+
+If not, you can use this:
 
     # fisher_yates_shuffle( \@array ) : 
     # generate a random permutation of @array in place
     sub fisher_yates_shuffle {
         my $array = shift;
-        my $i;
-        for ($i = @$array; --$i; ) {
+        my $i = @$array;
+        while (--$i) {
             my $j = int rand ($i+1);
             @$array[$i,$j] = @$array[$j,$i];
         }
@@ -1229,6 +1220,10 @@ Use this:
 
     fisher_yates_shuffle( \@array );    # permutes @array in place
 
+Note that the above implementation shuffles an array in place,
+unlike the List::Util::shuffle() which takes a list and returns
+a new shuffled list.
+
 You've probably seen shuffling algorithms that work using splice,
 randomly picking another element to swap the current element with
 
@@ -1307,6 +1302,12 @@ in the permute() function should work on any list:
        }
     }
 
+Unfortunately, this algorithm is very inefficient. The Algorithm::Permute
+module from CPAN runs at least an order of magnitude faster. If you don't
+have a C compiler (or a binary distribution of Algorithm::Permute), then
+you can use List::Permutor which is written in pure Perl, and is still
+several times faster than the algorithm above.
+
 =head2 How do I sort an array by (anything)?
 
 Supply a comparison function to sort() (described in L<perlfunc/sort>):
@@ -1832,12 +1833,8 @@ the PDL module from CPAN instead--it makes number-crunching easy.
 Copyright (c) 1997-1999 Tom Christiansen and Nathan Torkington.
 All rights reserved.
 
-When included as part of the Standard Version of Perl, or as part of
-its complete documentation whether printed or otherwise, this work
-may be distributed only under the terms of Perl's Artistic License.
-Any distribution of this file or derivatives thereof I<outside>
-of that package require that special arrangements be made with
-copyright holder.
+This documentation is free; you can redistribute it and/or modify it
+under the same terms as Perl itself.
 
 Irrespective of its distribution, all code examples in this file
 are hereby placed into the public domain.  You are permitted and