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

Hello Monks,

More I get closer to my solution more problems I discover. I am trying to convert decimals into 16 bits.

I am using pack and unpack, which works perfect when the first digit of the decimal number is not zero:

I know it does not make sense to have a decimal starting with zero. The reason is that I have a number such as 0.02911 where I am splitting the string before the dot and after so I can send them separately.

So my alternative option would be to convert the decimal to binary B16 send in and then reverse the process. Cookbook 2.4. Converting Between Binary and Decimal

Sample of code with both proposed solutions:

#!/usr/bin/perl use warnings; use strict; my $sampleDecimal = "02911"; my $uint16 = pack 'n', $sampleDecimal; my $decimal = unpack 'n', $uint16; print "Decimal: " . $decimal . "\n"; my $binaryStr = desimalToBinary( $sampleDecimal , 16 , 'n' ); print "Binary: " . $binaryStr . "\n"; my $decimalStr = binaryToDecimal( $binaryStr , 16 , 'n' ); print "Decimal from binary: " . $decimalStr . "\n"; sub binaryToDecimal { my $binary = shift; my $bitSize = shift; my $template = shift; return unpack($template, pack("B$bitSize", substr("0" x $bitSize . + $binary, -$bitSize))); } sub desimalToBinary { my $decimal = shift; my $bitSize = shift; my $template = shift; my $bitStr = unpack("B$bitSize", pack($template, $decimal)); $bitStr =~ s/^0+(?=\d)//; # otherwise you'll get leading zeros return $bitStr; } __END__ Decimal: 2911 Binary: 101101011111 Decimal from binary: 2911

Unfortunately, both proposed solutions do give the same result. A non leading zero decimal. I know I could add manually the leading zero, but in cases the number produced with a non zero digit, then I will have completely wrong number.

So the question, is it possible to get the leading zero through pack and unpack using 'n' as a template?

Update 2: Well it seems that the best solution is to use, sprintf as roboticus proposed.

Sample of code/solution:

#!/usr/bin/perl use warnings; use strict; my $sampleDecimal = "02911"; my $uint16 = pack 'n', $sampleDecimal; my $decimal = unpack 'n', $uint16; $decimal = sprintf("%05d", $decimal); print "Decimal: " . $decimal . "\n"; my $binaryStr = desimalToBinary( $sampleDecimal , 16 , 'n' ); print "Binary: " . $binaryStr . "\n"; my $decimalStr = binaryToDecimal( $binaryStr , 16 , 'n' ); $decimalStr = sprintf("%05d", $decimalStr); print "Decimal from binary: " . $decimalStr . "\n"; sub binaryToDecimal { my $binary = shift; my $bitSize = shift; my $template = shift; return unpack($template, pack("B$bitSize", substr("0" x $bitSize . + $binary, -$bitSize))); } sub desimalToBinary { my $decimal = shift; my $bitSize = shift; my $template = shift; my $bitStr = unpack("B$bitSize", pack($template, $decimal)); $bitStr =~ s/^0+(?=\d)//; # otherwise you'll get leading zeros return $bitStr; } __END__ Decimal: 02911 Binary: 101101011111 Decimal from binary: 02911

Thank you for your time and effort.

Seeking for Perl wisdom...on the process of learning...not there...yet!

Replies are listed 'Best First'.
Re: How to pack and unpack 16 bit decimal with leading zero
by roboticus (Chancellor) on Jul 27, 2015 at 03:20 UTC

    thanos1983:

    No.

    Leading zeroes are just formatting. It has nothing to do with the numeric value. So if you want leading zeroes in your output, you'll need to do it. One way would be to use something like sprintf:

    $ perl -e 'printf "%05d",2911' 02911

    Remember: a 16 bit number has 16 bits. Each bit is for a power of two in the result. There are no extra bits for specifying formatting. The fact that your code prints a number is because perl is converting the number to a string for you, using the default method--which is what we 'normally' want to see. If you want to specify a different format, use a formatting function (sprintf) to do it.

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

      Hello roboticus,

      I guess the only solution is to use sprintf and in cases the number will 5 digits by default then there will be no zero. It should work, or I hope at least. :D

      Thank you for your time and effort.

      Seeking for Perl wisdom...on the process of learning...not there...yet!
Re: How to pack and unpack 16 bit decimal with leading zero (no)
by tye (Sage) on Jul 27, 2015 at 03:16 UTC
    So the question, is it possible to get the leading zero through pack and unpack using 'n' as a template?

    No.

    - tye        

      Hello tye,

      Nice answer, short and direct. :D

      Thank you for time and effort.

      Seeking for Perl wisdom...on the process of learning...not there...yet!
Re: How to pack and unpack 16 bit decimal with leading zero
by BrowserUk (Patriarch) on Jul 27, 2015 at 07:57 UTC

      Hello BrowserUk,

      Thank you for your time and effort, reading and replying to my question.

      Well the reason that I need to have a leading zero, is that the number is a decimal. I am getting this value and then I split the decimal to the main and the remaining part. So the main usually is 0 or 1 maybe in worst cases two digit number. The remaining number usually is like (0.0124). Usually it contains a leading zero, but in some cases it does not.

      This is the reason that I need to have a leading zero, on the number.

      Thank you for your time and effort reading and replying to my question.

      Seeking for Perl wisdom...on the process of learning...not there...yet!
        the reason that I need to have a leading zero, is that the number is a decimal. I am getting this value and then I split the decimal to the main and the remaining part

        Then why are you splitting it into two parts?

        Why not pack it as a floating point value: my $packed = pack 'f', 1.0124;?


        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.
        I'm with torvalds on this Agile (and TDD) debunked I told'em LLVM was the way to go. But did they listen!
Re: How to pack and unpack 16 bit decimal with leading zero
by RichardK (Parson) on Jul 27, 2015 at 10:56 UTC

    Just use printf.

    perl -E 'printf "%016b",123;' 0000000001111011

    You didn't say what you're trying to achieve and it looks like an XY problem, but you seem to be trying to recreate fixed point maths. Maybe reading up on that may help?