How to effectively use the BitVector Module In Perl to find the XOR of two numbers? - perl

I am having trouble figuring out how to effectively use the BitVector module in Perl to find the Exclusive Or (XOR) of two numbers in hexadecimal form.
This is my whole code:
use Bit::Vector;
$bits = Bit::Vector->Word_Bits(); # bits in a machine word
print "This program will take two numbers and will return the XOR of the two numbers.\n";
print "Enter the first number in hexadecimal form:\n";
$firstHexNumber = <STDIN>;
$vector = Bit::Vector->new($bits, $firstHexNumber); # bit vector constructor
print "Enter the second number in hexadecimal form:\n";
$secondHexNumber = <STDIN>;
$vector2 = Bit::Vector->new($bits, $secondHexNumber); # bit vector constructor
$vector3 = Bit::Vector->new($bits); # bit vector constructor
$vector3->Xor($vector,$vector2);
print $vector3;
I am not sure if I am doing the syntax right for the BitVector module.
If I try to run it, I get an output like this.
Output
When I input 1 and 16 as my arguments, the output is supposed to be 17.
Please help me see what's wrong with my code to get the output correct.
Thank you.

No need for a module.
# Make sure the bitwise feature wasn't activated (e.g. by `use 5.022;`)
no if $] >= 5.022, feature => qw( bitwise );
my $hex1 = '012345';
my $hex2 = '000AAA';
my $hex_xor = unpack('H*', pack('H*', $hex1) ^ pack('H*', $hex2) );
say $hex_xor; # 0129ef
or (5.22+)
# Safe. Feature accepted without change in 5.28.
use experimental qw( bitwise );
my $hex1 = '012345';
my $hex2 = '000AAA';
my $hex_xor = unpack('H*', pack('H*', $hex1) ^. pack('H*', $hex2) );
say $hex_xor; # 0129ef
or (5.28+)
use feature qw( bitwise ); # Or: use 5.028; # Or: use v5.28;
my $hex1 = '012345';
my $hex2 = '000AAA';
my $hex_xor = unpack('H*', pack('H*', $hex1) ^. pack('H*', $hex2) );
say $hex_xor; # 0129ef
These solutions work with numbers of arbitrary length, which is why I assume Bit::Vector was selected for use. (Just pad the numbers so that both have the same length if necessary, or Perl will effectively right-pad with zeroes.)

You can use new_Hex() and to_Hex():
use strict;
use warnings;
use Bit::Vector;
my $bits = Bit::Vector->Word_Bits(); # bits in a machine word
my $firstHexNumber = "1";
my $vector = Bit::Vector->new_Hex($bits, $firstHexNumber);
my $secondHexNumber = "17";
my $vector2 = Bit::Vector->new_Hex($bits, $secondHexNumber);
my $vector3 = Bit::Vector->new($bits); # bit vector constructor
$vector3->Xor($vector,$vector2);
print $vector3->to_Hex;
Output:
0000000000000016

Related

Why is my Perl script printing incorrect values when not using hard-coded values?

