Angles (geometric), normalization and conversion


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 Code %cvt = (@units X @units).map: -> ($a, $b) {
    "{$a.<code>}2{$b.<code>}" => sub ($angle) {
        my $norm = $angle % $a.<number>
                 - ( $a.<number> if $angle < 0 );
        $norm * $b.<number> / $a.<number>
    }
}

say '     Angle Unit     ', @units».<name>».tc.fmt('%11s');

for -2, -1, 0, 1, 2, tau, 16, 360/tau, 360-1, 400-1, 6400-1, 1_000_000 -> $angle {
    say '';
    for @units -> $from {
        my @sub_keys = @units.map: { "{$from.<code>}2{.<code>}" };

        my @results = %cvt{@sub_keys}».($angle);

        say join ' ', $angle      .fmt('%10g'),
                      $from.<name>.fmt('%-8s'),
                      @results    .fmt('%11g');
    }
}

Output:

     Angle Unit         Degrees    Gradians       Mills     Radians

        -2 degrees           -2    -2.22222    -35.5556  -0.0349066
        -2 gradians        -1.8          -2         -32  -0.0314159
        -2 mills        -0.1125      -0.125          -2  -0.0019635
        -2 radians     -114.592    -127.324    -2037.18          -2

        -1 degrees           -1    -1.11111    -17.7778  -0.0174533
        -1 gradians        -0.9          -1         -16   -0.015708
        -1 mills       -0.05625     -0.0625          -1 -0.000981748
        -1 radians     -57.2958     -63.662    -1018.59          -1

         0 degrees            0           0           0           0
         0 gradians           0           0           0           0
         0 mills              0           0           0           0
         0 radians            0           0           0           0

         1 degrees            1     1.11111     17.7778   0.0174533
         1 gradians         0.9           1          16    0.015708
         1 mills        0.05625      0.0625           1 0.000981748
         1 radians      57.2958      63.662     1018.59           1

         2 degrees            2     2.22222     35.5556   0.0349066
         2 gradians         1.8           2          32   0.0314159
         2 mills         0.1125       0.125           2   0.0019635
         2 radians      114.592     127.324     2037.18           2

   6.28319 degrees      6.28319     6.98132     111.701    0.109662
   6.28319 gradians     5.65487     6.28319     100.531    0.098696
   6.28319 mills       0.353429    0.392699     6.28319   0.0061685
   6.28319 radians            0           0           0           0

        16 degrees           16     17.7778     284.444    0.279253
        16 gradians        14.4          16         256    0.251327
        16 mills            0.9           1          16    0.015708
        16 radians      196.732     218.592     3497.47     3.43363

   57.2958 degrees      57.2958      63.662     1018.59           1
   57.2958 gradians     51.5662     57.2958     916.732         0.9
   57.2958 mills        3.22289     3.58099     57.2958     0.05625
   57.2958 radians      42.8064     47.5626     761.002    0.747112

       359 degrees          359     398.889     6382.22     6.26573
       359 gradians       323.1         359        5744     5.63916
       359 mills        20.1938     22.4375         359    0.352447
       359 radians      49.1848     54.6498     874.397    0.858437

       399 degrees           39     43.3333     693.333    0.680678
       399 gradians       359.1         399        6384     6.26748
       399 mills        22.4438     24.9375         399    0.391717
       399 radians      181.016     201.129     3218.06     3.15933

      6399 degrees          279         310        4960     4.86947
      6399 gradians       359.1         399        6384     6.26748
      6399 mills        359.944     399.938        6399      6.2822
      6399 radians      155.693     172.992     2767.88     2.71736

   1000000 degrees          280     311.111     4977.78     4.88692
   1000000 gradians           0           0           0           0
   1000000 mills             90         100        1600      1.5708
   1000000 radians      339.513     377.237     6035.79     5.92562

Alternately, implemented as a series of postfix operators:

(Much of the complexity is due to the requirement that negative angles must normalize to a negative number.)

sub postfix:<t>( $t ) { my $a = $t % 1 * τ;           $t >=0 ?? $a !! $a - τ }
sub postfix:<d>( $d ) { my $a = $d % 360 * τ / 360;   $d >=0 ?? $a !! $a - τ }
sub postfix:<g>( $g ) { my $a = $g % 400 * τ / 400;   $g >=0 ?? $a !! $a - τ }
sub postfix:<m>( $m ) { my $a = $m % 6400 * τ / 6400; $m >=0 ?? $a !! $a - τ }
sub postfix:<r>( $r ) { my $a = $r % τ;               $r >=0 ?? $a !! $a - τ }

sub postfix:«->t» ($angle) { my $a = $angle / τ;        ($angle < 0 and $a == -1)    ?? -0 !! $a }
sub postfix:«->d» ($angle) { my $a = $angle / τ * 360;  ($angle < 0 and $a == -360)  ?? -0 !! $a }
sub postfix:«->g» ($angle) { my $a = $angle / τ * 400;  ($angle < 0 and $a == -400)  ?? -0 !! $a }
sub postfix:«->m» ($angle) { my $a = $angle / τ * 6400; ($angle < 0 and $a == -6400) ?? -0 !! $a }
sub postfix:«->r» ($angle) { my $a = $angle;            ($angle < 0 and $a == -τ)    ?? -0 !! $a }

