Is there any function to convert long decimal number in to hexadecimal? - perl

I have a need to convert a long decimal number :14245138929982432 in to hexadecimal value whose value is 329BE0DDB29BE0.
But when i am trying to use below piece of code i am getting result as FFFFFFFF.
$l_KeyExpected_UL=14245138929982432;
$hexadeci = sprintf '%X', $l_KeyExpected_UL;
print $hexadeci."\n";\
can Any one please help on this.

You can use the Math::BigInt module, which does all the heavy-lifting behind the bigint pragma
You can't use sprintf under bigint to convert large decimals to hex because its conversions aren't overloaded, but Math::BigInt objects have an as_hex method which returns the number expressed as a hex string, prefixed with 0x
This program wraps the conversion in a subroutine bigint_to_hex, which removes the 0x prefix and changes lower case to upper case
It is unusual now to encounter an installation of Perl that won't handle 64-bit values anyway. But this method will work with any decimal string, as I have demonstrated by converting a value of 1.2E40 as well as the value in your question
It's vital that you pass big integers as strings, because numeric literals will be converted to floating point by the compiler if they exceed the width of an ordinary integer. My program also prints the hex equivalent of the same 1.2E40 value without quotation marks so that you can see the difference
use strict;
use warnings 'all';
use feature 'say';
use Math::BigInt;
my $l_KeyExpected_UL = '14245138929982432';
say bigint_to_hex($l_KeyExpected_UL);
say bigint_to_hex('12345678901234567890123456789012345678901');
say bigint_to_hex(12345678901234567890123456789012345678901);
say bigint_to_hex(1.2E40);
sub bigint_to_hex {
my $hex = Math::BigInt->new(shift)->as_hex;
$hex =~ s/^0x//;
uc $hex;
}
output
329BE0DDB29BE0
2447DB449988978536BF5BBBE40E766C35
2447DB449988B214BEA48F651CA8000000
2343CBEEEA6F2C193478C00E0000000000

If you have a build of Perl with 64-bit integers
A Perl build with 64-bit ints will display the following:
$ perl -V:ivsize
ivsize='8';
If this is what you have, you can simply use
my $i = 14245138929982432;
my $hex = sprintf('%X', $i);
If you have a build of Perl that may not have 64-bit integers
That number requires at least 56 bits to store.
Math::Int64 allows you to access native 64-bit ints.
use Math::Int64 qw( uint64 int64_to_hex );
# Note that the number is provided as a string!
my $i = uint64('14245138929982432');
my $hex = int64_to_hex($i);
You could also use an arbitrary precision library such as Math::BigInt, but it will be necessarily slower. If you're going to do some number crunching with 64-bit ints, you definitely want Math::Int64 instead of Math::BigInt.

Related

How to get numeric value of a hash?

On the Proof of work blockchain wiki, one can find that the hash
0000c3af42fc31103f1fdc0151fa747ff87349a4714df7cc52ea464e12dcd4e9
corresponds to the value 2^239.61238653. My question is, how can one calculate this numeric value of a hash?
First note that the block hash is usually represented as a hexadecimal, little endian value, when you try to convert to decimal. If your system is little-endian:
To convert to decimal in bash/perl:
$ hex=0000c3af42fc31103f1fdc0151fa747ff87349a4714df7cc52ea464e12dcd4e9
$ $ perl -le 'use bignum qw/hex/; print hex("0x".$ARGV[0])' --"$hex"
532607621168989936896605052113495566299419916018780134558135832581308350315356027254565114944
or, to get base2 log:
perl -le 'use bignum qw/hex/; print log(hex($ARGV[0]))/log(2)' -- "$hex"
239.6123865298365295145460775449928303015
Which represents 2^239.61238653

Bit selection in perl

How can we bit select the variables in perl code?
I am new to perl and I have a scenario where I need to extract a particular format from a file and give input to a another module for analysis.
Currently I have extracted the required pattern which is in 16-bit Hexadecimal.
Now from this 16bits hexadecimal format ,I want only LSB 10bits.
Kindly refer the below example(This is a sample code where I have used only 1 line of my requirement)
use strict;
my $string = "HDR 0c0d PlD 1000 GAP 412";
$string =~ s/.*HDR\s(\S+).*/$1/g;
print "$string\n";
my $hex = hex($string);
print "$hex";
The output in $hex is 3095 which is 16bit 16’b0011000010000101 now I need to extract only the LSB 10bits(0010000101), Please let me know some easy way to do this .
Use bit mask to select bits which you need. To select right 10 bit you can use:
my $x = 0xfff0;
print $x & 0x3ff;
output is
1008
which is decimal number of ten bits of number 0xfff0

