Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

Bitwise Operator Error

by ravishi (Acolyte)
on Oct 02, 2008 at 18:26 UTC ( [id://715064]=perlquestion: print w/replies, xml ) Need Help??

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

I am using Perl and I have a string such as the $testString below. I take the string and remove the trailing/leading whitespace. Then, I remove the spaces between the words. My last goal is to do a bitwise & operator (mask) to determine if the 2nd bit is a 1.

What I want in this example is an end output of 0. I get 4294967295 with an error saying "Argument "00008008000000FF00800000" isn't numeric in bitwise and (&) at .... line 16. Do I have to typecast the array to be an int? I thought you didn't have to do that. Please advise.

#!/usr/bin/perl -w # File displayPipeTracer2.pl $testString = " 00008008 000000FF 00800000"; print "Original: $testString\n"; $testString =~ s/^\s+//; #remove leading spaces $testString =~ s/\s+$//; #remove trailing spaces print "Removed L/T: $testString\n"; $testString =~ s/\s//g; print "Removed ws: $testString\n"; $maskResult = $testString & 400000000000000000000000; print "Mask Result: $maskResult\n";

Replies are listed 'Best First'.
Re: Bitwise Operator Error
by ikegami (Patriarch) on Oct 02, 2008 at 19:13 UTC

    Strings used in numerical context as treated as decimal numbers. Use hex to convert them

    Similarly, numerical literals are treated as decimal numbers. Prepend 0x.

    #!/usr/bin/perl -w # File displayPipeTracer2.pl my $testString = " 00008008 000000FF 00800000"; $testString =~ s/\s+//g; my $maskResult = hex($testString) & 0x400000000000000000000000; print "Mask Result: $maskResult\n";

    But those numbers are huge!

    Integer overflow in hexadecimal number at script.pl line 7. Hexadecimal number > 0xffffffff non-portable at script.pl line 7. Integer overflow in hexadecimal number at script.pl line 7. Hexadecimal number > 0xffffffff non-portable at script.pl line 7. Mask Result: 4294967295

    But Perl is capable of large number arithmetic using bigint/Math::BigInt.

    #!/usr/bin/perl -w # File displayPipeTracer2.pl use bigint; my $testString = " 00008008 000000FF 00800000"; $testString =~ s/\s+//g; $testString = Math::BigInt->new("0x$testString"); my $maskResult = $testString & 0x400000000000000000000000; print "Mask Result: $maskResult\n";
      Thanks, that worked. However, this is just a sample code. I tried using bigint in my main program and it gives me a whole slew of new errors. It is a GUI program using Tk and a few Tk modules (Tk::TableMatrix, Tk::Balloon, Tk::Bitmap, and Tk::Pane). I'm guessing that bigint and the Tk modules conflict. These are two separate errors I get when I run it with bigint. The second I get when I comment out the first error.
      C:\code>DisplayPipeTracer15.pl -trace out.PipeTracer.xml '8┬¿├⌐☻♥' isn't numeric at C:/Perl/site/ +lib/Tk/Widget.pm line 205. at C:\code\displayPipeTracer15.pl line 387 C:\code>DisplayPipeTracer15.pl -trace out.PipeTracer.xml trace_file = out.PipeTracer.xml Ports to be Analyzed: 1 2 'h┬Ñ├⌐☻♥' isn't numeric at C:/Perl/site/ +lib/Tk.pm line 250. at C:\code\displayPipeTracer15.pl line 159
      Here is my code for the lines the errors point to. First is 387 and the second is 159.

      Line 387:

      my $cycleAccept = $statusBar->Button(-text => "Go to", -font => ['Arial', 8], -command=> \&GoToCycle, -bd => 1, -takefocus => 'never', -highlightthickness => 0)->pack( +-side => 'left');

      Line 159:

      $PortFrame = $allPortsFrame->Scrolled('TableMatrix', -resizeborders=>'none', -titlerows => 1, -titlecols => 1, -background => 'white', -foreground => 'white', -borderwidth => 0, -rows => 6, -colstretchmode=>'all', -cols => 1, -colwidth => 25, -cache => 1, -scrollbars => "osoe")->pa +ckAdjust(-side => "top", + -fill => 'both', + -expand => 1);
        bigint basically turns every number into an object which acts as a number. Limit the scope of bigint using curlies, or create the objects yourself were needed.
        #!/usr/bin/perl -w # File displayPipeTracer2.pl { # Only makes objects from numbers in these curlies use bigint; my $testString = " 00008008 000000FF 00800000"; $testString =~ s/\s+//g; $testString = Math::BigInt->new("0x$testString"); my $maskResult = $testString & 0x400000000000000000000000; print "Mask Result: $maskResult\n"; }
        #!/usr/bin/perl -w # File displayPipeTracer2.pl my $testString = " 00008008 000000FF 00800000"; $testString =~ s/\s+//g; $testString = Math::BigInt->new("0x$testString"); my $mask = Math::BigInt->new('0x400000000000000000000000'); my $maskResult = $testString & $mask; print "Mask Result: $maskResult\n";
Re: Bitwise Operator Error
by almut (Canon) on Oct 02, 2008 at 21:46 UTC

    You could also avoid going numeric altogether by converting your string to a bitstring (a string of ASCII 0's and 1's, that is, here):

    my $testString = " 00008008 000000FF 00800000"; $testString =~ s/\s+//g; # convert to a string representation of '0's and '1's my $bits = unpack("B*", pack("H*", $testString)); # test if specific bit is set my $maskResult = substr($bits, 1, 1) eq '1'; printf "%s\n--> 2nd bit from left: %d\n", $bits, $maskResult;

    Checking for several non-adjacent bits with substr might get a bit unwieldy (if you need that) ... in which case you could use the bitwise string-AND operation. For example

    my $testString = " 01008008 000000DF 00800000"; my $mask = "42000000 00000020 00000000"; for ($testString, $mask) { s/\s+//g; $_ = pack("H*", $_); # convert from hex to (binary) bitstring } # bitwise string AND my $maskResult = $testString & $mask; # ----- visualise what's going on (functionally not required) ----- for my $bits ($testString, $mask, '', $maskResult) { if ($bits) { print unpack("B*", $bits), "\n"; } else { print "-" x 96, "\n"; } } # --------------------------------------------------------------- # check for any non-zero bytes $maskResult =~ tr/\0//d; printf "There were %s matching bits.\n", length($maskResult) ? "some": +"no";

    This would test whether any of the bits specified in $mask are set in $testString.

    There is always more than one way to do it :)

Re: Bitwise Operator Error
by XooR (Beadle) on Oct 02, 2008 at 19:29 UTC
    I reimplemented your example with BigInt. I hope that this you wanted:
    #!/usr/bin/perl # File displayPipeTracer2.pl use warnings; use strict; use Math::BigInt; my $testString = " 00008008 000000FF 00800000"; print "Original: $testString\n"; $testString =~ s/\s//g; $testString =~ s/^/0x/g; my $big_x = new Math::BigInt($testString); my $big_y = new Math::BigInt("40000000_00000000_00000000"); my $big_result = $big_x->band( $big_y ); print $big_x->as_hex(), " & ", $big_y->as_hex(), "\n"; print "Mask Result: ", $big_result->as_hex(), "\n";
Re: Bitwise Operator Error
by jethro (Monsignor) on Oct 02, 2008 at 19:21 UTC

    Even if you follow broomdusters advice, you still have a big problem. The internal numbers presentation automatically changes a number to floating point if it gets too big. Anding floating point numbers is quite useless as you can see here:

    $maskResult = 4000000000000000 & 4000000000000000; print $maskResult,"\n"; ####prints 4294967295 $maskResult = 1000000000000000 & 4000000000000000; print $maskResult,"\n"; ####prints 4294967295

    If you want to use really large integers you need bigint or Math:BigInt

Re: Bitwise Operator Error
by broomduster (Priest) on Oct 02, 2008 at 18:49 UTC
    Your hexadecimal number in $testString needs to begin with 0x be properly interpreted as hexadecimal. Then it will work. You can also simplify your white-space removal. All together, here is one way to get where you want to go:
    $testString =~ s/\s+//g;
    $testString =~ s/^/0x/; $maskResult = $testString & 400000000000000000000000;
    $maskResult = hex( $testString ) & 0x400000000000000000000000;

    Updated: Need to use hex and need to have mask as hex string.

    Updated 2: I see ikegami has also pointed out my error(s) corrected above.

    Updated 3: and ikegami has also noted the need for Math::BigInt here.

      That's wrong.

      >perl -we"print 0+'0x0001'" Argument "0x0001" isn't numeric in addition (+) at -e line 1. 0

      See my reply to the OP for details

      Thanks for the help but I just tried what you suggested and it doesn't seem to work. It outputs a 0 which is correct but I get a warning saying that it isn't numeric. I then changed the first bit of the original string to an F to test if I get an output of 1, and I still get a 0.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (9)
As of 2024-03-28 14:46 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found