Αριθμοί και συμβολοσειρές#

Ένα βαθμωτό μπορεί να περιέχει έναν αριθμό, μια συμβολοσειρά ή και τα δύο ταυτόχρονα. Η Perl μετατρέπει σιωπηλά μεταξύ των δύο κάθε φορά που ένας τελεστής απαιτεί μία μορφή - η + θέλει αριθμούς, η . θέλει συμβολοσειρές, οι τελεστές σύγκρισης έχουν ξεχωριστές αριθμητικές και συμβολοσειριακές μορφές. Η κατανόηση των κανόνων μετατροπής και του πού δαγκώνουν είναι ουσιαστική για τη συγγραφή προβλέψιμου κώδικα Perl.

Αριθμητικά κυριολεκτικά#

Τα κυριολεκτικά ακεραίων εμφανίζονται σε πέντε βάσεις:

0                    # zero
12345                # decimal
4_294_967_296        # underscores for legibility (decimal 4.29 billion)
0xff                 # hex      - 255
0Xdead_beef          # hex with underscores
0b01_1011            # binary   - 27
0377                 # octal    - 255 (leading 0, NOT followed by [bBxX])
0o12_345             # octal, alternative spelling (5.33.5+)

Τα κυριολεκτικά κινητής υποδιαστολής απαιτούν είτε τελεία είτε εκθέτη:

3.14
0.5                  # leading zero ok
.5                   # leading dot ok
1e3                  # 1000
1.5E-10              # exponent - uppercase or lowercase 'e'

Οι κάτω παύλες γίνονται αποδεκτές μεταξύ ψηφίων οπουδήποτε - 3.14_15_92, 1_000_000. Πολλαπλές διαδοχικές κάτω παύλες προκαλούν προειδοποίηση: η 23__500 προειδοποιεί, η 23_500 όχι.

Τα δεκαεξαδικά και οκταδικά κυριολεκτικά κινητής υποδιαστολής χρειάζονται τον εκθέτη p (δύναμη του 2):

0x1.999ap-4          # hex float
0b101.01p-1          # binary float
0o7.65p2             # octal float

Ο εκθέτης p είναι υποχρεωτικός για μη δεκαδικά κυριολεκτικά κινητής υποδιαστολής. Η σκέτη 0x1F.5 είναι σφάλμα ανάλυσης.

Συμβολοσειρά → αριθμός#

Όταν η Perl μετατρέπει μια συμβολοσειρά σε αριθμό, καταναλώνει το μεγαλύτερο πρόθεμα που μοιάζει με αριθμό και αγνοεί τα υπόλοιπα:

"42"        + 0      # 42
"42abc"     + 0      # 42       - leading digits parsed
"abc42"     + 0      # 0        - no leading digits
" \t  42"   + 0      # 42       - leading whitespace ok
"4_2"       + 0      # 4        - underscores in literals only, NOT strings
"0xFF"      + 0      # 0        - hex prefix NOT auto-recognised
"3.14e2"    + 0      # 314      - scientific notation parsed
"Inf"       + 0      # Inf      - case-insensitive infinity
"NaN"       + 0      # NaN

Η ασυμφωνία μεταξύ αριθμητικών κυριολεκτικών (που αναγνωρίζουν _, 0x, 0b, 0) και αριθμητικών συμβολοσειρών (που δεν αναγνωρίζουν τίποτα από αυτά) είναι ο κανόνας μετατροπής όπου σκοντάφτει κανείς πιο συχνά. Για μετατροπή συμβολοσειράς σε μη δεκαδική μορφή, χρησιμοποιήστε hex ή oct:

my $bytes = hex "FF";          # 255
my $bytes = hex "0xFF";        # 255  - hex() ignores the 0x
my $perms = oct "0755";        # 493
my $perms = oct "0o755";       # 493  - explicit octal prefix
my $bytes = oct "0xFF";        # 255  - oct() recognises any prefix