Getting all Unicode aliases for a codepoint

The charnames pragma provides charnames::viacode which returns the "best" name for a given code point
For instance
$ perl -Mcharnames=:full -E'say charnames::viacode(ord "A")'
LATIN CAPITAL LETTER A
Is there a convenient way to discover all known aliases for this name from within Perl?
To get the Unicode aliases of a code point, you can use the following:
use Unicode::UCD qw( charprop );
my #aliases =
map { s/:.*//sr }
split /,/,
charprop($ucp, "Name_Alias"); # $ucp is the Unicode code point as a number.
For example, this returns SP for U+0020 SPACE.
The complete list can be found here.
For all the values you can pass to \N{}, see here.

Can't use an undefined value as an ARRAY reference

I have a simple script written in perl, and i keep getting this particular error when i try to run. The script is for generating some numbers for use in checking integer to floating point. This is the particular error i get.
Can't use an undefined value as an ARRAY reference at /tools/oss/packages/i86pc-5.10/perl/5.8.8-32/lib/5.8.8/Math/BigInt/Calc.pm line 1180
From the error message am not able to figure out where my code is going wrong. By the way i need to use 64 bit numbers. How do i debug this issue?
Here is the code sample
use bignum;
use warnings;
use strict;
open(VCVT, ">CvtIntToFp") or die "couldn't open file to write:$!";
my $number;
my $sgn;
# left with 31 bits excluding the sign
# 23 bits of significand needed, all the result
# will be exact except where leading bit ignoring singn is >23
# take its 2's complement to get the negative number and put it
# into the register
# 32 bit number 1 bit sign 31 left any number with leading 1 #position >23 (counting from 0) will be inexact when in floating point
# 30-24 bit positons can have a leading ones at at any position and result is an inexact
my $twoPwr32 = 0x100000000; #2**32
my #num=();
for(my $i=0; $i<100; $i++)
{
$sgn = (rand()%2);
my $tempLead = (rand()%7); # there are 7 bits from 24 to 30
$number=$tempLead << 24;
if($sgn)
{$number = ($twoPwr32- $number +1) & 0xffffffff;
}
$number = sprintf("%x", $number);
push(#num, $number);
}
my $item=0;
foreach $item (#num)
{
print "$item\n";
print VCVT "$item\n";
}
Try using use diagnostics to get a better error message and read perldoc bignum. The error and explanation is given there that usage of bignum internally converts the numbers into bignum and returns a reference. Since I have perl 5.14 documentation I have the link for documentation of perl 5.20 and I think the bug still exists. Refer to http://perldoc.perl.org/bignum.html
Update :
Hexadecimal number > 0xffffffff non-portable at throw_stack.pl line 19 (#1)
(W portable) The hexadecimal number you specified is larger than 2**32-1
(4294967295) and therefore non-portable between systems. See
perlport for more on portability concerns.
Also refer to this question for the usage of 64 bit arithmetic in Perl.

In Perl, can I treat a string as a byte array?

In Perl, is it appropriate to use a string as a byte array containing 8-bit data? All the documentation I can find on this subject focuses on 7-bit strings.
For instance, if I read some data from a binary file into $data
my $data;
open FILE, "<", $filepath;
binmode FILE;
read FILE $data 1024;
and I want to get the first byte out, is substr($data,1,1) appropriate? (again, assuming it is 8-bit data)
I come from a mostly C background, and I am used to passing a char pointer to a read() function. My problem might be that I don't understand what the underlying representation of a string is in Perl.
The bundled documentation for the read command, reproduced here, provides a lot of information that is relevant to your question.
read FILEHANDLE,SCALAR,LENGTH,OFFSET
read FILEHANDLE,SCALAR,LENGTH
Attempts to read LENGTH characters of data into variable SCALAR
from the specified FILEHANDLE. Returns the number of
characters actually read, 0 at end of file, or undef if there
was an error (in the latter case $! is also set). SCALAR will
be grown or shrunk so that the last character actually read is
the last character of the scalar after the read.
An OFFSET may be specified to place the read data at some place
in the string other than the beginning. A negative OFFSET
specifies placement at that many characters counting backwards
from the end of the string. A positive OFFSET greater than the
length of SCALAR results in the string being padded to the
required size with "\0" bytes before the result of the read is
appended.
The call is actually implemented in terms of either Perl's or
system's fread() call. To get a true read(2) system call, see
"sysread".
Note the characters: depending on the status of the filehandle,
either (8-bit) bytes or characters are read. By default all
filehandles operate on bytes, but for example if the filehandle
has been opened with the ":utf8" I/O layer (see "open", and the
"open" pragma, open), the I/O will operate on UTF-8 encoded
Unicode characters, not bytes. Similarly for the ":encoding"
pragma: in that case pretty much any characters can be read.
See perldoc -f pack and perldoc -f unpack for how to treat strings as byte arrays.
You probably want to use sysopen and sysread if you want to read bytes from binary file.
See also perlopentut.
Whether this is appropriate or necessary depends on what exactly you are trying to do.
#!/usr/bin/perl -l
use strict; use warnings;
use autodie;
use Fcntl;
sysopen my $bin, 'test.png', O_RDONLY;
sysread $bin, my $header, 4;
print map { sprintf '%02x', ord($_) } split //, $header;
Output:
C:\Temp> t
89504e47
Strings are strings of "characters", which are bigger than a byte.1 You can store bytes in them and manipulate them as though they are characters, taking substrs of them and so on, and so long as you're just manipulating entities in memory, everything is pretty peachy. The data storage is weird, but that's mostly not your problem.2
When you try to read and write from files, the fact that your characters might not map to bytes becomes important and interesting. Not to mention annoying. This annoyance is actually made a bit worse by Perl trying to do what you want in the common case: If all the characters in the string fit into a byte and you happen to be on a non-Windows OS, you don't actually have to do anything special to read and write bytes. Perl will complain, however, if you have stored a non-byte-sized character and try to write it without giving it a clue about what to do with it.
This is getting a little far afield, largely because encoding is a large and confusing topic. Let me leave it off there with some references: Look at Encode(3perl), open(3perl), perldoc open, and perldoc binmode for lots of hilarious and gory details.
So the summary answer is "Yes, you can treat strings as though they contained bytes if they do in fact contain bytes, which you can assure by only reading and writing bytes.".
1: Or pedantically, "which can express a larger range of values than a byte, though they are stored as bytes when that is convenient". I think.
2: For the record, strings in Perl are internally represented by a data structure called a 'PV' which in addition to a character pointer knows things like the length of the string and the current value of pos.3
3: Well, it will start storing the current value of pos if it starts being interesting. See also
use Devel::Peek;
my $x = "bluh bluh bluh bluh";
Dump($x);
$x =~ /bluh/mg;
Dump($x);
$x =~ /bluh/mg;
Dump($x);
It might help more if you tell us what you are trying to do with the byte array. There are various ways to work with binary data, and each lends itself to a different set of tools.
Do you want to convert the data into a Perl array? If so, pack and unpack are a good start. split could also come in handy.
Do you want to access individual elements of the string without unpacking it? If so, substr is fast and will do the trick for 8 byte data. If you want other bit depths, take a look at the vec function, which treads a string as a bit vector.
Do you want to scan the string and convert certain bytes to other bytes? Then the s/// or tr/// constructs might be useful.
Allow me just to post a small example about treating string as binary array - since I myself found it difficult to believe that something called "substr" would handle null bytes; but seemingly it does - below is a snippet of a perl debugger terminal session (with both string and array/list approaches):
$ perl -d
Loading DB routines from perl5db.pl version 1.32
Editor support available.
Enter h or `h h' for help, or `man perldebug' for more help.
^D
Debugged program terminated. Use q to quit or R to restart,
use o inhibit_exit to avoid stopping after program termination,
h q, h R or h o to get additional info.
DB<1> $str="\x00\x00\x84\x00"
DB<2> print $str
�
DB<3> print unpack("H*",$str) # show content of $str as hex via `unpack`
00008400
DB<4> $str2=substr($str,2,2)
DB<5> print unpack("H*",$str2)
8400
DB<6> $str2=substr($str,1,3)
DB<7> print unpack("H*",$str2)
008400
[...]
DB<30> #stra=split('',$str); print #stra # convert string to array (by splitting at empty string)
�
DB<31> print unpack("H*",$stra[3]) # print indiv. elems. of array as hex
00
DB<32> print unpack("H*",$stra[2])
84
DB<33> print unpack("H*",$stra[1])
00
DB<34> print unpack("H*",$stra[0])
00
DB<35> print unpack("H*",join('',#stra[1..3])) # print only portion of array/list via indexes (using flipflop [two dots] operator)
008400