Numbers from text¶
Level: 201 · a number arrives in a file, a form field or a command-line argument
One line: Perl reads a number from the front of any string — "42abc" + 0 is 42, "0x1A" is 0, "1_000" is 1 — and warns without stopping; "nan", "inf" and "42\n" all pass looks_like_number; /^\d+$/ accepts "42\n" and the Arabic-Indic ٣; and sprintf '%.2f', 2.675 is 2.67, because the double nearest 2.675 is just below it.
Measured¶
Verified output of numbers_pl.pl — regenerated by tools/run_examples.py, never hand-typed.
--- what + 0 makes of a string ---
string + 0 warns looks_like_number
"42" 42 no yes
" 42 " 42 no yes
"42\n" 42 no yes
"42abc" 42 yes no
"3.14.15" 3.14 yes no
"abc" 0 yes no
"" 0 yes no
"0x1A" 0 yes no
"1_000" 1 yes no
"1e3" 1000 no yes
"٣" 0 yes no
"nan" NaN no yes
"inf" Inf no yes
"0 but true" 0 no yes
--- hex and oct read prefixes; + 0 never does ---
hex('1A') = 26
hex('0x1A') = 26
oct('0x1A') = 26
oct('0b101') = 5
oct('755') = 493
oct('0o755') = 493
--- is this string an integer? ---
string /^\d+$/ /\A\d+\z/ /\A[0-9]+\z/
"42" yes yes yes
"42\n" yes no no
"٣" yes yes no
"4 2" no no no
--- floating point is binary, and perl prints 15 significant digits ---
0.1 + 0.2 = 0.3
0.1 + 0.2 == 0.3 ? no
sprintf '%.17g', 0.1+0.2 = 0.30000000000000004
sprintf '%.2f', 2.675 = 2.67
sprintf '%.20f', 2.675 = 2.67499999999999982236 (the double nearest 2.675)
sprintf '%.2f', 1.005 = 1.00
sprintf '%.0f', 0.5 = 0
sprintf '%.0f', 1.5 = 2
sprintf '%.0f', 2.5 = 2
int(-3.7) = -3
--- integers are exact until they are not ---
9007199254740992 + 1 = 9007199254740993
2**53 + 1 = 9.00719925474099e+15 (** returns a floating-point number)
'18446744073709551615'+0 = 18446744073709551615
'18446744073709551616'+0 = 1.84467440737096e+19
What + 0 accepts¶
Perl converts a string to a number wherever a number is needed, reading as much of the front as looks numeric:
- Whitespace around the number is fine, a trailing newline included, and there is no warning.
- Anything after the number is dropped, with a warning:
42abcis 42,3.14.15is 3.14. - Source-code spellings do not apply.
0x1Aand1_000are numbers in a Perl program; in a string they are 0 and 1. nanandinfare numbers, andlooks_like_numberagrees — so a check withlooks_like_numberlets both through.0 but trueis special-cased: numerically 0, true as a string, and exempt from the warning, for functions that must return a true zero.٣is not a number to+ 0, even though\dmatches it.
hex and oct¶
hex reads hexadecimal with or without 0x. oct reads a prefix and picks the base: 0x hex, 0b binary, 0o or a leading digit octal. Use them when the string is meant to be in that base; + 0 never is.
Is it an integer?¶
/^\d+$/accepts"42\n", because$matches before a final newline, and accepts٣, because\dis Unicode — see the Unicode bug./\A\d+\z/fixes the newline —\zis the true end of the string — but still accepts٣./\A[0-9]+\z/is the check that means what it says.
Floating point¶
A number with a fraction is a binary double. Perl prints it with 15 significant digits, so 0.1 + 0.2 prints 0.3 and is not equal to 0.3 — %.17g shows the rest. sprintf '%.2f', 2.675 rounds the double actually stored — %.20f shows it begins 2.674999… — down to 2.67. And a value exactly halfway rounds to the even neighbour: 0.5 to 0, 1.5 and 2.5 both to 2. int truncates towards zero.
Integers¶
Perl keeps whole numbers as 64-bit integers while it can, so 9007199254740992 + 1 is exact, one past where a double stops counting in ones. ** returns a double, so 2**53 + 1 is not exact. The largest unsigned 64-bit integer converts exactly; one more and the string becomes a double, printed as 1.84467440737096e+19.
What to do instead¶
Check the whole string before converting, and never trust + 0 to tell you it failed. For money, count in integer cents, or use Math::BigFloat, which ships with perl.
If you are coming from another language¶
- C.
atoiis+ 0: it reads the front and cannot report failure.strtoltells you where it stopped. See Parsing a number from text ↗. - Rust.
"42abc".parse::<i32>()is an error, never a 42. See Parsing out of a string ↗. - Python.
int("42abc")raisesValueError;int(" 42\n")is 42; andint("٣")is 3 — Python converts every Unicode decimal digit, where Perl reads 0. - Java. The other direction — a number written as text — follows the locale: Format follows the locale ↗.
See also¶
sortis not alphabetical —<=>on a string that is not a number-l,-aand-Ftake a line apart — adding up a column, and the54.5that was54.50- perlnumber ↗ and sprintf ↗