I use an A/D converter to get some results of an electric conductivity probe. I use a miniEC interface from Sparky's Widgets. We run a calibration and get the slope and the intercept values. When I am testing this values with this calibration in a static script the result is correct.
See here, not a big thing but a proof that my calibration works well. The result is correct.
#!/usr/bin/perl
my $slope = "0.048684077307972626";
my $intercept = "24.831896523430906";
$ECdec = 62.5;
print "$ECdec \n";
###lin
$EC1 = ( ( $ECdec - $intercept ) / $slope );
print "Electric Conductivity $EC1 µS/m \n";
Output is:
62.5
Electric Conductivity 773.725323749752 �S/m
When I swap the static value $ECdec to the output of the A/D Converter and try to get a result it is totally wrong. Can anyone see my failure?
Here is the Perl which reads the probes value from the converter, swap the bytes, convert it to decimal and then add the linear regression. What did I do wrong?
#!/usr/bin/perl
my $dir = '/var/www/motion';
my $slope = "0.048684077307972626";
my $intercept = "24.831896523430906";
###get value
my $EC = `sudo i2cget -y 1 0x4a 0x00 w` ;
print "$EC \n";
###swap
my $ECswap = $EC;
substr $ECswap, 4, 0, substr $ECswap, 2, 2, q();
print "$ECswap \n";
###convert to decimal
$ECdec = hex($ECswap);
print "$ECdec \n";
$ECvalue = ($ECdec - $ECintercept)/$slope);
print "$ECvalue"
#$rrd = `/usr/bin/rrdtool update $dir/homeec.rrd N:$ECdec`;
####system ("clear");
print "Electric Conductivity $ECdec µS/m \n";
Output here is:
0x5303
0x0353
851
Electric Conductivity 16969.9858590372 �S/m
You are printing $ECdec in your output instead of $ECvalue
Also, please always post your real code. The program you have shown won't compile and is clearly not the one that is giving you problems
This is how your program should look
You must always use strict and use warnings 'all' at the top of even the most trivial Perl programs, and declare all of your variables with my
You should always use utf8 if your code contains non-ASCII characters like the Greek mu µ in microSiemens. Perl doesn't support source code encoded other than in 7-bit ASCII or UTF-8. I don't know whether your terminal expects UTF-8 characters, and you may need to alter the use open statement
I have commented out your call to i2cget to retrieve a real value and subsituted a constant string instead
I have also converted the hex string to binary before swapping the bytes for speed, but it's far from critical and you should retain the character swap if you find it more readable. I would use a regular expression and write it like this
die unless $EChex =~ /0x(\p{hex}{2})(\p{hex}{2})/;
my $EC = hex($2.$1);
#!/usr/bin/perl
use utf8;
use strict;
use warnings 'all';
use open qw/ :std :encoding(utf8) /;
use constant DIR => '/var/www/motion';
use constant SLOPE => 0.048684077307972626;
use constant INTERCEPT => 24.831896523430906;
# my $EChex = `sudo i2cget -y 1 0x4a 0x00 w` ;
my $EChex = '0x5303';
printf "\$EChex = %s\n", $EChex;
my $EC = hex $EChex;
printf "\$EC = %s\n", $EC;
$EC = (($EC & 0xFF00) >> 8) | (($EC & 0xFF) << 8); # swap bytes
my $ECvalue = ($EC - INTERCEPT) / SLOPE;
printf "Electric Conductivity %.3fµS/m \n", $ECvalue;
output
$EChex = 0x5303
$EC = 21251
Electric Conductivity 16969.986µS/m

Replace binary form 0->1 and 1->0 value - perl

