Αριθμοί και συμβολοσειρές#
Ένα βαθμωτό μπορεί να περιέχει έναν αριθμό, μια συμβολοσειρά ή και τα δύο ταυτόχρονα. Η 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"
Αριθμητική έναντι συμβολοσειριακής σύγκρισης#
Δύο παράλληλες οικογένειες τελεστών σύγκρισης με διαφορετική σημασιολογία:
Αριθμητικός | Συμβολοσειρά | Σημασία |
|---|---|---|
|
| ίσο |
|
| άνισο |
|
| μικρότερο |
|
| μικρότερο ή ίσο |
|
| μεγαλύτερο |
|
| μεγαλύτερο ή ίσο |
|
| τριμερής σύγκριση |
Η σειρά ταξινόμησης διαφέρει δραματικά σε τιμές που μοιάζουν με αριθμούς αλλά είναι μεγάλες:
"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.