for <-2 -1 0 1 2 6.2831853 16 57.2957795 359 399 6399 1000000> -> $a {
    say '';
    say '  Quantity  Unit      ', <turns degrees gradians mils radians>.fmt('%15s');
    for 'turns', &postfix:«t», 'degrees', &postfix:«d», 'gradians', &postfix:«g»,
        'mils',  &postfix:«m», 'radians', &postfix:«r»
      -> $unit, &f {
            printf "%10s %-10s %15s %15s %15s %15s %15s\n", $a, $unit,
            |($a.&f->t, $a.&f->d, $a.&f->g, $a.&f->m, $a.&f->r)».round(.00000001);
    }
}

Output:

 Quantity  Unit                turns         degrees        gradians            mils         radians
        -2 turns                    0               0               0               0               0
        -2 degrees        -0.00555556              -2     -2.22222222    -35.55555556     -0.03490659
        -2 gradians            -0.005            -1.8              -2             -32     -0.03141593
        -2 mils             -0.000313         -0.1125          -0.125              -2      -0.0019635
        -2 radians        -0.31830989   -114.59155903   -127.32395447  -2037.18327158              -2

  Quantity  Unit                turns         degrees        gradians            mils         radians
        -1 turns                    0               0               0               0               0
        -1 degrees        -0.00277778              -1     -1.11111111    -17.77777778     -0.01745329
        -1 gradians           -0.0025            -0.9              -1             -16     -0.01570796
        -1 mils             -0.000156        -0.05625         -0.0625              -1     -0.00098175
        -1 radians        -0.15915494    -57.29577951    -63.66197724  -1018.59163579              -1

  Quantity  Unit                turns         degrees        gradians            mils         radians
         0 turns                    0               0               0               0               0
         0 degrees                  0               0               0               0               0
         0 gradians                 0               0               0               0               0
         0 mils                     0               0               0               0               0
         0 radians                  0               0               0               0               0

  Quantity  Unit                turns         degrees        gradians            mils         radians
         1 turns                    0               0               0               0               0
         1 degrees         0.00277778               1      1.11111111     17.77777778      0.01745329
         1 gradians            0.0025             0.9               1              16      0.01570796
         1 mils              0.000156         0.05625          0.0625               1      0.00098175
         1 radians         0.15915494     57.29577951     63.66197724   1018.59163579               1

  Quantity  Unit                turns         degrees        gradians            mils         radians
         2 turns                    0               0               0               0               0
         2 degrees         0.00555556               2      2.22222222     35.55555556      0.03490659
         2 gradians             0.005             1.8               2              32      0.03141593
         2 mils              0.000313          0.1125           0.125               2       0.0019635
         2 radians         0.31830989    114.59155903    127.32395447   2037.18327158               2

  Quantity  Unit                turns         degrees        gradians            mils         radians
 6.2831853 turns            0.2831853      101.946708       113.27412      1812.38592      1.77930572
 6.2831853 degrees         0.01745329       6.2831853        6.981317      111.701072      0.10966227
 6.2831853 gradians        0.01570796      5.65486677       6.2831853     100.5309648      0.09869604
 6.2831853 mils            0.00098175      0.35342917      0.39269908       6.2831853       0.0061685
 6.2831853 radians                  1    359.99999959    399.99999954   6399.99999269       6.2831853

  Quantity  Unit                turns         degrees        gradians            mils         radians
        16 turns                    0               0               0               0               0
        16 degrees         0.04444444              16     17.77777778    284.44444444      0.27925268
        16 gradians              0.04            14.4              16             256      0.25132741
        16 mils                0.0025             0.9               1              16      0.01570796
        16 radians         0.54647909    196.73247221    218.59163579   3497.46617261      3.43362939

  Quantity  Unit                turns         degrees        gradians            mils         radians
57.2957795 turns            0.2957795       106.48062        118.3118       1892.9888      1.85843741
57.2957795 degrees         0.15915494      57.2957795     63.66197722   1018.59163556               1
57.2957795 gradians        0.14323945     51.56620155      57.2957795      916.732472             0.9
57.2957795 mils            0.00895247       3.2228876      3.58098622      57.2957795         0.05625
57.2957795 radians         0.11890653     42.80634926     47.56261029    761.00176466      0.74711174

  Quantity  Unit                turns         degrees        gradians            mils         radians
       359 turns                    0               0               0               0               0
       359 degrees         0.99722222             359    398.88888889   6382.22222222      6.26573201
       359 gradians            0.8975           323.1             359            5744      5.63915881
       359 mils              0.056094        20.19375         22.4375             359      0.35244743
       359 radians         0.13662457      49.1848452       54.649828    874.39724794      0.85843749

  Quantity  Unit                turns         degrees        gradians            mils         radians
       399 turns                    0               0               0               0               0
       399 degrees         0.10833333              39     43.33333333    693.33333333      0.68067841
       399 gradians            0.9975           359.1             399            6384      6.26747734
       399 mils              0.062344        22.44375         24.9375             399      0.39171733
       399 radians         0.50282229    181.01602572    201.12891747   3218.06267946      3.15932565

  Quantity  Unit                turns         degrees        gradians            mils         radians
      6399 turns                    0               0               0               0               0
      6399 degrees              0.775             279             310            4960      4.86946861
      6399 gradians            0.9975           359.1             399            6384      6.26747734
      6399 mils              0.999844       359.94375        399.9375            6399      6.28220356
      6399 radians         0.43248085    155.69310421    172.99233802   2767.87740825      2.71735729

  Quantity  Unit                turns         degrees        gradians            mils         radians
   1000000 turns                    0               0               0               0               0
   1000000 degrees         0.77777778             280    311.11111111   4977.77777778      4.88692191
   1000000 gradians                 0               0               0               0               0
   1000000 mils                  0.25              90             100            1600      1.57079633
   1000000 radians          0.9430919    339.51308233    377.23675814   6035.78813022      5.92562114