perlfaq4.pod
来自「视频监控网络部分的协议ddns,的模块的实现代码,请大家大胆指正.」· POD 代码 · 共 2,029 行 · 第 1/5 页
POD
2,029 行
=head1 NAMEperlfaq4 - Data Manipulation ($Revision: 10394 $)=head1 DESCRIPTIONThis section of the FAQ answers questions related to manipulatingnumbers, dates, strings, arrays, hashes, and miscellaneous data issues.=head1 Data: Numbers=head2 Why am I getting long decimals (eg, 19.9499999999999) instead of the numbers I should be getting (eg, 19.95)?Internally, your computer represents floating-point numbers in binary.Digital (as in powers of two) computers cannot store all numbersexactly. Some real numbers lose precision in the process. This is aproblem with how computers store numbers and affects all computerlanguages, not just Perl.L<perlnumber> shows the gory details of number representations andconversions.To limit the number of decimal places in your numbers, you can use theprintf or sprintf function. See the L<"Floating PointArithmetic"|perlop> for more details. printf "%.2f", 10/3; my $number = sprintf "%.2f", 10/3;=head2 Why is int() broken?Your C<int()> is most probably working just fine. It's the numbers thataren't quite what you think.First, see the answer to "Why am I getting long decimals(eg, 19.9499999999999) instead of the numbers I should be getting(eg, 19.95)?".For example, this print int(0.6/0.2-2), "\n";will in most computers print 0, not 1, because even such simplenumbers as 0.6 and 0.2 cannot be presented exactly by floating-pointnumbers. What you think in the above as 'three' is really more like2.9999999999999995559.=head2 Why isn't my octal data interpreted correctly?Perl only understands octal and hex numbers as such when they occur asliterals in your program. Octal literals in perl must start with aleading C<0> and hexadecimal literals must start with a leading C<0x>.If they are read in from somewhere and assigned, no automaticconversion takes place. You must explicitly use C<oct()> or C<hex()> if youwant the values converted to decimal. C<oct()> interprets hexadecimal (C<0x350>),octal (C<0350> or even without the leading C<0>, like C<377>) and binary(C<0b1010>) numbers, while C<hex()> only converts hexadecimal ones, withor without a leading C<0x>, such as C<0x255>, C<3A>, C<ff>, or C<deadbeef>.The inverse mapping from decimal to octal can be done with either the<%o> or C<%O> C<sprintf()> formats.This problem shows up most often when people try using C<chmod()>,C<mkdir()>, C<umask()>, or C<sysopen()>, which by widespread traditiontypically take permissions in octal. chmod(644, $file); # WRONG chmod(0644, $file); # rightNote the mistake in the first line was specifying the decimal literalC<644>, rather than the intended octal literal C<0644>. The problem canbe seen with: printf("%#o",644); # prints 01204Surely you had not intended C<chmod(01204, $file);> - did you? If youwant to use numeric literals as arguments to chmod() et al. then pleasetry to express them as octal constants, that is with a leading zero andwith the following digits restricted to the set C<0..7>.=head2 Does Perl have a round() function? What about ceil() and floor()? Trig functions?Remember that C<int()> merely truncates toward 0. For rounding to acertain number of digits, C<sprintf()> or C<printf()> is usually theeasiest route. printf("%.3f", 3.1415926535); # prints 3.142The C<POSIX> module (part of the standard Perl distribution)implements C<ceil()>, C<floor()>, and a number of other mathematicaland trigonometric functions. use POSIX; $ceil = ceil(3.5); # 4 $floor = floor(3.5); # 3In 5.000 to 5.003 perls, trigonometry was done in the C<Math::Complex>module. With 5.004, the C<Math::Trig> module (part of the standard Perldistribution) implements the trigonometric functions. Internally ituses the C<Math::Complex> module and some functions can break out fromthe real axis into the complex plane, for example the inverse sine of2.Rounding in financial applications can have serious implications, andthe rounding method used should be specified precisely. In thesecases, it probably pays not to trust whichever system rounding isbeing used by Perl, but to instead implement the rounding function youneed yourself.To see why, notice how you'll still have an issue on half-way-pointalternation: for ($i = 0; $i < 1.01; $i += 0.05) { printf "%.1f ",$i} 0.0 0.1 0.1 0.2 0.2 0.2 0.3 0.3 0.4 0.4 0.5 0.5 0.6 0.7 0.7 0.8 0.8 0.9 0.9 1.0 1.0Don't blame Perl. It's the same as in C. IEEE says we have to dothis. Perl numbers whose absolute values are integers under 2**31 (on32 bit machines) will work pretty much like mathematical integers.Other numbers are not guaranteed.=head2 How do I convert between numeric representations/bases/radixes?As always with Perl there is more than one way to do it. Below are afew examples of approaches to making common conversions between numberrepresentations. This is intended to be representational rather thanexhaustive.Some of the examples later in L<perlfaq4> use the C<Bit::Vector>module from CPAN. The reason you might choose C<Bit::Vector> over theperl built in functions is that it works with numbers of ANY size,that it is optimized for speed on some operations, and for at leastsome programmers the notation might be familiar.=over 4=item How do I convert hexadecimal into decimalUsing perl's built in conversion of C<0x> notation: $dec = 0xDEADBEEF;Using the C<hex> function: $dec = hex("DEADBEEF");Using C<pack>: $dec = unpack("N", pack("H8", substr("0" x 8 . "DEADBEEF", -8)));Using the CPAN module C<Bit::Vector>: use Bit::Vector; $vec = Bit::Vector->new_Hex(32, "DEADBEEF"); $dec = $vec->to_Dec();=item How do I convert from decimal to hexadecimalUsing C<sprintf>: $hex = sprintf("%X", 3735928559); # upper case A-F $hex = sprintf("%x", 3735928559); # lower case a-fUsing C<unpack>: $hex = unpack("H*", pack("N", 3735928559));Using C<Bit::Vector>: use Bit::Vector; $vec = Bit::Vector->new_Dec(32, -559038737); $hex = $vec->to_Hex();And C<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 How do I convert from octal to decimalUsing Perl's built in conversion of numbers with leading zeros: $dec = 033653337357; # note the leading 0!Using the C<oct> function: $dec = oct("33653337357");Using C<Bit::Vector>: use Bit::Vector; $vec = Bit::Vector->new(32); $vec->Chunk_List_Store(3, split(//, reverse "33653337357")); $dec = $vec->to_Dec();=item How do I convert from decimal to octalUsing C<sprintf>: $oct = sprintf("%o", 3735928559);Using C<Bit::Vector>: use Bit::Vector; $vec = Bit::Vector->new_Dec(32, -559038737); $oct = reverse join('', $vec->Chunk_List_Read(3));=item How do I convert from binary to decimalPerl 5.6 lets you write binary numbers directly withthe C<0b> notation: $number = 0b10110110;Using C<oct>: my $input = "10110110"; $decimal = oct( "0b$input" );Using C<pack> and C<ord>: $decimal = ord(pack('B8', '10110110'));Using C<pack> and C<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 C<Bit::Vector>: $vec = Bit::Vector->new_Bin(32, "11011110101011011011111011101111"); $dec = $vec->to_Dec();=item How do I convert from decimal to binaryUsing C<sprintf> (perl 5.6+): $bin = sprintf("%b", 3735928559);Using C<unpack>: $bin = unpack("B*", pack("N", 3735928559));Using C<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.=back=head2 Why doesn't & work the way I want it to?The behavior of binary arithmetic operators depends on whether they'reused on numbers or strings. The operators treat a string as a seriesof bits and work with that (the string C<"3"> is the bit patternC<00110011>). The operators work with the binary form of a number(the number C<3> is treated as the bit pattern C<00000011>).So, saying C<11 & 3> performs the "and" operation on numbers (yieldingC<3>). Saying C<"11" & "3"> performs the "and" operation on strings(yielding C<"1">).Most problems with C<&> and C<|> arise because the programmer thinksthey have a number but really it's a string. The rest arise becausethe programmer says: if ("\020\020" & "\101\101") { # ... }but a string consisting of two null bytes (the result of C<"\020\020"& "\101\101">) is not a false value in Perl. You need: if ( ("\020\020" & "\101\101") !~ /[^\000]/) { # ... }=head2 How do I multiply matrices?Use the Math::Matrix or Math::MatrixReal modules (available from CPAN)or the PDL extension (also available from CPAN).=head2 How do I perform an operation on a series of integers?To call a function on each element in an array, and collect theresults, use: @results = map { my_func($_) } @array;For example: @triple = map { 3 * $_ } @single;To call a function on each element of an array, but ignore theresults: foreach $iterator (@array) { some_func($iterator); }To call a function on each integer in a (small) range, you B<can> use: @results = map { some_func($_) } (5 .. 25);but you should be aware that the C<..> operator creates an array ofall integers in the range. This can take a lot of memory for largeranges. Instead use: @results = (); for ($i=5; $i < 500_005; $i++) { push(@results, some_func($i)); }This situation has been fixed in Perl5.005. Use of C<..> in a C<for>loop will iterate over the range, without creating the entire range. for my $i (5 .. 500_005) { push(@results, some_func($i)); }will not create a list of 500,000 integers.=head2 How can I output Roman numerals?Get the http://www.cpan.org/modules/by-module/Roman module.=head2 Why aren't my random numbers random?If you're using a version of Perl before 5.004, you must call C<srand>once at the start of your program to seed the random number generator. BEGIN { srand() if $] < 5.004 }5.004 and later automatically call C<srand> at the beginning. Don'tcall C<srand> more than once--you make your numbers less random,rather than more.Computers are good at being predictable and bad at being random(despite appearances caused by bugs in your programs :-). see theF<random> article in the "Far More Than You Ever Wanted To Know"collection in http://www.cpan.org/misc/olddoc/FMTEYEWTK.tgz , courtesyof Tom Phoenix, talks more about this. John von Neumann said, "Anyonewho attempts to generate random numbers by deterministic means is, ofcourse, living in a state of sin."If you want numbers that are more random than C<rand> with C<srand>provides, you should also check out the C<Math::TrulyRandom> module fromCPAN. It uses the imperfections in your system's timer to generaterandom numbers, but this takes quite a while. If you want a betterpseudorandom generator than comes with your operating system, look at"Numerical Recipes in C" at http://www.nr.com/ .=head2 How do I get a random number between X and Y?To get a random number between two values, you can use the C<rand()>builtin to get a random number between 0 and 1. From there, you shiftthat into the range that you want.C<rand($x)> returns a number such that C<< 0 <= rand($x) < $x >>. Thuswhat you want to have perl figure out is a random number in the rangefrom 0 to the difference between your I<X> and I<Y>.That is, to get a number between 10 and 15, inclusive, you want arandom number between 0 and 5 that you can then add to 10. my $number = 10 + int rand( 15-10+1 );Hence you derive the following simple function to abstractthat. It selects a random integer between the two givenintegers (inclusive), For example: C<random_int_between(50,120)>. sub random_int_between { my($min, $max) = @_; # Assumes that the two arguments are integers themselves! return $min if $min == $max; ($min, $max) = ($max, $min) if $min > $max; return $min + int rand(1 + $max - $min); }=head1 Data: Dates=head2 How do I find the day or week of the year?The localtime function returns the day of the year. Without anargument localtime uses the current time. $day_of_year = (localtime)[7];The C<POSIX> module can also format a date as the day of the year orweek of the year. use POSIX qw/strftime/; my $day_of_year = strftime "%j", localtime; my $week_of_year = strftime "%W", localtime;To get the day of year for any date, use C<POSIX>'s C<mktime> to get
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?