RosettaCodeData/Task/Angles-geometric-normalization-and-conversion/Perl/angles-geometric-normalization-and-conversion.pl
2023-07-01 13:44:08 -04:00

34 lines
1.1 KiB
Perl

use strict;
use warnings;
use feature 'say';
use POSIX 'fmod';
my $tau = 2 * 4*atan2(1, 1);
my @units = (
{ code => 'd', name => 'degrees' , number => 360 },
{ code => 'g', name => 'gradians', number => 400 },
{ code => 'm', name => 'mills' , number => 6400 },
{ code => 'r', name => 'radians' , number => $tau },
);
my %cvt;
for my $a (@units) {
for my $b (@units) {
$cvt{ "${$a}{code}2${$b}{code}" } = sub {
my($angle) = shift;
my $norm = fmod($angle,${$a}{number}); # built-in '%' returns only integers
$norm -= ${$a}{number} if $angle < 0;
$norm * ${$b}{number} / ${$a}{number}
}
}
}
printf '%s'. '%12s'x4 . "\n", ' Angle Unit ', <Degrees Gradians Mills Radians>;
for my $angle (-2, -1, 0, 1, 2, $tau, 16, 360/$tau, 360-1, 400-1, 6400-1, 1_000_000) {
print "\n";
for my $from (@units) {
my @sub_keys = map { "${$from}{code}2${$_}{code}" } @units;
my @results = map { &{$cvt{$_}}($angle) } @sub_keys;
printf '%10g %-8s' . '%12g'x4 . "\n", $angle, ${$from}{name}, @results;
}
}