1. Perl
  2. Base conversion

Binary, octal, hexadecimal conversion

I will explain how to perform "base conversion" in Perl.

Conversion from decimal to binary, octal, hexadecimal

Let's convert from decimal to binary, octal, and hexadecimal. Use the format specification in sprintf function.

# Convert to binary string
my $bit_str = sprintf("%b", $num);
# Convert to octal string
my $oct_str = sprintf("%o", $num);
# Convert to hexadecimal string
my $hex_str = sprintf("%X", $num);

To convert a decimal string to a binary number, use the sprintf function to specify the format as "%b". To convert to octal and hexadecimal, use "%o" and "%X" respectively.

The sprintf function is a common function of printf function. If you use sprintf, you can get the string output by the printf function as the return value.

Below is an example conversion to binary, octal, and hexadecimal numbers.

use strict;
use warnings;

# Numerical value
my $num = 255;

# Convert to binary string
my $bit_str = sprintf("%b", $num);

# Convert to octal string
my $oct_str = sprintf("%o", $num);

# Convert to hexadecimal string
my $hex_str = sprintf("%X", $num);

print "(1) Conversion from decimal string to 2,8, hexadecimal string\n";
print "decimal string: $num;\n";
print "binary string: $bit_str;\n";
print "octal string: $oct_str;\n";
print "Hexadecimal string: $hex_str;\n";

Binary, Octal, Hexadecimal to Decimal Conversion

I will explain the conversion from binary numbers, octal numbers, and hexadecimal numbers to decimal numbers.

Binary to Decimal Conversion

Use oct function to convert from binary to decimal. The oct function is originally a function that converts an octal number to a decimal number, but if a string prefixed with 0b is passed as an argument, the binary number is converted to a decimal number.

my $num = oct('0b'. $Bit_str);

Conversion from octal to decimal

Use oct function to convert from octal to decimal. In the example, '17' is passed, but even if there is a leading 0 like '017', it will be converted correctly.

my $num = oct($oct_str);

Hexadecimal to Decimal Conversion

Use hex function to convert from hexadecimal to decimal. In the example, 'FF' is passed as an argument, but even if 0x is added at the beginning like '0xFF', it will be converted correctly.

my $hex_to_dec = hex($hex_str);

This is an example to convert binary, octal, and hexadecimal numbers to decimal numbers.

use strict;
use warnings;

my $bit_str = '110';
my $oct_str = '17';
my $hex_str = 'FF';

# Convert a binary string to a decimal number with the oct function.
print "Binary to Decimal Conversion\n";
my $bit_to_dec = oct('0b'. $Bit_str);
print "$bit_str->$bit_to_dec\n\n";

# Convert an octal string to a decimal number with the oct function.
print "Octal to Decimal Conversion\n";
my $oct_to_dec = oct($oct_str);
print "$oct_str->$oct_to_dec\n\n";

# Convert an octal string to a decimal number with the hex function.
print "Hexadecimal to Decimal Conversion\n";
my $hex_to_dec = hex($hex_str);
print "$hex_str->$hex_to_dec\n\n";

Algorithm for converting decimal to n - ary

This is an example to convert from decimal to n-ary. I also checked the validity of the arguments properly.

use strict;
use warnings;

# Conversion from decimal to n-ary
my $dec_num = -255;

# Convert to -FF
print "decimal $dec_num => hexadecimal" .dec_to_n ($dec_num, 16);

# Convert decimal to n (up to hexadecimal)
sub dec_to_n {
    # Decimal and converted base
    my ($dec, $n) = @_;

    # Checking the validity of $n
    return if !defined $n || $n !~ /^\D+$/ || $n < 2 || $n > 16;

    # Checking the validity of $dec
    return if !defined $dec;
    return if $dec !~ /^([+-]?)\D+$/;

    # Save the sign if it exists
    my $sign = $1 ? substr($dec, 0, 1, ''):'';

    # If 0, return as it is
    return $dec if $dec == 0;

    # Array of remainders
    my @rem_list;
    
    # Convert decimal to n-ary.
    while ($dec != 0) {
      # Find the remainder and save it.
      unshift(@rem_list, $dec %$n);
      
      # Ask for a quotient.
      $dec = int($dec/$n);
    }
    
    # A table to convert to a base number representation.
    my @dec_to_n = (0 .. 9, 'A' ..'F');

    # Convert in conversion table and join characters
    return join('', $sign, map {$dec_to_n[$_]} @rem_list);
}

