Task: Angles (geometric), normalization and conversion


C++: #include <functional>
#include <iostream>
#include <iomanip>
#include <math.h>
#include <sstream>
#include <vector>
#include <boost/algorithm/string.hpp>

template<typename T>
T normalize(T a, double b) { return std::fmod(a, b); }

inline double d2d(double a) { return normalize<double>(a, 360); }
inline double g2g(double a) { return normalize<double>(a, 400); }
inline double m2m(double a) { return normalize<double>(a, 6400); }
inline double r2r(double a) { return normalize<double>(a, 2*M_PI); }

double d2g(double a) { return g2g(a * 10 / 9); }
double d2m(double a) { return m2m(a * 160 / 9); }
double d2r(double a) { return r2r(a * M_PI / 180); }
double g2d(double a) { return d2d(a * 9 / 10); }
double g2m(double a) { return m2m(a * 16); }
double g2r(double a) { return r2r(a * M_PI / 200); }
double m2d(double a) { return d2d(a * 9 / 160); }
double m2g(double a) { return g2g(a / 16); }
double m2r(double a) { return r2r(a * M_PI / 3200); }
double r2d(double a) { return d2d(a * 180 / M_PI); }
double r2g(double a) { return g2g(a * 200 / M_PI); }
double r2m(double a) { return m2m(a * 3200 / M_PI); }

void print(const std::vector<double> &values, const char *s, std::function<double(double)> f) {
    using namespace std;
    ostringstream out;
    out << "                  ┌───────────────────┐\n";
    out << "                  │ " << setw(17) << s << " │\n";
    out << "┌─────────────────┼───────────────────┤\n";
    for (double i : values)
        out << "│ " << setw(15) << fixed << i << defaultfloat << " │ " << setw(17) << fixed << f(i) << defaultfloat << " │\n";
    out << "└─────────────────┴───────────────────┘\n";
    auto str = out.str();
    boost::algorithm::replace_all(str, ".000000", "       ");
    cout << str;
}

int main() {
    std::vector<double> values = { -2, -1, 0, 1, 2, 6.2831853, 16, 57.2957795, 359, 399, 6399, 1000000 };
    print(values, "normalized (deg)", d2d);
    print(values, "normalized (grad)", g2g);
    print(values, "normalized (mil)", m2m);
    print(values, "normalized (rad)", r2r);

    print(values, "deg -> grad ", d2g);
    print(values, "deg -> mil ", d2m);
    print(values, "deg -> rad ", d2r);

    print(values, "grad -> deg ", g2d);
    print(values, "grad -> mil ", g2m);
    print(values, "grad -> rad ", g2r);

    print(values, "mil -> deg ", m2d);
    print(values, "mil -> grad ", m2g);
    print(values, "mil -> rad ", m2r);

    print(values, "rad -> deg ", r2d);
    print(values, "rad -> grad ", r2g);
    print(values, "rad -> mil ", r2m);

    return 0;
}


C#: using System;

public static class Angles
{
    public static void Main() => Print(-2, -1, 0, 1, 2, 6.2831853, 16, 57.2957795, 359, 6399, 1_000_000);

    public static void Print(params double[] angles) {
        string[] names = { "Degrees", "Gradians", "Mils", "Radians" };
        Func<double, double> rnd = a => Math.Round(a, 4);
        Func<double, double>[] normal = { NormalizeDeg, NormalizeGrad, NormalizeMil, NormalizeRad };

        Func<double, double>[,] convert = {
            { a => a, DegToGrad, DegToMil, DegToRad },
            { GradToDeg, a => a, GradToMil, GradToRad },
            { MilToDeg, MilToGrad, a => a, MilToRad },
            { RadToDeg, RadToGrad, RadToMil, a => a }
        };

        Console.WriteLine($@"{"Angle",-12}{"Normalized",-12}{"Unit",-12}{
            "Degrees",-12}{"Gradians",-12}{"Mils",-12}{"Radians",-12}");

        foreach (double angle in angles) {
            for (int i = 0; i < 4; i++) {
                double nAngle = normal[i](angle);

                Console.WriteLine($@"{
                    rnd(angle),-12}{
                    rnd(nAngle),-12}{
                    names[i],-12}{
                    rnd(convert[i, 0](nAngle)),-12}{
                    rnd(convert[i, 1](nAngle)),-12}{
                    rnd(convert[i, 2](nAngle)),-12}{
                    rnd(convert[i, 3](nAngle)),-12}");
            }
        }
    }

    public static double NormalizeDeg(double angle) => Normalize(angle, 360);
    public static double NormalizeGrad(double angle) => Normalize(angle, 400);
    public static double NormalizeMil(double angle) => Normalize(angle, 6400);
    public static double NormalizeRad(double angle) => Normalize(angle, 2 * Math.PI);

    private static double Normalize(double angle, double N) {
        while (angle <= -N) angle += N;
        while (angle >= N) angle -= N;
        return angle;
    }

    public static double DegToGrad(double angle) => angle * 10 / 9;
    public static double DegToMil(double angle) => angle * 160 / 9;
    public static double DegToRad(double angle) => angle * Math.PI / 180;
    
    public static double GradToDeg(double angle) => angle * 9 / 10;
    public static double GradToMil(double angle) => angle * 16;
    public static double GradToRad(double angle) => angle * Math.PI / 200;
    
    public static double MilToDeg(double angle) => angle * 9 / 160;
    public static double MilToGrad(double angle) => angle / 16;
    public static double MilToRad(double angle) => angle * Math.PI / 3200;
    
    public static double RadToDeg(double angle) => angle * 180 / Math.PI;
    public static double RadToGrad(double angle) => angle * 200 / Math.PI;
    public static double RadToMil(double angle) => angle * 3200 / Math.PI;
}