In my script i am dealing with binary value and i need to replace 0->1 and 1->0 at one place.
example :
input digit = 10101001
output digit = 01010110
I tried $string =~ s/1/0/; and reverse function but that is getting fail to give me correct out put.
can some one help me out.
Use tr:
my $str = '10101001';
$s =~ tr/01/10/;
print "$s\n";
Outputs:
01010110
If your input string has only those two possibilities 0 and 1, then you can use substitution in a multi-stage approach:
$str =~ s/1/x/g; # all 1's to x
$str =~ s/0/1/g; # all 0's to 1
$str =~ s/x/0/g; # all x's to 0
This is not a bad option for languages that only provide substitutions, but Perl also has an atomic translation feature:
$str =~ tr/01/10/;
which will work just as well (better, really, since it's less code and probably less passes over the data).
You could also go mathy on this and use the bitwise XOR operator ^...
my $input = '10101001';
my $binval = oct( '0b'.$input );
my $result = $binval ^ 0b11111111;
printf "%08b\n", $result;
...which will also give you 01010110.
This of course has the downside of being dependent on the length of the bit input string. The given solution only works for 8-bit values. It wouldn't be hard to generalize for any number of bits, though.
To incorporate Lưu Vĩnh Phúc's comment - you can also use the bitwise NOT operator ~. Again, the implementation is dependent on the number of bits as you need to truncate the result:
my $input = '10101001';
my $binval = oct( '0b'.$input );
print substr( sprintf ( '%b', ~$binval ), -8 )."\n";

How to force long double in Perl

I lose precision when doing arithmetic or trying to print (debug) numbers this big:
1234567890.123456789
I think my problems are with $d (result of arithmetic) and the formatted print of $e.
How can I force long doubles? My Perl version (5.8.4 on SUN) says it's possible.
sprintf has a size option for long doubles (q or L or ll), but I haven't figured out how to use it, and don't know if it would work with printf.
Edit: I added BigFloat, which works! But I'd still like to force long doubles.
Try to add 1234567890 + 0.123456789
and subtract 1234567890 - 0.123456789.
use Config;
use Math::BigFloat;
$a = 1234567890;
$b = 123456789;
$c = $b/1e9; # 0.123456789
$d = $a + $c; # not enough precision (32-bit or double?)
$e = sprintf("%d.%.9d",$a,$b); # combine as strings
$f = 1234567890.123456789; # for reference (not enough precision)
# Use BigFloat to bypass lack of longdbl
$aBig = Math::BigFloat->new("$a");
$dSum = $aBig->fadd("$c"); # $dSum = $a + $c
$aBig = Math::BigFloat->new("$a"); # <-- Need a new one for every operation?
$dDif = $aBig->fsub(abs("$c")); # $dDif = $a - $c
print "a $a\n"; # 1234567890
print "c $c\n"; # 0.123456789
print "d=a+c $d\n"; # 1234567890.12346 <-- **Problem**
print "dSum=a+c $dSum\n"; # 1234567890.123456789 <-- Solution
print "dDif=a-c $dDif\n"; # 1234567890.876543211 <-- Solution
print "e $e\n"; # 1234567890.123456789
print "f $f\n"; # 1234567890.12346 <-- double, 52-bit, not longdbl?
printf ("printf e 20.9f %20.9f\n",$e); # 1234567890.123456717 <-- **Problem**
printf ("printf dSum 20.9f %20.9f\n",$dSum); # 1234567890.123456717 <-- **Problem**
printf ("printf dSum 20s %20s\n",$dSum); # 1234567890.123456789
printf ("printf dDif 20.9f %20.9f\n",$dDif); # 1234567890.876543283 <-- **Problem**
printf ("printf dDif 20s %20s\n",$dDif); # 1234567890.876543211
print "uselongdouble $Config{uselongdouble}\n"; # empty. No long doubles by default
print "d_longdbl $Config{d_longdbl}\n"; # "define". Supports long doubles
print "size double longdbl $Config{doublesize} $Config{longdblsize}\n"; # Ans 8 16
I also used this code to try to understand the types, but it didn't help much. Has anyone used it to explain problems like this?
use Devel::Peek 'Dump';
Dump ($dSum); # Wow, it's complicated
Dump ($f);
Perl has one size of float, and it's called NV. The size of an NV is decided when Perl is built.
$ perl -V:nvsize
nvsize='8';
This information is also accessible within a Perl program via the Config module.
$ perl -MConfig -E'say $Config{nvsize}'
8
The size of NV cannot be changed after Perl is built.
You can force Perl to be built to use long double floats as follows when when building Perl:
sh Configure -Duselongdouble ...
-or-
perlbrew install -Duselongdouble ...
-or-
perlbrew install --ld ...
If you don't want to rebuild your perl or make a new one, you will need to use a module. I recommend Math::LongDouble as it provides access to native long double floats, and it does so as transparently as possible.
Another option is to use an arbitrary-precision library such as Math::BigFloat, but that will be slower that necessary if all you need is a long double.
bignum will overload all operators in the current scope to use arbitrary precision integers and floating point operations.
use bignum;
my $f = 123456789.123456789;
print "$f\n"; # 123456789.123456789
print $f + $f, "\n"; # 246913578.246913578
Behind the scenes, bignum turns all numeric constants into Math::BigInt and Math::BigNum objects as appropriate.
It's important to note that bignum is lexically scoped and does not effect the whole program. For example...
{
use bignum;
$f = 123456789.123456789; # $f is a Math::BigNum object
}
$g = 123456789.123456789; # $g is a regular NV
print "$f\n"; # 123456789.123456789
print "$g\n"; # 123456789.123457
# This will use Math::BigNum's addition method, but $g has already lost precision.
print $f + $g, "\n"; # 246913578.246913789
You can get a bit better performance out of this by using the Math::BigInt::GMP plugin to use the GNU Multiple Precision Arithmetic Library for some operations. You have to install that module first using the normal CPAN install process (you don't need GMP). Then tell bignum to use GMP.
use bignum lib => "GMP";

perl-how to treat a string as a binary number?

Read a file that contains an address and a data, like below:
#0, 12345678
#1, 5a5a5a5a
...
My aim is to read the address and the data. Consider the data I read is in hex format, and then I need to unpack them to binary number.
So 12345678 would become 00010010001101000101011001111000
Then, I need to further unpack the transferred binary number to another level.
So it becomes, 00000000000000010000000000010000000000000001000100000001000000000000000100000001000000010001000000000001000100010001000000000000
They way I did is like below
while(<STDIN>) {
if (/\#(\S+)\s+(\S+)/) {
$addr = $1;
$data = $2;
$mem{$addr} = ${data};
}
}
foreach $key (sort {$a <=> $b} (keys %mem)) {
my $str = unpack ('B*', pack ('H*',$mem{$key}));
my $str2 = unpack ('B*', pack ('H*', $str));
printf ("#%x ", $key);
printf ("%s",$str2);
printf ("\n");
}
It works, however, my next step is to do some numeric operation on the transferred bits.
Such as bitwise or and shifting. I tried << and | operator, both are for numbers, not strings. So I don't know how to solve this.
Please leave your comments if you have better ideas. Thanks.
You can employ Bit::Vector module from metaCPAN
use strict;
use warnings;
use Bit::Vector;
my $str = "1111000011011001010101000111001100010000001111001010101000111010001011";
printf "orig str: %72s\n", $str;
#only 72 bits for better view
my $vec = Bit::Vector->new_Bin(72,$str);
printf "vec : %72s\n", $vec->to_Bin();
$vec->Move_Left(2);
printf "left 2 : %72s\n", $vec->to_Bin();
$vec->Move_Right(4);
printf "right 4 : %72s\n", $vec->to_Bin();
prints:
orig str: 1111000011011001010101000111001100010000001111001010101000111010001011
vec : 001111000011011001010101000111001100010000001111001010101000111010001011
left 2 : 111100001101100101010100011100110001000000111100101010100011101000101100
right 4 : 000011110000110110010101010001110011000100000011110010101010001110100010
If you need do some math with arbitrary precision, you can also use Math::BigInt or use bigint (http://perldoc.perl.org/bigint.html)
Hex and binary are text representation of numbers. Shifting and bit manipulations are numerical operations. You want a number, not text.
my $hex = '5a5a5a5a';
$num = hex($hex); # Convert to number.
$num >>= 1; # Manipulate the number.
$hex = sprintf('%08X', $num); # Convert back to hex.
In a comment, you mention you want to deal with 256 bit numbers. The native numbers don't support that, but you can use Math::BigInt.
My final solution of this is forget about treat them as numbers, just treat them as string . I use substring and string concentration instead of shift. Then for the or operation , I just add each bit of the string, if it's 0 the result is 0, else is 1.
It may not be the best way to solve this problem. But that's the way I finally used.

How do I unpack a double-precision value in Perl?

From this question:
bytearray - Perl pack/unpack and length of binary string - Stack Overflow
I've learned that #unparray = unpack("d "x5, $aa); in the snippet below results with string items in the unparray - not with double precision numbers (as I expected).
Is it possible to somehow obtain an array of double-precision values from the $aa bytestring in the snippet below?:
$a = pack("d",255);
print length($a)."\n";
# prints 8
$aa = pack("ddddd", 255,123,0,45,123);
print length($aa)."\n";
# prints 40
#unparray = unpack("d "x5, $aa);
print scalar(#unparray)."\n";
# prints 5
print length($unparray[0])."\n"
# prints 3
printf "%d\n", $unparray[0] '
# prints 255
# one liner:
# perl -e '$a = pack("d",255); print length($a)."\n"; $aa = pack("ddddd", 255,123,0,45,123); print length($aa)."\n"; #unparray = unpack("d "x5, $aa); print scalar(#unparray)."\n"; print length($unparray[0])."\n" '
Many thanks in advance for any answers,
Cheers!
What makes you think it's not stored as a double?
use feature qw( say );
use Config qw( %Config );
use Devel::Peek qw( Dump );
my #a = unpack "d5", pack "d5", 255,123,0,45,123;
say 0+#a; # 5
Dump $a[0]; # NOK (floating point format)
say $Config{nvsize}; # 8 byte floats on this build
Sorry, but you've misunderstood hobbs' answer to your earlier question.
$unparray[0] is a double-precision floating-point value; but length is not like (say) C's sizeof operator, and doesn't tell you the size of its argument. Rather, it converts its argument to a string, and then tells you the length of that string.
For example, this:
my $a = 3.0 / 1.5;
print length($a), "\n";
will print this:
1
because it sets $a to 2.0, which gets stringified as 2, which has length 1.