# Perl turns a string into a number wherever a number is needed, reading as far
# as it can: the leading number in "42abc" is 42. It warns -- `use v5.36` turns
# warnings on -- but it does not stop, and some strings a person would call
# garbage convert without any warning at all.
use v5.36;
use utf8;
use Scalar::Util qw(looks_like_number);

binmode STDOUT, ':encoding(UTF-8)';

sub yn { $_[0] ? 'yes' : 'no' }    # no signature: a failed match in an argument list passes nothing
sub visible ($s) { '"' . ($s =~ s/\n/\\n/gr) . '"' }

say "--- what + 0 makes of a string ---";
printf "  %-14s %-8s %-7s %s\n", 'string', '+ 0', 'warns', 'looks_like_number';
for my $s ("42", " 42 ", "42\n", "42abc", "3.14.15", "abc", "", "0x1A", "1_000", "1e3", "\x{663}", "nan", "inf", "0 but true") {
    my $warned = 0;
    local $SIG{__WARN__} = sub { $warned = 1 };
    my $number = $s + 0;
    printf "  %-14s %-8s %-7s %s\n", visible($s), $number, yn($warned), yn(looks_like_number($s));
}
say "";

say "--- hex and oct read prefixes; + 0 never does ---";
say "  hex('1A')     = ", hex('1A');
say "  hex('0x1A')   = ", hex('0x1A');
say "  oct('0x1A')   = ", oct('0x1A');
say "  oct('0b101')  = ", oct('0b101');
say "  oct('755')    = ", oct('755');
say "  oct('0o755')  = ", oct('0o755');
say "";

say "--- is this string an integer? ---";
printf "  %-8s %-10s %-12s %s\n", 'string', '/^\d+$/', '/\A\d+\z/', '/\A[0-9]+\z/';
for my $s ("42", "42\n", "\x{663}", "4 2") {
    printf "  %-8s %-10s %-12s %s\n", visible($s), yn($s =~ /^\d+$/), yn($s =~ /\A\d+\z/), yn($s =~ /\A[0-9]+\z/);
}
say "";

say "--- floating point is binary, and perl prints 15 significant digits ---";
say "  0.1 + 0.2                = ", 0.1 + 0.2;
say "  0.1 + 0.2 == 0.3         ? ", yn(0.1 + 0.2 == 0.3);
say "  sprintf '%.17g', 0.1+0.2 = ", sprintf('%.17g', 0.1 + 0.2);
say "  sprintf '%.2f', 2.675    = ", sprintf('%.2f', 2.675);
say "  sprintf '%.20f', 2.675   = ", sprintf('%.20f', 2.675), "   (the double nearest 2.675)";
say "  sprintf '%.2f', 1.005    = ", sprintf('%.2f', 1.005);
say "  sprintf '%.0f', 0.5      = ", sprintf('%.0f', 0.5);
say "  sprintf '%.0f', 1.5      = ", sprintf('%.0f', 1.5);
say "  sprintf '%.0f', 2.5      = ", sprintf('%.0f', 2.5);
say "  int(-3.7)                = ", int(-3.7);
say "";

say "--- integers are exact until they are not ---";
say "  9007199254740992 + 1      = ", 9007199254740992 + 1;
say "  2**53 + 1                 = ", 2**53 + 1, "   (** returns a floating-point number)";
say "  '18446744073709551615'+0  = ", '18446744073709551615' + 0;
say "  '18446744073709551616'+0  = ", '18446744073709551616' + 0;