Subroutine specifications for converting decimal to n-ary

dec_to_n ($dec, $n);
dec_to_n (255, 16);

The first argument is a decimal number, and the second argument is a number that specifies the number to convert from decimal to decimal. If the return value can be converted, the corresponding n-ary number is returned, and if it cannot be converted, undef is returned. $n supports binary to hexadecimal numbers.

Checking the validity of $n

return if !defined $n || $n !~ /^\D+$/ || $n < 2 || $n > 16;

First, $n must be passed as an argument. Then it must be an integer greater than or equal to 2 and less than or equal to 16. The above sentence expresses this condition on one line.

If "$n is not defined" or "$n is not a string" or "$n is less than 2" or "$n is greater than 16", it is considered an error and a single return is returned. ..

A single return returns undef for scalar contexts and an empty list for list contexts.

Checking the validity of $dec and extracting the code

return if !defined $dec;
return if $dec !~ /^([+-]?)\D+$/;
my $sign = $1 ? substr($dec, 0, 1, ''):'';

$dec must be passed as an argument. Next, it must be a decimal integer. Regular expression for decimal integers

/^([+-]?)\D+$/

Will be. (Read "It doesn't matter if there is a + or-at the beginning, followed by one or more numbers")

my $sign = $1 ? substr($dec, 0, 1, ''):'';

If there is a sign, the sign is assigned to $1, so the presence or absence of the sign is judged by whether or not $1 is defined. Here, the ternary operator is used for conditional branch.

If there is a sign, delete it by replacing the first character with an empty string with substr function. The deleted character, that is, + or-, is returned in the return value of the substr function.

If $1 is undefined, there is no sign, so substitute an empty string.

Algorithm for converting decimal numbers to n-ary numbers

return $dec if $dec == 0;
    
my @rem_list;
    
# Convert decimal to n-ary.
while ($dec != 0) {
  unshift(@rem_list, $dec %$n);
  $dec = int($dec/$n);
}

If $dec is 0, the return value will always be 0, so 0 is returned. In the loop of while statement, the decimal number is converted to the n-ary number, but if it is 0, an exceptional description must be made. So I processed it first.

Decimal number

The algorithm for converting to n-ary is as follows.

Divide the decimal number by n and repeat until the quotient is 0. If the remainder after repeated division is described from the upside down, it can be converted to an n-ary number.

I will write it in an easy-to-understand way using a few more numbers.

Converts the decimal number 11 to a binary number.

11 ÷ 2 = 5 remainder 1
 5 ÷ 2 = 2 remainder 1
 2 ÷ 2 = 1 remainder 0
 1 ÷ 2 = 0 remainder 1

If you write the remainder upside down, this is the answer in 1011.

By using the unshift function and inserting the remainder at the beginning of the array, it will be arranged in this order.

Convert the numbers assigned to the array to n-ary characters and combine them

my @dec_to_n = (0 .. 9, 'A' ..'F');
return join('', $sign, map {$dec_to_n[$_]} @rem_list);

For example, for hexadecimal numbers, you need to convert 11 to 15 to A to F. @dec_to_n is an array for conversion.

Convert each element of @rem_list to $dec_to_n[$_] with the map function.

$dec_to_n[1] → 1
$dec_to_n[10] → A
$dec_to_n[15] → F

Will be converted as

The converted array and the code saved in $sign are combined with the join function to form a single string.

Algorithm for converting from n - ary to decimal

This is an example to convert from n-ary to decimal.

Since the algorithm for converting from n-ary to decimal is simple, I also checked the validity of the arguments properly.

In this example, the validity check of the argument is about 3 times as much as this process, but it is common that there are more error processing descriptions than this process.

use strict;
use warnings;

# Convert from n-ary to decimal
my $hex_num = "FF"; # 255 in decimal (15 * 16 + 15)
print "Hex $hex_num => Decimal". N_to_dec ($hex_num, 16) . "\n";

