Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

hexadecimal division

by holandes777 (Beadle)
on Dec 15, 2017 at 23:16 UTC ( #1205629=perlquestion: print w/replies, xml ) Need Help??

holandes777 has asked for the wisdom of the Perl Monks concerning the following question:

Lift the veil of ignorance from my eyes

I am trying to follow am LRC computation (Longitudinal CRC computation) and have hit a bump

# Calculating the exclusive or of "202005" # V= X32 .XOR. X30 .XOR. X32 .XOR. X30 .XOR. X30 .XOR. X35 + = X05 my $command = '202005'; print "$command length=" . length($command) . "\n"; my $result = substr($command,0,1); for (my $i=1; $i<length($command); $i++) { my $c = substr($command,$i,1); print "$i) " . sprintf("%02X ", ord($result)) . " xor ". sprintf(" +%02X ", ord($c)); $result = $result ^ $c; print " gives " . sprintf("%02X ", ord($result)) . "\n"; } print sprintf("%02X ", ord($result)) . "\n"; if ( $result == "\x05" ) { print ":-)\n"; } else { print ":-(\n"; } print "====\n"; # THIS IS WHERE THE PROBLEM BEGINS: # Divide by X10: # Y = INT ( X05 / X10 ) = X00 my $dividend = $result; my $divisor = "\x10"; my $result2; #$result2 = int($dividend/$divisor); #print sprintf("%02X ", ord($result2)) . "\n"; # results in Illegal division by zero at kk.pl line 22. # and this results in character zero, not NUL: $result2 = int(ord($dividend)/ord($divisor)); print sprintf("%02X ", ord($result2)) . "\n";

What concept did I miss? Thank you.

It has been pointed out I was noyt clear as to what I needed, and it is true! So allow me to clarify:

The result of the xor-ing is correct according to the API doc: they expect X'05' and if you run the code we have a display of 05 which is 0x05. It is the next step, where we divide this 0x05 result by X'10' (0x10). The code says:<\p> $result2 = int($dividend/$divisor);

what I expect is 5/16 converted to an int which is the NUL characted (0x00) which the API show as X'00'. The result I AM getting is 30 (0x30 or the ascii charated zero). This is where I need your help, on the last statement.

Replies are listed 'Best First'.
Re: hexadecimal division
by LanX (Archbishop) on Dec 15, 2017 at 23:48 UTC
Re: hexadecimal division
by LanX (Archbishop) on Dec 16, 2017 at 05:23 UTC
Re: hexadecimal division
by haukex (Chancellor) on Dec 16, 2017 at 19:42 UTC

    I think it's best to clarify a few things - you may already know some or all of this, but since this kind of question comes up once in a while, I'll take this opportunity to write a little more on it.

    First, hexadecimal is just another representation format for the more abstract concept of an integer number - although Perl handles all kinds of numbers pretty transparently, I'll just talk about integers for now. The idea of different representations of the same thing occurs in a lot of places:

    • 0b00101010, 0x2a, 052, and XLII represent the same integer commonly known as 42 in decimal; note that in C (not Perl!) one can even write that integer as '*',
    • the byte sequences EF BB BF, FE FF, and 2B 2F 76 38 represent the same Unicode character (the BOM),
    • 42C, 315.15K, and 107.6F represent the same temperature, and
    • "2009-02-13 13:31:30 HST" and "2009-02-14 10:31:30 AEDT" represent the same second in time.

    In any of these examples, if one is getting inputs in different formats, it's usually easiest to first convert them to a single internal representation, do the work, and then re-convert them to the desired format on output, instead of trying to mix different formats in one program.

    Second, I've noticed that sometimes the term "hexadecimal" is used in place of "binary", probably because binary files are viewed with "hex editors", and also that there is sometimes confusion between a string containing a hexadecimal representation of some bytes and the bytes themselves.

    Let's say a file contains four bytes whose numeric values in decimal are 80, 101, 114, and 108. This sequence of bytes interpreted as ASCII characters is the string "Perl". If I run a tool to get a hex dump of that file, I will see something like "5065726c", that is, each byte is being represented as a two-digit hexadecimal number. However, if in my code I have a string that looks like "5065726c", this is a sequence of eight characters and, ignoring Unicode for now, also a sequence of eight bytes (decimal values 53, 48, 54, 53, etc.). If in my program I instead want to work with the four bytes (8-bit integers) which the string "5065726c" represents, I need to convert it first. In Perl, the usual tools for all these kinds of conversions are pack, unpack, ord, chr, hex, oct, and sprintf.

    In Perl, the string "Perl" can also be written as "\x50\x65\x72\x6C", but regarding your code note that "\x10" is not the same as 0x10 - the latter is simply another way of writing the number 16, while the former is a string with one character, that character having a decimal value of 16 (the ASCII control character DLE / "data link escape"). If one has had exposure to a language like C or C++, one might be used to the equivalence (again ignoring Unicode) of strings and char arrays, and therefore being able to initialize a "string" with code like {0x50,0x65,0x72,0x6C,0}. But in Perl, strings can't directly be treated as arrays of integers - although this being Perl, of course there's a module for that ;-) (but please don't use it in real code). Another point: although Perl converts between the two transparently in most cases, 16 and "16" are still two different things, the first an integer and the second a two-character string.

    When it comes to the operations ~ | & ^, in Perl one has to be aware of how the Bitwise String Operators work, so it is important to be aware of whether one is working with strings or integers. 0x2A ^ 0x7A and "\x2A" ^ "\x7A" are essentially the same operation (00101010 xor 01111010 = 01010000), but in the first, the inputs and output are integers, while in the latter they are strings.

    While it's possible to implement division in other domains, it's of course easiest with numbers, and we don't even really have to care what internal format the computer is using to store those numbers. So at the very latest, the division is when you'll need to convert. But in this case, I'd personally probably work with integers all the way through. (By the way, dividing an integer by a power of two is the same as a bit shift, that is, int($x/16) is the same as $x>>4.)

    Lastly, Data::Dumper with Useqq turned on (or Data::Dump) will help you inspect the variables at each step. However, note that both of these modules will sometimes display a string like "16" as the number 16 - if you want to know exactly how Perl is storing your value internally, use Devel::Peek.

    It is still a bit unclear to me if you need the output as an integer or string. In your example, the output as an integer would be 0 (aka 0x00), which Perl will transparently convert to the string "0", which is a one-character string, that character being the ASCII character 0x30 - which would probably explain the result you are currently getting. If instead you need the output as a binary value stored in a string, you'll have to convert the integer 0 to the string "\0" (aka "\x00") using e.g. pack, or, since it's a single character, chr.

    use warnings; use strict; use List::Util qw/reduce/; use Data::Dumper; $Data::Dumper::Useqq=1; $Data::Dumper::Indent=0; $Data::Dumper::Terse=1; my $string = "a202005"; print Dumper($string),"\n"; # "a202005" my @chars = map ord, split //, $string; # or: unpack 'C*', $string print Dumper(\@chars),"\n"; # [97,50,48,50,48,48,53] my $xor = reduce { $a ^ $b } @chars; print Dumper($xor),"\n"; # 100 my $chr = chr $xor; # or: pack 'C', $xor print Dumper($chr),"\n"; # "d" my $out = $xor>>4; print Dumper($out),"\n"; # 6 print Dumper(chr $out),"\n"; # "\6"

    Updated as per replies. Also very minor edits for clarity.

      > hexadecimal is just another representation format for the more abstract concept of an integer

      minor nitpick, to my surprise it's now possible to define hexadecimal floats.

      see perldata#Scalar-value-constructors

      0x1.999ap-4         # hexadecimal floating point (the "p" is required)

      couldn't test yet, seems to be newer than 5.16 :)

      update

      yep

      DB<1> p $] 5.024001 DB<2> p 0x1.999Ap-4 0.100000381469727

      Though not mentioned in perlnumber yet

      update

      seems to work, the exponent 4 counts to the power of 2 (NOT 16 or 256). (16**4 is there to move the fraction point)

      DB<37> p 0x1999A /16**4 /2**4 0.100000381469727

      And it becomes obvious why p was used since an E is a valid hex digit.

      more testing

      DB<49> eval qq{print 0x1p${_},"\n"} for -4..4 0.0625 0.125 0.25 0.5 1 2 4 8 16

      Hex fraction point moves with each 4 power steps (since 16 == 2**4 )

      DB<58> x 0x10 , 0x1.0p4 , 0x1.0p0 , 0x10p-4 0 16 1 16 2 1 3 1

      Cheers Rolf
      (addicted to the Perl Programming Language and ☆☆☆☆ :)
      Wikisyntax for the Monastery

        hexadecimal floats

        Yep, that's why I said "I'll just talk about integers for now" - but I could have worded it better, thank you for pointing that out! I've updated the node.

        Yes, 5.22.
        ($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,
Re: hexadecimal division
by Marshall (Abbot) on Dec 16, 2017 at 00:07 UTC
    Calculation of CRC32 is well known. I suggest a module, perhaps CRC32.

    I am curious as to what you think this means?
    # V= X32 .XOR. X30 .XOR. X32 .XOR. X30 .XOR. X30 .XOR. X35 = X05
    That looks like gibberish to me.

      I am curious as to what you think this means?

      # V= X32 .XOR. X30 .XOR. X32 .XOR. X30 .XOR. X30 .XOR. X35 = X05

      That looks like gibberish to me.

      Not gibberish, FORTRAN (maybe GNU FORTRAN) or something that tries to look like FORTRAN.

      Alexander

      --
      Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
      In the API document that is tehir way of sayin "hex numbers", in this case they are the hex representations of the numbers being xored. That part worked fine, as the result was 0x05. It is the mext part that failed as the result was 0x30 not 0x00. To me that is off because the int of 5 / 16 is 0 (as they denote in x`00`)
        ... API document for what?
Re: hexadecimal division
by bart (Canon) on Dec 17, 2017 at 16:19 UTC
    Here's your error:
    $result2 = int(ord($dividend)/ord($divisor)); print sprintf("%02X ", ord($result2)) . "\n";
    You get the result as an integer (= 0), but you treat it as a character (="0").
Re: hexadecimal division
by karlgoethebier (Monsignor) on Dec 16, 2017 at 16:54 UTC

    See also String::LRC. Regards, Karl

    The Crux of the Biscuit is the Apostrophe

    perl -MCrypt::CBC -E 'say Crypt::CBC->new(-key=>'kgb',-cipher=>"Blowfish")->decrypt_hex($ENV{KARL});'Help

      That module calculates the first part of the OP's question (a simple xor checksum), but not the important part.
        The first part is already buggy, cause something like $result == "\x05" not doing what the OP thinks it does.

        Cheers Rolf
        (addicted to the Perl Programming Language and ☆☆☆☆ :)
        Wikisyntax for the Monastery

        "...not the important part."

        Thanks. I didn't read the friendly manual. Regards, Karl

        The Crux of the Biscuit is the Apostrophe

        perl -MCrypt::CBC -E 'say Crypt::CBC->new(-key=>'kgb',-cipher=>"Blowfish")->decrypt_hex($ENV{KARL});'Help

Re: hexadecimal division
by LanX (Archbishop) on Dec 16, 2017 at 23:58 UTC
    I can't tell if you are using the right algorithm, but here my little implementation inside the debugger.

    Please note

    • how I avoid operating on strings, except for input and output.
    • that it doesn't matter if the input numbers are shown in decimal or hex.

    DB<96> x @input = map {ord} split //,'202005' # input ASCII values 0 50 1 48 2 50 3 48 4 48 5 53 DB<97> $result = 0 ; # neutral start DB<98> $result ^= $_ for @input ; # XOR all DB<99> p $result 5 DB<100> p $result2 = int( $result / 0x10 ) 0 DB<101> print "Input: "; printf "0x%x ",$_ for @input Input: 0x32 0x30 0x32 0x30 0x30 0x35 DB<102> printf "Output: 0x%x", $result2 Output: 0x0

    NB: in case you adopt this code:

    • p and x are debugger commands for dumping results, please ignore them.
    • please declare the variables with my (debugger can't handle them)
    • one doesn't need to decompose a string for input
      DB<105> x @input = (0x32, 0x30, 0x32, 0x30, 0x30, 0x35) 0 50 1 48 2 50 3 48 4 48 5 53
    • If you want to operate on large sets of data consider using unpack and pack to initalize the input
    HTH!

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)
    Wikisyntax for the Monastery

Re: hexadecimal division
by Anonymous Monk on Dec 16, 2017 at 00:50 UTC
    In finite field theory, "divide" means "multiply by the inverse." But I really don't know what you're trying to accomplish or what answer you expected, so I don't know how to help you.
      "But I really don't know what you're trying to accomplish or what answer you expected"

      I'm going to go all smartass which I don't do normally, but I found this comment entertaining and enlightening relative to the situation at hand... "divide by zero" is the appropriate error message here :)

      No disrespect intended; your post is well qualified. I just found it accurate, appropriate but funny in context (it's Friday, and I enjoy good posts after work hours on Fridays)

      Apologies for not being clear. IN the last part: The first part (xor-ing) worked fine, as the result was 0x05, It is the next part, the division or 0x05 by 0x10 that failed as the result was 0x30 not 0x00. To me that is off because the int of 5 / 16 is 0 (the API says X`00`)
        First there is nothing like a "hexadecimal division" in Perl.

        Numbers are represented internally as integers or floats in binary format.

        You are only free to use different base systems for the notation, see perlnumber .

        But the division is always the same!

        > the division or 0x05 by 0x10 that failed as the result was 0x30 not 0x00

        really?

        DB<17> p 0x05/0x10 0.3125 DB<18> p int(0x05/0x10) 0

        But "\x10" is not a number it's a one-character string with the ASCII code 16 (= 0x10)

        DB<25> p int(0x05/"\x10") Illegal division by zero at (eval 33)[C:/Perl_64/lib/perl5db.pl:646] l +ine 2.

        "\x{Hex}" is just a way to use chr inside interpolated strings!

        (See "escape sequences" in perlop#Quote-and-Quote-like-Operators for details.)

        Stop using ASCII codes in strings for hex-numbers!

        Perl is not C, it will ONLY try to treat a string which looks like a decimal number as it's look-a-like number, all others as number zero in numerical context.

        DB<31> p "05"/"16" # strings with decimal(!) numbers 0.3125

        Again Perl is not C and will NOT try to take the byte-code of a character as a number, (unless you use ord explicitly ) !

        "\x10" doesn't look like a decimal number, it doesn't even look like any number at all!

        It's just one character which has position 16 (=0x10) in the ASCII table.

        DB<27> p ord("\x10") 16 DB<28> p "\x10" &#9658; # not a number, hence 0

        (NB: &#9658; shows as ► on my display this is not a number, not even a character.

        It's the Data_Link_Escape character in original ASCII, some OS try to overload it with something more meaningful.)

        This can only succeed (somehow) if you use the ASCII-code of a number character.

        Only the 10 characters "0".."9" look like a digit in ASCII.

        DB<1> p ord("1") 49 DB<2> p ord("\x31") 49 DB<3> p 0 + "\x31" # string = "1" looks like number 1 DB<4> p 5 / "\x31\x36" # string = "16" looks like number 0.3125

        I hope it's clearer now, since we already had this discussion in one of your last questions!

        --> vexed by the hex!

        Cheers Rolf
        (addicted to the Perl Programming Language and ☆☆☆☆ :)
        Wikisyntax for the Monastery

Re: hexadecimal division
by ikegami (Pope) on Dec 18, 2017 at 16:12 UTC

    What I expect is 5/16 converted to an int which is the NUL characted (0x00) which the API show as X'00'.

    Two errors in there.

    1. Division produces a number, not a string. You should be expecting the result to be zero, not a string.
    2. Hex is a text representation of a number. X'00' represents the number zero, not a string.

    Replace

    print sprintf("%02X ", ord($result2)) . "\n";
    with
    print sprintf("%02X ", $result2) . "\n";
Re: hexadecimal division
by Anonymous Monk on Dec 16, 2017 at 23:05 UTC
    Maybe you just want this? $result2 = chr(ord($dividend)/ord($divisor));

    In Perl, bitwise operators like ^ are overloaded to work with strings or numbers. Division only works with numbers, so you have to force your string to a number with ord, then force it back to a string with chr.

        To make things more complicated than necessary?
Re: hexadecimal division
by Anonymous Monk on Dec 16, 2017 at 00:56 UTC
    I daresay that the original code that you are following is ... wrong. Therefore, add "print" statements as-needed to show you what it was attempting to do, then replace the whole thing wth sensible logic. Unfortunately in "old" code you will find a lot of crazy examples of this sort.

      Stating *where* it is "wrong" and pointing out *what* is "wrong" would almost certainly be a benefit to all those who read this thread.

        But what is the task?

        I daresay this code is too messy to give more information.

        update

        Though I have to admit that it sounds like some friend of us who normally gets downvotes for the low information calories hidden in lots of wording carbs ...

        Cheers Rolf
        (addicted to the Perl Programming Language and ☆☆☆☆ :)
        Wikisyntax for the Monastery

      I daresay another code-free, answer-free “response” to be proud™ of in the coming decades. People in the 2050s will look back … fondly on the Era of Handwaving (©2017, all rights deferred) and shed a tear of Nostalgia®.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1205629]
Front-paged by stevieb
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (4)
As of 2019-10-20 04:26 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Notices?