Non-decimal radices/Convert: Difference between revisions

Content added Content deleted
(→‎{{header|PARI/GP}}: Loop was going wrong direction.)
(→‎{{header|Perl}}: Simple builtins, rewrite code, show modules.)
Line 1,743: Line 1,743:


=={{header|Perl}}==
=={{header|Perl}}==
For base 2 and 16, we can do this entirely with language features:
To parse from a base:
<lang perl>use POSIX;
<lang perl>sub to2 { sprintf "%b", shift; }
sub to16 { sprintf "%x", shift; }
sub from2 { unpack("N", pack("B32", substr("0" x 32 . shift, -32))); }
sub from16 { hex(shift); }</lang>


Small functions will handle arbitrary base conversions for bases 2-36:
<lang perl>sub base_to {
my($n,$b) = @_;
my $s = "";
while ($n) {
$s .= ('0'..'9','a'..'z')[$n % $b];
$n = int($n/$b);
}
scalar(reverse($s));
}
sub base_from {
my($n,$b) = @_;
my $t = 0;
for my $c (split(//, lc($n))) {
$t = $b * $t + index("0123456789abcdefghijklmnopqrstuvwxyz", $c);
}
$t;
}</lang>

There are a plethora of modules that perform base conversion.

The core [https://metacpan.org/pod/distribution/perl/ext/POSIX/lib/POSIX.pod POSIX] module includes strtol (and strtoul) which is simple and fast, but only does conversions from a base. On some platforms the function may be limited to 32-bit even with a 64-bit Perl.
<lang perl>use POSIX;
my ($num, $n_unparsed) = strtol('1a', 16);
my ($num, $n_unparsed) = strtol('1a', 16);
$n_unparsed == 0 or die "invalid characters found";
$n_unparsed == 0 or die "invalid characters found";
print "$num\n"; # prints "26"</lang>
print "$num\n"; # prints "26"</lang>


The [https://metacpan.org/pod/ntheory ntheory] module includes functions that will perform base conversion, and is fast. It supports bases up to 36 and bigints.
To format into a base:
<lang perl>sub digitize
<lang perl>use ntheory qw/fromdigits todigitstring/;
my $n = 65261;
# Converts an integer to a single digit.
{my $i = shift;
my $n16 = todigitstring($n, 16) || 0;
my $n10 = fromdigits($n16, 16);
$i < 10
say "$n $n16 $n10"; # prints "65261 feed 65261"</lang>
? $i

: ('a' .. 'z')[$i - 10];}
Other modules include but are not limited to:


* [https://metacpan.org/pod/Math::BaseCalc Math::BaseCalc]
sub to_base
* [https://metacpan.org/pod/Math::Int2Base Math::Int2Base]
{my ($int, $radix) = @_;
* [https://metacpan.org/pod/Math::NumberBase Math::NumberBase]
my $numeral = '';
* [https://metacpan.org/pod/Convert::AnyBase Convert::AnyBase]
do {
* [https://metacpan.org/pod/Math::BaseCnv Math::BaseCnv]
$numeral .= digitize($int % $radix);
* [https://metacpan.org/pod/Math::BaseConvert Math::BaseConvert]
} while $int = int($int / $radix);
scalar reverse $numeral;}</lang>


The last two are ''much'' slower than the others or the simple functions above, but may have extra features. Math::Base::Convert and Convert::BaseN are currently not recommended.
<code>Math::BaseCnv</code> can convert an integer to or from an
arbitrary other base. Its normal output is upper-case but the usual
<code>lc()</code> can convert (cf [[String case#Perl|String case]]).
<lang Perl>use Math::BaseCnv 'cnv';
print cnv("1a", 16, 10),"\n"; # "1a" from hex to decimal prints 26
print lc(cnv(26, 10, 16)),"\n"; # 26 from decimal to hex prints "1a"</lang>


The module [https://metacpan.org/pod/Math::Fleximal Math::Fleximal] not only does very arbitrary base conversion, but allows computations in different bases.
<code>Math::BaseCalc</code> can do similar conversions with an
arbitrary set of characters for digits.


=={{header|Perl 6}}==
=={{header|Perl 6}}==