Με use warnings, μια αριθμητική πράξη σε συμβολοσειρά που δεν αρχίζει με αριθμητικό πρόθεμα εκπέμπει Argument «…» isn’t numeric in addition (+). Το αποτέλεσμα παραμένει 0· η προειδοποίηση είναι το σήμα. Η συγγραφή ανεκτικού κώδικα που δέχεται είσοδο χρήστη συχνά σημαίνει φιλτράρισμα με Scalar::Util::looks_like_number ή regex πρώτα.

Αριθμός → συμβολοσειρά#

Η Perl μετατρέπει αριθμό σε συμβολοσειρά χρησιμοποιώντας την ίδια λογική με sprintf("%g", $n) για αριθμούς κινητής υποδιαστολής και την προφανή δεκαδική αναπαράσταση για ακεραίους:

my $i = 42;             "$i"   # "42"
my $f = 3.14;           "$f"   # "3.14"
my $z = 0.0;            "$z"   # "0"        - not "0.0"
my $b = 1e10;           "$b"   # "10000000000"
my $s = 1e20;           "$s"   # "1e+20"    - switches to scientific past ~15 digits
my $n = "Inf" + 0;      "$n"   # "Inf"

Η προεπιλεγμένη ακρίβεια είναι αρκετά ψηφία για πλήρη κύκλο των περισσότερων double. Για ακριβή έλεγχο, μορφοποιήστε ρητά με sprintf:

sprintf "%.2f", 3.14159           # "3.14"
sprintf "%05d", 42                # "00042"
sprintf "%e", 1234567             # "1.234567e+06"

Η συνένωση εξαναγκάζει σε συμβολοσειρές· η αριθμητική εξαναγκάζει σε αριθμούς#

"42" + "3"           # 45    - both coerced to numbers
42 . 3               # "423" - both coerced to strings
"3" x "5"            # "33333" - left operand string, right operand number

Ο τελεστής . είναι ο τελεστής ρητής μετατροπής σε συμβολοσειρά· η + είναι ο τελεστής ρητής μετατροπής σε αριθμό. Ένα βαθμωτό που περιέχει αριθμό τον οποίο θέλετε ως συμβολοσειρά μπορεί να συνενωθεί με "":

my $s = "" . $n;     # idiomatic "stringify"
my $s = "$n";        # same; usually clearer

Ένα βαθμωτό που περιέχει συμβολοσειρά την οποία θέλετε ως αριθμό προσθέτει 0:

my $n = $s + 0;      # idiomatic "numify"

Αριθμητική έναντι συμβολοσειριακής σύγκρισης#

Δύο παράλληλες οικογένειες τελεστών σύγκρισης με διαφορετική σημασιολογία:

Αριθμητικός

Συμβολοσειρά

Σημασία

==

eq

ίσο

!=

ne

άνισο

<

lt

μικρότερο

<=

le

μικρότερο ή ίσο

>

gt

μεγαλύτερο

>=

ge

μεγαλύτερο ή ίσο

<=>

cmp

τριμερής σύγκριση

Η σειρά ταξινόμησης διαφέρει δραματικά σε τιμές που μοιάζουν με αριθμούς αλλά είναι μεγάλες:

"10" <  "9"          # FALSE - 10 < 9 numerically
"10" lt "9"          # TRUE  - '1' < '9' lexicographically

Ταξινομήστε αριθμούς αριθμητικά:

my @sorted = sort { $a <=> $b } @numbers;       # numeric
my @sorted = sort                @strings;       # default - string
my @sorted = sort { $a cmp $b }  @strings;       # explicit string

Η επιλογή λάθος τελεστή είναι η πηγή σφαλμάτων «η ταξινόμησή μου είναι λάθος». Δείτε numeric comparison και string comparison.

Κινητή υποδιαστολή: ακρίβεια, Inf, NaN#

Οι περισσότερες Perl χρησιμοποιούν αριθμούς κινητής υποδιαστολής διπλής ακρίβειας IEEE 754 - περίπου 15–17 δεκαδικά ψηφία ακρίβειας. Η κλασική έκπληξη:

0.1 + 0.2 == 0.3      # FALSE - neither side is exactly representable
                      # 0.1 + 0.2 = 0.30000000000000004

Για χρήματα ή οτιδήποτε πρέπει να είναι ακριβές, δουλέψτε σε ακεραίους (λεπτά αντί για ευρώ) ή χρησιμοποιήστε ένα άρθρωμα bignum:

