Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

why are hex values not numbers?

by perl-diddler (Chaplain)
on Sep 26, 2016 at 20:36 UTC ( [id://1172666]=perlquestion: print w/replies, xml ) Need Help??

perl-diddler has asked for the wisdom of the Perl Monks concerning the following question:

Why are hex values not interpreted as numbers:
printf "dec(%d) hex(%x)", "65", "0x41"; Argument "0x41" isn't numeric in printf at -e line 2. dec(65) hex(0) # vs. shell: > printf "dec(%d) hex(0x%08x)\n" "65" "0x41" dec(65) hex(0x00000041)

I know about hex, that doesn't explain why perl shouldn't be able to DWIM, no?

p.s. maybe the latest perl should allow "0x41"->$* ? (tongue-in-cheek)

Replies are listed 'Best First'.
Re: why are hex values not numbers?
by stevieb (Canon) on Sep 26, 2016 at 20:53 UTC
    "p.s. maybe the latest perl should allow "0x41"->$* ? (tongue-in-cheek)"

    It does, but it doesn't work how you think it does. That's called postfix deref, and it only dereferences a reference. A string (which is what you have) is not a reference. Here's an example of using postfix deref after assigning your string to a scalar reference:

    perl -wMstrict -E 'my $x="0x41"; my $y = \$x; say $y->$*' 0x41

    We don't often see direct scalar refs though. Makes more sense with a struct:

    perl -wMstrict -E 'my $href={a=>1}; say $_ for keys $href->%*' a

    Which is the equivalent of the circumfix deref operator, which is by far more common (postfix deref was just released from experimental status in 5.24.0):

    perl -wMstrict -E 'my $href={a=>1}; say $_ for keys %{ $href }' a

    ...or more simply as we're using the whole thing, and not just a piece of it:

    perl -wMstrict -E 'my $href={a=>1}; say $_ for keys %$href' a
      Sorry, forgot it took a ref, so:
      \"0x41"->$*

      I.e. treat the ref as a SCALAR value?

      Hey, don't take this too seriously, I mean it is a joke, right? ;-)

Re: why are hex values not numbers?
by hippo (Bishop) on Sep 26, 2016 at 21:00 UTC

    Here are 2 options. I favour the former.

    #!/usr/bin/env perl use strict; use warnings; printf 'dec(%d) hex(%x)', 65, 0x41; print "\n"; printf 'dec(%d) hex(%x)', "65", eval "0x41"; print "\n";
      But I think you missed the point.

      The "dec" isn't needed. That conversion happens without the explicit 'dec'.

      That's why I compared it against the shell equivalent, that makes no such differentiation. Perl *does* accept both decimal and hex outside of quotes, so why is the eval needed for hex numbers from strings? Seems a bit odd for a computer language.

        Because decimals alone are special inside string literals. perldata states:

        Hexadecimal, octal, or binary, representations in string literals (e.g. '0xff') are not automatically converted to their integer representation. The hex() and oct() functions make these conversions for you. See hex and oct for more details.

        Consider the decimal autoconversion as a bit of handy magic, nothing more.

        why is the eval needed for hex numbers from strings? Seems a bit odd for a computer language.

        In many (most) other languages -- I'd post a list, but the PM post size limit is something like 64kb -- you would have to explicitly convert the string containing a decimal number also -- see atoi(), atoi64(), atof() etc. in your local C compiler's CTR manual.

        Your expectations are naive; and your protestations more so.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority". I knew I was on the right track :)
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: why are hex values not numbers?
by haukex (Archbishop) on Sep 27, 2016 at 08:18 UTC

    Hi perl-diddler,

    By the way, Perl's internal API function that decides whether a string looks like a number is exposed by Scalar::Util's looks_like_number:

    use Scalar::Util qw/looks_like_number/; print looks_like_number("65" )?"yes":"no", "\n"; # yes print looks_like_number("0x41" )?"yes":"no", "\n"; # no print looks_like_number( 0xA_A )?"yes":"no", "\n"; # yes print looks_like_number("0xA_A")?"yes":"no", "\n"; # no

    In the second-to-last example, the literal 0xA_A becomes 170, which of course looks like a number.

    Regards,
    -- Hauke D

      So perl says that 0xAA looks like a number.
      Fine.

      Then why doesn't "0xAA"?

        Because it's in quotes. Thus a string. And so could be the start of a string that contains (the base 64 string): "0x1a2b3c4d5e6f7q"

        Hi perl-diddler,

        I think BrowserUk made a good point, I just wanted to expand on that: numeric literals really are different from strings. Numeric literals are numbers; the literal 0xAA means the number 170. In this example, note especially the last item in the list:

        $ perl -wMstrict -le '$,=", "; print 42, 0xFF, 0b1111, 42 + 0xFF + 0b1 +111, 42 . 0xFF . 0b1111' 42, 255, 15, 312, 4225515

        Perl converts the literals internally before doing anything else with them.

        Consider that there are limits on the size of integers that you can normally store in memory:

        $ perl -wMstrict -le 'print 0xFFFFFFFF' 4294967295 $ perl -wMstrict -le 'print 0xFFFFFFFFF' Hexadecimal number > 0xffffffff non-portable at -e line 1. 68719476735 $ perl -wMstrict -le 'print 0xFFFFFFFFFFFFFFFFF' Integer overflow in hexadecimal number at -e line 1. Hexadecimal number > 0xffffffff non-portable at -e line 1. 2.95147905179353e+20

        Note that in each of the above examples, the results are exactly the same if you put a hex("...") around the literals.

        Next, consider that there isn't a similar limit on the size of strings:

        $ perl -wMstrict -le 'print hex( "0x".("F" x 2**29) )' Integer overflow in hexadecimal number at -e line 1. Hexadecimal number > 0xffffffff non-portable at -e line 1. Inf

        That string, which is over 500MB, is much more likely to be some kind of data than a number - does it make sense that it should be converted to Inf or some other floating-point number if the user accidentally uses it in numeric context? (Note even Math::BigInt can't handle interpreting a hex number that big on my system!)

        Now, in theory, Perl could convert hexadecimal strings that are "small enough" to numbers automagically. But in such a theoretical solution, would it make sense that 0+"0xFFFFFFFF" eq "4294967295", but 0+"0x1FFFFFFFF" eq "0"? Where does one draw the line which numbers are "small enough", and won't such a division cause confusion for the users? (Let's ignore for now the potential performance impact of adding the code to check for hexadecimal to Perl's grok_number_flags.)

        Instead, the design choice that literal numbers are fundamentally different from strings makes things much more consistent. Sure, one will have to call hex and oct a few times, but on the other hand, the argument can be made that calling those functions explicitly gives the code more clarity.

        Hope this helps,
        -- Hauke D

Re: why are hex values not numbers?
by Eily (Monsignor) on Sep 27, 2016 at 16:38 UTC

    It's not just about being decimal or hexadecimal, since "1_1" == 1_1 is false (thanks haukex for mentioning the digit separator). I'm not sure if this is enough of a reason, but obtaining the same value with or without the quotes only works when you can stringify and turn into a number (numberify?) back and forth without changing either the string or the number. For example you wouldn't obtain the original string in map { "$_" } map { 0+$_ } "0x16"; if "0x16" was interpreted as 22.

    Now "Don't use a string as a number if the number won't give you the same string" could have been a pretty good safety net, if perl didn't allow some oddities like "4 ever" being interpreted as the number 4. And print "equal" if '12.9999999999999999' == 13 prints "equal" on my version of perl.

    Edit: you don't get your original string either with leading 0. print "Different" if "042" ne 0+"042";. "042" is 42 but 042 is 34, so once again if "042" had the same numeric value as a bare 042, it wouldn't stringify back to the original string.

      Following my last edit, I realized there's a good reason why using a string as a number is not always the same as simply removing the quotes. It's so that if you ask for user input, the user can type "042", or select this value in a form that pads its numbers with 0, and you'll still get the value the user meant to send rather than 34. I guess having "042" != 042 for this reason but "0x16" == 0x16 is more surprising than only having decimal numbers work this way.

Re: why are hex values not numbers?
by shmem (Chancellor) on Sep 27, 2016 at 21:02 UTC
    Why are hex values not interpreted as numbers

    They are, if they appear as such in your code, e.g.:

    perl -le 'print 0x41' 65

    They are not, if the hexadecimal notation happens to be a string. The string "0x41" in numerical context yields 0, since from left to right, the numerical part ends after 0.

    perl -le 'print 0 + "0x41"' 0

    Same for strings with leading decimal numbers:

    perl -le 'print 0+"3.1415pi--roughly"' 3.1415

    But perl doesn't look at your string trying to guess whether it is a valid hex number. If you want a string to be interpreted as a hex number, use hex. It will happily remove the leading "0x":

    perl -le 'print hex "0x41"' 65
    perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
Re: why are hex values not numbers?
by AnomalousMonk (Archbishop) on Sep 28, 2016 at 00:14 UTC

    Once you get this vexed question nailed down, I think you should investigate why the substr built-in is named "substr" and not "substring", "subStr", "subString", "sub_str", "sub_string" or any of a large number of other possibilities. You may answer "Well, they had to call it something," but is just saying "The documentation says it, I believe it, that settles it!" ever really satisfactory? Question authority! (Please see perlfunc for additional raw material. Personally, I've been wondering a lot lately about grep.)


    Give a man a fish:  <%-{-{-{-<

      English Wikipedia on Grep:

      > grep's name comes from the ed command g/re/p (globally search a regular expression and print)

      ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,

      I think you should investigate why the substr built-in is named "substr" and not "substring", "subStr", "subString", "sub_str", "sub_string" or any of a large number of other possibilities.
      Alas, even the shortest of these (substr) is way too long to be competitive at code golf. As a golfer, I wish Perl had used a built-in operator rather than the substr function for string slicing. This is one of the very few areas where Python trounces Perl at code golf, as discussed in detail at Re: Drunk on golf: 99 Bottles of Beer.

      Quite apart from golf, I miss Python's concise and powerful string slicing operator when coding in Perl and feel string slicing is a common enough operation to warrant a very short "Huffman-coded" way to do it -- especially given "things that are commonly used should be shorter/more succinct" is one of Larry's language design principles. I also find it odd that Perl supports built-in array and hash slices, but not built-in string slices.

        I quite agree with your reasoning and conclusion. That said, substr is one of the Perl functions I use the least; uncommonly, on par with things like getpwuid, at least for me.

Re: why are hex strings not numbers?
by Anonymous Monk on Sep 26, 2016 at 20:40 UTC

    What is a value?

    Stuff between quotes are strings

      Then why does the string "65" print out "ok"? I didn't eval or convert it first.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1172666]
Approved by Paladin
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others avoiding work at the Monastery: (5)
As of 2024-03-28 15:00 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found