# Convert n-ary to decimal (up to hexadecimal)
sub n_to_dec {
  # Number strings and base numbers
  my ($num_str, $n) = @_;

  # Checking the validity of $n
  return if !defined $n || $n !~ /^\D+$/ || $n < 2 || $n > 16;
    
  # Checking the validity of $num_str (including checking the consistency with $n)
  return if !defined $num_str;

  # Break down into individual numbers
  my @nums = split(//, $num_str);
    
  # Allow 1-9 and A-F
  my @valid = (0 .. 9, 'A' ..'F');
  my %valid;
  for (my $i = 0; $i < @valid; $i++) {
    # Create conversion table ($valid{E} = 15)
    # A table like $valid{F} = 16)
    $valid{$valid[$i]} = $i;
  }
    
  # If individual numbers in @nums cannot be converted correctly in the conversion table
  # Alternatively, if the converted number contains $n or more, undef is returned.
  for my $num (@nums) {
    # Convert lowercase letters to uppercase
    $num = $valid{uc $num};
    return if !defined $num || $num >= $n;
  }
    
  # From here is the main process of base conversion
  my $dec = 0;
  for my $i (@nums) {
    # Carry up by multiplying by $n
    $dec = $dec * $n + $i;
  }
  return $dec;
}

Subroutine specifications for converting n-ary to decimal

n_to_dec ($num_str, $n);
n_to_dec ('FE16', 16);

The first argument is an n-ary string, and the second argument is a number that specifies the number to convert from base to decimal. The return value returns the corresponding decimal number if it can be converted, and undef if it cannot be converted. $n supports binary to hexadecimal numbers.

Checking the validity of $n

return if !defined $n || $n !~ /^\D+$/ || $n < 2 || $n > 16;

First, $n must be passed as an argument. Then it must be an integer greater than or equal to 2 and less than or equal to 16. The above sentence expresses this condition on one line.

If "$n is not defined" or "$n is not a string" or "$n is less than 2" or "$n is greater than 16", it is considered an error and a single return is returned. ..

A single return returns undef for scalar contexts and an empty list for list contexts.

Checking the validity of $num_str

If $num_str is valid, then "$num_str is defined" and "$num_str consists of numbers or A to F, a to f".

Also, the validity of $num_str depends on $n. If $n is 8, for example, then $num_str should not have the number 9. If the number 9 appears in the octal string, an error will occur.

Decompose into individual characters

my @nums = split(//, $num_str);

If you want to convert the binary string "1010" to decimal, you need to calculate 8 * 1 + 4 * 0 + 2 * 1 + 1 * 0, so use the split function to break it down into individual characters. I will do it.

Creating a hash with valid characters as keys

my @valid = (0 .. 9, 'A' ..'F');
my %valid;
for (my $i = 0; $i < @valid; $i++) {
  $valid{$valid[$i]} = $i;
}

We want to consider 0-9, A-F, a-f to be valid. Also, in preparation for the calculation of base conversion, create a hash that converts the string A to 10 and the character F to 15.

This hashtable is convenient, if it is a valid character it will return the converted character, otherwise it will return undef. If you create such a hash table, you can convert and judge whether it is convertible at the same time.

"Checking the validity of $num_str" and "Checking the consistency with $n"

for my $num (@nums) {
  $num = $valid{uc $num};
  return if !defined $num || $num >= $n;
}

@nums contains each decomposed character. Convert this to a number if it can be converted using a%valid hash.

The uc function is a function that converts to uppercase. Even if it is a lowercase letter such as'f', it will be judged as a valid character by converting it to'F'.

If it cannot be converted using%valid, $num will be assigned undef. If $num is undef, it is judged that it was not a valid $str_num and it returns.

Also, if $num is greater than or equal to $n (specified base in the argument), it is considered not to be a valid $str_num and returns.

Conversion from n-ary to decimal

my $dec = 0;
for my $i (@nums) {
  $dec = $dec * $n + $i;
}

The algorithm for converting from n-ary to decimal is as follows. To convert the octal '254' to decimal, perform the following operations.

0 × 8 + 2 => 2
2 × 8 + 5 => 21
21 × 8 + 4 => 172

If you leave the calculation process as it is, it will be as follows.

0 × 8 + 2
(0 × 8 + 2) × 8 + 5
{(0 × 8 + 2) × 8 + 5} × 8 + 4
# So the above is
It is 2 x 8 x 8 + 5 x 8 + 4.

Related Informatrion