use bignum;            # auto-promotes to arbitrary precision
0.1 + 0.2 == 0.3      # TRUE under bignum

use Math::BigInt;
my $big = Math::BigInt->new("100000000000000000000") + 1;

Οι Inf και NaN είναι πραγματικές τιμές:

my $inf = 9 ** 9 ** 9;       # Inf - overflow
my $nan = $inf - $inf;       # NaN - undefined arithmetic
my $nan = "NaN" + 0;         # NaN - accepted from string

$nan == $nan                  # FALSE - NaN never equals anything
$nan != $nan                  # TRUE  - including itself

Οι Inf και NaN δεν κάνουν διάκριση πεζών-κεφαλαίων στην είσοδο και έχουν αρκετές ορθογραφίες (Infinity, 1.#INF, …)· στην έξοδο η Perl κανονικοποιεί στις σύντομες μορφές.

Σημειώστε ότι η perl5 παράγει μοιραία σφάλματα για 1/0 και sqrt(-1)· αυτά δεν παράγουν NaN. Είναι εξαιρετικά, όχι αριθμητικά.

Ανάλυση αριθμών επηρεαζόμενη από τοπικές ρυθμίσεις#

Με use locale και ενεργή τοπική ρύθμιση POSIX, η υποδιαστολή είναι ό,τι ορίζει η τοπική ρύθμιση. Αυτό επηρεάζει την ανάλυση και τη μετατροπή σε συμβολοσειρά των αριθμών κινητής υποδιαστολής:

use locale;
use POSIX qw(setlocale LC_NUMERIC);
setlocale LC_NUMERIC, 'de_DE.UTF-8';   # German uses ',' as decimal

my $x = 3.14;
print "$x\n";                            # "3,14"  - locale formatting
"3,14" + 0                                # 3.14    - locale parsing

Αυτό σπάνια είναι αυτό που θέλετε για ανταλλαγή δεδομένων. Ο περισσότερος κώδικας που διαβάζει ή γράφει δομημένα δεδομένα δεν πρέπει ρητά να βρίσκεται στην εμβέλεια use locale, ώστε η . να είναι πάντα η υποδιαστολή. Χρησιμοποιήστε μορφοποίηση τοπικών ρυθμίσεων μόνο στο όριο όπου η έξοδος προορίζεται για ανθρώπινο αναγνώστη.

«Μοιάζει με αριθμό»#

Οι κανόνες για το αν μια συμβολοσειρά είναι «αρκετά αριθμητική» δεν είναι απλοί για ενσωματωμένο χειρισμό· χρησιμοποιήστε Scalar::Util::looks_like_number:

use Scalar::Util qw(looks_like_number);

looks_like_number("42")        # true
looks_like_number("3.14e10")   # true
looks_like_number("Inf")       # true
looks_like_number("NaN")       # true
looks_like_number("0xFF")      # FALSE - hex strings are not "numeric"
looks_like_number("")          # FALSE - empty string
looks_like_number(undef)       # FALSE
looks_like_number("3.14abc")   # FALSE - trailing junk

Αυτή είναι η συνάρτηση επικύρωσης - αυστηρή, χωρίς σκουπίδια στην αρχή, χωρίς σκουπίδια στο τέλος, χωρίς προθέματα hex/oct. Ταιριάζει τις συνθήκες υπό τις οποίες η Perl θα χρησιμοποιήσει τη cached αριθμητική μορφή ενός αριθμού αντί να αναλύει εκ νέου σε κάθε αριθμητική πράξη.

Δείτε επίσης#

  • Scalars - η ιστορία διπλής μορφής / dualvar· τιμές αλήθειας.

  • Numeric comparison - ==, <=>.

  • String comparison - eq, cmp.

  • Arithmetic - +, -, *, /, %, **.

  • String - . (συνένωση), x (επανάληψη).

  • hex, oct - μετατροπή μη δεκαδικών αριθμητικών συμβολοσειρών.

  • int, abs, sprintf - ρητή αριθμητική μετατροπή και μορφοποίηση.

  • Scalar::Util - looks_like_number, dualvar.