# Numbers and strings A scalar can hold a number, a string, or both at once. Perl silently converts between the two whenever an operator demands one shape — `+` wants numbers, `.` wants strings, comparison operators have separate numeric and string forms. Understanding the conversion rules and where they bite is essential to writing predictable Perl. ## Numeric literals Integer literals come in five bases: ```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+) ``` Float literals require either a dot or an exponent: ```perl 3.14 0.5 # leading zero ok .5 # leading dot ok 1e3 # 1000 1.5E-10 # exponent — uppercase or lowercase 'e' ``` Underscores are accepted between digits anywhere — `3.14_15_92`, `1_000_000`. Multiple consecutive underscores warn: `23__500` warns, `23_500` does not. Hex and octal floats need the `p` (power-of-2) exponent: ```perl 0x1.999ap-4 # hex float 0b101.01p-1 # binary float 0o7.65p2 # octal float ``` The `p` exponent is *required* for non-decimal floats. Plain `0x1F.5` is a parse error. ## String → number When Perl converts a string to a number, it consumes the longest prefix that looks like a number and ignores the rest: ```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 ``` The mismatch between numeric *literals* (which honour `_`, `0x`, `0b`, `0`) and numeric *strings* (which honour none of those) is the single most-tripped-over conversion rule. To convert a string that’s in non-decimal form, use [`hex`](../perlfunc/hex.md) or [`oct`](../perlfunc/oct.md): ```perl 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 ``` Under `use warnings`, an arithmetic operation on a string that doesn’t *start* with a number prefix emits *Argument ”…“ isn’t numeric in addition (+)*. The result is still 0; the warning is the signal. Writing tolerant code that accepts user input often means filtering with [`Scalar::Util::looks_like_number`](../../Scalar/Util.md) or a regex first. ## Number → string Perl converts a number to a string using the same logic as `sprintf("%g", $n)` for floats and the obvious decimal representation for integers: ```perl 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" ``` The default precision is enough digits to roundtrip *most* doubles. For exact control, format explicitly with [`sprintf`](../perlfunc/sprintf.md): ```perl sprintf "%.2f", 3.14159 # "3.14" sprintf "%05d", 42 # "00042" sprintf "%e", 1234567 # "1.234567e+06" ``` ## Concatenation forces strings; arithmetic forces numbers ```perl "42" + "3" # 45 — both coerced to numbers 42 . 3 # "423" — both coerced to strings "3" x "5" # "33333" — left operand string, right operand number ``` The `.` operator is the explicit-stringify operator; `+` is the explicit-numerify operator. A scalar that holds a number you want as a string can be concatenated with `""`: ```perl my $s = "" . $n; # idiomatic "stringify" my $s = "$n"; # same; usually clearer ``` A scalar that holds a string you want as a number adds 0: ```perl my $n = $s + 0; # idiomatic "numify" ``` ## Numeric vs string comparison Two parallel families of comparison operators with **different semantics**: | Numeric | String | Meaning | |-----------|----------|-------------------| | `==` | `eq` | equal | | `!=` | `ne` | not equal | | `<` | `lt` | less | | `<=` | `le` | less or equal | | `>` | `gt` | greater | | `>=` | `ge` | greater or equal | | `<=>` | `cmp` | three-way compare | The sort order is dramatically different on values that look like numbers but are large: ```perl "10" < "9" # FALSE — 10 < 9 numerically "10" lt "9" # TRUE — '1' < '9' lexicographically ``` Sort numbers numerically: ```perl my @sorted = sort { $a <=> $b } @numbers; # numeric my @sorted = sort @strings; # default — string my @sorted = sort { $a cmp $b } @strings; # explicit string ``` Picking the wrong operator is the source of ”my sort is wrong“ bugs. See [numeric comparison](../perlop/numeric-comparison.md) and [string comparison](../perlop/string-comparison.md). ## Floating-point: precision, `Inf`, `NaN` Most Perls use IEEE 754 double-precision floats — about 15–17 decimal digits of precision. The classic surprise: ```perl 0.1 + 0.2 == 0.3 # FALSE — neither side is exactly representable # 0.1 + 0.2 = 0.30000000000000004 ``` For money or anything that *must* be exact, work in integers (cents instead of dollars) or use a bignum module: ```perl 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` and `NaN` are real values: ```perl 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` and `NaN` are case-insensitive on input and have several spellings (`Infinity`, `1.#INF`, …); on output Perl normalises to the short forms. Note that perl5 generates *fatal* errors for `1/0` and `sqrt(-1)`; those don’t produce `NaN`. They are exceptional, not arithmetic. ## Locale-affected number parsing Under `use locale` plus an active POSIX locale, the decimal point is whatever the locale says. This affects parsing and stringifying of floats: ```perl 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 ``` This is rarely what you want for data interchange. Most code that reads or writes structured data should explicitly *not* be in the `use locale` scope, so that `.` is always the decimal point. Use locale formatting only at the boundary where output is for a human reader. ## ”Looks like a number“ The rules for whether a string is ”numeric enough“ are not simple to inline; use [`Scalar::Util::looks_like_number`](../../Scalar/Util.md): ```perl 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 ``` This is the validator function — strict, no leading garbage, no trailing garbage, no hex/oct prefixes. It matches the conditions under which Perl will use a number’s cached numeric form rather than re-parsing on every arithmetic op. ## See also - [Scalars](scalars.md) — the dual-form / dualvar story; truth values. - [Numeric comparison](../perlop/numeric-comparison.md) — `==`, `<=>`. - [String comparison](../perlop/string-comparison.md) — `eq`, `cmp`. - [Arithmetic](../perlop/arithmetic.md) — `+`, `-`, `*`, `/`, `%`, `**`. - [String](../perlop/string.md) — `.` (concat), `x` (repetition). - [`hex`](../perlfunc/hex.md), [`oct`](../perlfunc/oct.md) — convert non-decimal numeric strings. - [`int`](../perlfunc/int.md), [`abs`](../perlfunc/abs.md), [`sprintf`](../perlfunc/sprintf.md) — explicit numeric conversion and formatting. - [`Scalar::Util`](../../Scalar/Util.md) — `looks_like_number`, `dualvar`.