Angles (geometric), normalization and conversion
This task is about the normalization and/or conversion of (geometric) angles using some common scales.
The angular scales that will be used in this task are:
- degree
- gradian
- mil
- radian
- Definitions
The angular scales used or referenced here:
- turn is a full turn or 360 degrees, also shown as 360º
- degree is 1/360 of a turn
- gradian is 1/400 of a turn
- mil is 1/6400 of a turn
- radian is 1/2 of a turn (or 0.5/ of a turn)
Or, to put it another way, for a full circle:
- there are 360 degrees
- there are 400 gradians
- there are 6,400 mils
- there are 2 radians (roughly equal to 6.283+)
A mil is approximately equal to a milliradian (which is 1/1000 of a radian).
There is another definition of a mil which is 1/1000 of a radian ─── this definition won't be used in this Rosetta Code task.
Turns are sometimes known or shown as:
- turn(s)
- 360 degrees
- unit circle
- a (full) circle
Degrees are sometimes known or shown as:
- degree(s)
- deg
- º (a symbol)
- ° (a symbol)
Gradians are sometimes known or shown as:
- gradian(s)
- grad(s)
- grade(s)
- gon(s)
- metric degree(s)
Mils are sometimes known or shown as:
- mil(s)
- NATO mil(s)
Radians are sometimes known or shown as:
- radian(s)
- rad(s)
- Notes
In continental Europe, the French term centigrade was used for 1/100 of a grad (grade); this was one reason for the adoption of the term Celsius to replace centigrade as the name of a temperature scale.
Gradians were commonly used in civil engineering.
Mils were normally used for artillery (elevations for ranging).
- Positive and negative angles
Although the definition of the measurement of an angle doesn't support the concept of a negative angle, it's frequently useful to impose a convention that allows positive and negative angular values to represent orientations and/or rotations in opposite directions relative to some reference. It is this reason that negative angles will keep their sign and not be normalized to positive angles.
- Normalization
Normalization (for this Rosetta Code task) will keep the same sign, but it will reduce the magnitude to less than a full circle; in other words, less than 360º.
Normalization shouldn't change -45º to 315º,
An angle of 0º, +0º, 0.000000, or -0º should be shown as 0º.
- Task
-
- write a function (or equivalent) to do the normalization for each scale
- Suggested names:
- d2d, g2g, m2m, and r2r
- write a function (or equivalent) to convert one scale to another
- Suggested names for comparison of different computer language function names:
- d2g, d2m, and d2r for degrees
- g2d, g2m, and g2r for gradians
- m2d, m2g, and m2r for mils
- r2d, r2g, and r2m for radians
- normalize all angles used (except for the "original" or "base" angle)
- show the angles in every scale and convert them to all other scales
- show all output here on this page
For the (above) conversions, use these dozen numbers (in the order shown):
- -2 -1 0 1 2 6.2831853 16 57.2957795 359 399 6399 1000000
Go
<lang go>package main
import (
"fmt" "math" "strconv" "strings"
)
func d2d(d float64) float64 { return math.Mod(d, 360) }
func g2g(g float64) float64 { return math.Mod(g, 400) }
func m2m(m float64) float64 { return math.Mod(m, 6400) }
func r2r(r float64) float64 { return math.Mod(r, 2*math.Pi) }
func d2g(d float64) float64 { return d2d(d) * 400 / 360 }
func d2m(d float64) float64 { return d2d(d) * 6400 / 360 }
func d2r(d float64) float64 { return d2d(d) * math.Pi / 180 }
func g2d(g float64) float64 { return g2g(g) * 360 / 400 }
func g2m(g float64) float64 { return g2g(g) * 6400 / 400 }
func g2r(g float64) float64 { return g2g(g) * math.Pi / 200 }
func m2d(m float64) float64 { return m2m(m) * 360 / 6400 }
func m2g(m float64) float64 { return m2m(m) * 400 / 6400 }
func m2r(m float64) float64 { return m2m(m) * math.Pi / 3200 }
func r2d(r float64) float64 { return r2r(r) * 180 / math.Pi }
func r2g(r float64) float64 { return r2r(r) * 200 / math.Pi }
func r2m(r float64) float64 { return r2r(r) * 3200 / math.Pi }
// Aligns number to decimal point assuming 7 characters before and after. func s(f float64) string {
wf := strings.Split(strconv.FormatFloat(f, 'g', 15, 64), ".") if len(wf) == 1 { return fmt.Sprintf("%7s ", wf[0]) } le := len(wf[1]) if le > 7 { le = 7 } return fmt.Sprintf("%7s.%-7s", wf[0], wf[1][:le])
}
func main() {
angles := []float64{-2, -1, 0, 1, 2, 6.2831853, 16, 57.2957795, 359, 399, 6399, 1000000} ft := "%s %s %s %s %s\n" fmt.Printf(ft, " degrees ", "normalized degs", " gradians ", " mils ", " radians") for _, a := range angles { fmt.Printf(ft, s(a), s(d2d(a)), s(d2g(a)), s(d2m(a)), s(d2r(a))) } fmt.Printf(ft, "\n gradians ", "normalized grds", " degrees ", " mils ", " radians") for _, a := range angles { fmt.Printf(ft, s(a), s(g2g(a)), s(g2d(a)), s(g2m(a)), s(g2r(a))) } fmt.Printf(ft, "\n mils ", "normalized mils", " degrees ", " gradians ", " radians") for _, a := range angles { fmt.Printf(ft, s(a), s(m2m(a)), s(m2d(a)), s(m2g(a)), s(m2r(a))) } fmt.Printf(ft, "\n radians ", "normalized rads", " degrees ", " gradians ", " mils ") for _, a := range angles { fmt.Printf(ft, s(a), s(r2r(a)), s(r2d(a)), s(r2g(a)), s(r2m(a))) }
}</lang>
- Output:
degrees normalized degs gradians mils radians -2 -2 -2.2222222 -35.5555555 -0.0349065 -1 -1 -1.1111111 -17.7777777 -0.0174532 0 0 0 0 0 1 1 1.1111111 17.7777777 0.0174532 2 2 2.2222222 35.5555555 0.0349065 6.2831853 6.2831853 6.981317 111.701072 0.1096622 16 16 17.7777777 284.4444444 0.2792526 57.2957795 57.2957795 63.6619772 1018.5916355 0.9999999 359 359 398.8888888 6382.2222222 6.2657320 399 39 43.3333333 693.3333333 0.6806784 6399 279 310 4960 4.8694686 1000000 280 311.1111111 4977.7777777 4.8869219 gradians normalized grds degrees mils radians -2 -2 -1.8 -32 -0.0314159 -1 -1 -0.9 -16 -0.0157079 0 0 0 0 0 1 1 0.9 16 0.0157079 2 2 1.8 32 0.0314159 6.2831853 6.2831853 5.6548667 100.5309648 0.0986960 16 16 14.4 256 0.2513274 57.2957795 57.2957795 51.5662015 916.732472 0.8999999 359 359 323.1 5744 5.6391588 399 399 359.1 6384 6.2674773 6399 399 359.1 6384 6.2674773 1000000 0 0 0 0 mils normalized mils degrees gradians radians -2 -2 -0.1125 -0.125 -0.0019634 -1 -1 -0.05625 -0.0625 -0.0009817 0 0 0 0 0 1 1 0.05625 0.0625 0.0009817 2 2 0.1125 0.125 0.0019634 6.2831853 6.2831853 0.3534291 0.3926990 0.0061685 16 16 0.9 1 0.0157079 57.2957795 57.2957795 3.2228875 3.5809862 0.0562499 359 359 20.19375 22.4375 0.3524474 399 399 22.44375 24.9375 0.3917173 6399 6399 359.94375 399.9375 6.2822035 1000000 1600 90 100 1.5707963 radians normalized rads degrees gradians mils -2 -2 -114.5915590 -127.3239544 -2037.1832715 -1 -1 -57.2957795 -63.6619772 -1018.5916357 0 0 0 0 0 1 1 57.2957795 63.6619772 1018.5916357 2 2 114.5915590 127.3239544 2037.1832715 6.2831853 6.2831853 359.9999995 399.9999995 6399.9999926 16 3.4336293 196.7324722 218.5916357 3497.4661726 57.2957795 0.7471117 42.8063492 47.5626102 761.0017646 359 0.8584374 49.1848451 54.6498279 874.3972479 399 3.1593256 181.0160257 201.1289174 3218.0626794 6399 2.7173572 155.6931042 172.9923380 2767.8774082 1000000 5.9256211 339.5130823 377.2367581 6035.7881301
Julia
<lang julia>using Formatting
d2d(d) = d % 360 g2g(g) = g % 400 m2m(m) = m % 6400 r2r(r) = r % 2π d2g(d) = d2d(d) * 10 / 9 d2m(d) = d2d(d) * 160 / 9 d2r(d) = d2d(d) * π / 180 g2d(g) = g2g(g) * 9 / 10 g2m(g) = g2g(g) * 16 g2r(g) = g2g(g) * π / 200 m2d(m) = m2m(m) * 9 / 160 m2g(m) = m2m(m) / 16 m2r(m) = m2m(m) * π / 3200 r2d(r) = r2r(r) * 180 / π r2g(r) = r2r(r) * 200 / π r2m(r) = r2r(r) * 3200 / π
fmt(x::Real, width=16) = Int(round(x)) == x ? rpad(Int(x), width) :
rpad(format(x, precision=7), width)
fmt(x::String, width=16) = rpad(x, width)
const t2u = Dict("degrees" => [d2d, d2g, d2m, d2r],
"gradians" => [g2d, g2g, g2m, g2r], "mils" => [m2d, m2g, m2m, m2r], "radians" => [r2d, r2g, r2m, r2r])
function testconversions(arr)
println("Number Units Degrees Gradians Mils Radians") for num in arr, units in ["degrees", "gradians", "mils", "radians"] print(fmt(num), fmt(units)) for f in t2u[units] print(fmt(f(num))) end println() end
end
testconversions([-2, -1, 0, 1, 2, 6.2831853, 16, 57.2957795, 359, 399, 6399, 1000000])
</lang>
- Output:
Number Units Degrees Gradians Mils Radians -2 degrees -2 -2.2222222 -35.5555556 -0.0349066 -2 gradians -1.8000000 -2 -32 -0.0314159 -2 mils -0.1125000 -0.1250000 -2 -0.0019635 -2 radians -114.5915590 -127.3239545 -2037.1832716 -2 -1 degrees -1 -1.1111111 -17.7777778 -0.0174533 -1 gradians -0.9000000 -1 -16 -0.0157080 -1 mils -0.0562500 -0.0625000 -1 -0.0009817 -1 radians -57.2957795 -63.6619772 -1018.5916358 -1 0 degrees 0 0 0 0 0 gradians 0 0 0 0 0 mils 0 0 0 0 0 radians 0 0 0 0 1 degrees 1 1.1111111 17.7777778 0.0174533 1 gradians 0.9000000 1 16 0.0157080 1 mils 0.0562500 0.0625000 1 0.0009817 1 radians 57.2957795 63.6619772 1018.5916358 1 2 degrees 2 2.2222222 35.5555556 0.0349066 2 gradians 1.8000000 2 32 0.0314159 2 mils 0.1125000 0.1250000 2 0.0019635 2 radians 114.5915590 127.3239545 2037.1832716 2 6.2831853 degrees 6.2831853 6.9813170 111.7010720 0.1096623 6.2831853 gradians 5.6548668 6.2831853 100.5309648 0.0986960 6.2831853 mils 0.3534292 0.3926991 6.2831853 0.0061685 6.2831853 radians 359.9999996 399.9999995 6399.9999927 6.2831853 16 degrees 16 17.7777778 284.4444444 0.2792527 16 gradians 14.4000000 16 256 0.2513274 16 mils 0.9000000 1 16 0.0157080 16 radians 196.7324722 218.5916358 3497.4661726 3.4336294 57.2957795 degrees 57.2957795 63.6619772 1018.5916356 1.0000000 57.2957795 gradians 51.5662016 57.2957795 916.7324720 0.9000000 57.2957795 mils 3.2228876 3.5809862 57.2957795 0.0562500 57.2957795 radians 42.8063493 47.5626103 761.0017647 0.7471117 359 degrees 359 398.8888889 6382.2222222 6.2657320 359 gradians 323.1000000 359 5744 5.6391588 359 mils 20.1937500 22.4375000 359 0.3524474 359 radians 49.1848452 54.6498280 874.3972479 0.8584375 399 degrees 39 43.3333333 693.3333333 0.6806784 399 gradians 359.1000000 399 6384 6.2674773 399 mils 22.4437500 24.9375000 399 0.3917173 399 radians 181.0160257 201.1289175 3218.0626795 3.1593256 6399 degrees 279 310 4960 4.8694686 6399 gradians 359.1000000 399 6384 6.2674773 6399 mils 359.9437500 399.9375000 6399 6.2822036 6399 radians 155.6931042 172.9923380 2767.8774082 2.7173573 1000000 degrees 280 311.1111111 4977.7777778 4.8869219 1000000 gradians 0 0 0 0 1000000 mils 90 100 1600 1.5707963 1000000 radians 339.5130823 377.2367581 6035.7881302 5.9256211
REXX
<lang rexx>/*REXX pgm normalizes an angle (in a scale), or converts angles from a scale to another.*/ numeric digits length( pi() ) - length(.) /*use the "length" of pi for precision.*/ parse arg x /*obtain optional arguments from the CL*/ if x= | x="," then x= '-2 -1 0 1 2 6.2831853 16 57.2957795 359 399 6399 1000000' w= 20; w7= w+7 /*W: # dec digits past the dec. point.*/ @deg = 'degrees'; @grd= "gradians"; @mil = 'mils'; @rad = "radians"
- = words(x)
call hdr @deg @grd @mil @rad
do j=1 for #; y= word(x,j) say shw(y) fmt(d2d(y)) fmt(d2g(y)) fmt(d2m(y)) fmt(d2r(y)) end /*j*/
call hdr @grd @deg @mil @rad
do j=1 for #; y= word(x,j) say shw(y) fmt(g2g(y)) fmt(g2d(y)) fmt(g2m(y)) fmt(g2r(y)) end /*j*/
call hdr @mil @deg @grd @rad
do j=1 for #; y= word(x,j) say shw(y) fmt(m2m(y)) fmt(m2d(y)) fmt(m2g(y)) fmt(m2r(y)) end /*j*/
call hdr @rad @deg @grd @mil
do j=1 for #; y= word(x,j) say shw(y) fmt(r2r(y)) fmt(r2d(y)) fmt(r2g(y)) fmt(r2m(y)) end /*j*/
exit /*stick a fork in it, we're all done. */ /*──────────────────────────────────────────────────────────────────────────────────────*/ fmt: _= format(arg(1), 6,w); L= length(_); return left(format(_/1, 6),L) /*align a #*/ shw: _= format(arg(1),12,9); L= length(_); return left(format(_/1,12),L) /* " " "*/ pi: pi= 3.1415926535897932384626433832795028841971693993751058209749445923078; return pi d2g: return d2d(arg(1)) * 10 / 9 /*convert degrees ───► gradians. */ d2m: return d2d(arg(1)) * 160 / 9 /*convert degrees ───► mils. */ d2r: return d2d(arg(1)) * pi() / 180 /*convert degrees ───► radians. */ g2d: return g2g(arg(1)) * 0.9 /*convert gradians ───► degrees. */ g2m: return g2g(arg(1)) * 16 /*convert gradians ───► mils. */ g2r: return g2g(arg(1)) * pi() * 0.005 /*convert gradians ───► radians. */ m2d: return m2m(arg(1)) * 9 * 0.00625 /*convert mils ───► degrees. */ m2g: return m2m(arg(1)) / 16 /*convert mils ───► gradians. */ m2r: return m2m(arg(1)) * pi() / 3200 /*convert mils ───► radians. */ r2d: return r2r(arg(1)) * 180 / pi() /*convert radians ───► degrees. */ r2g: return r2r(arg(1)) * 200 / pi() /*convert radians ───► gradians. */ r2m: return r2r(arg(1)) * 3200 / pi() /*convert radians ───► mils. */ d2d: return arg(1) // 360 /*normalize degrees ───► a unit circle.*/ g2g: return arg(1) // 400 /*normalize gradians───► a unit circle.*/ m2m: return arg(1) // 6400 /*normalize mils ───► a unit circle.*/ r2r: return arg(1) // (pi() * 2) /*normalize radians ───► a unit circle.*/ /*──────────────────────────────────────────────────────────────────────────────────────*/ hdr: parse arg #o #a #b #c .; _= '═'; say /* [↓] the header line*/
@n = 'normalized' say center(#o,23 ) center(@n #o,w7) center(#a,w7 ) center(#b,w7 ) center(#c,w7 ) say center(,23,_) center(,w7, _) center(,w7,_) center(,w7,_) center(,w7,_) return /* '↑' seperator line.*/</lang>
- output when using the default input:
degrees normalized degrees gradians mils radians ═══════════════════════ ═══════════════════════════ ═══════════════════════════ ═══════════════════════════ ═══════════════════════════ -2 -2 -2.22222222222222222222 -35.55555555555555555556 -0.03490658503988659154 -1 -1 -1.11111111111111111111 -17.77777777777777777778 -0.01745329251994329577 0 0 0 0 0 1 1 1.11111111111111111111 17.77777777777777777778 0.01745329251994329577 2 2 2.22222222222222222222 35.55555555555555555556 0.03490658503988659154 6.2831853 6.2831853 6.981317 111.701072 0.10966227099790767281 16 16 17.77777777777777777778 284.44444444444444444444 0.27925268031909273231 57.2957795 57.2957795 63.66197722222222222222 1018.59163555555555555556 0.9999999997716704269 359 359 398.88888888888888888889 6382.22222222222222222222 6.26573201465964318116 399 39 43.33333333333333333333 693.33333333333333333333 0.680678408277788535 6399 279 310 4960 4.86946861306417951962 1000000 280 311.11111111111111111111 4977.77777777777777777778 4.88692190558412281539 gradians normalized gradians degrees mils radians ═══════════════════════ ═══════════════════════════ ═══════════════════════════ ═══════════════════════════ ═══════════════════════════ -2 -2 -1.8 -32 -0.03141592653589793238 -1 -1 -0.9 -16 -0.01570796326794896619 0 0 0 0 0 1 1 0.9 16 0.01570796326794896619 2 2 1.8 32 0.03141592653589793238 6.2831853 6.2831853 5.65486677 100.5309648 0.09869604389811690553 16 16 14.4 256 0.25132741228718345908 57.2957795 57.2957795 51.56620155 916.732472 0.89999999979450338421 359 359 323.1 5744 5.63915881319367886304 399 399 359.1 6384 6.26747734391163751073 6399 399 359.1 6384 6.26747734391163751073 1000000 0 0 0 0 mils normalized mils degrees gradians radians ═══════════════════════ ═══════════════════════════ ═══════════════════════════ ═══════════════════════════ ═══════════════════════════ -2 -2 -0.1125 -0.125 -0.00196349540849362077 -1 -1 -0.05625 -0.0625 -0.00098174770424681039 0 0 0 0 0 1 1 0.05625 0.0625 0.00098174770424681039 2 2 0.1125 0.125 0.00196349540849362077 6.2831853 6.2831853 0.353429173125 0.39269908125 0.0061685027436323066 16 16 0.9 1 0.01570796326794896619 57.2957795 57.2957795 3.222887596875 3.58098621875 0.05624999998715646151 359 359 20.19375 22.4375 0.35244742582460492894 399 399 22.44375 24.9375 0.39171733399447734442 6399 6399 359.94375 399.9375 6.28220355947533966654 1000000 1600 90 100 1.57079632679489661923 radians normalized radians degrees gradians mils ═══════════════════════ ═══════════════════════════ ═══════════════════════════ ═══════════════════════════ ═══════════════════════════ -2 -2 -114.5915590261646417536 -127.32395447351626861511 -2037.18327157626029784171 -1 -1 -57.2957795130823208768 -63.66197723675813430755 -1018.59163578813014892086 0 0 0 0 0 1 1 57.2957795130823208768 63.66197723675813430755 1018.59163578813014892086 2 2 114.5915590261646417536 127.32395447351626861511 2037.18327157626029784171 6.2831853 6.2831853 359.99999958863999622298 399.99999954293332913665 6399.99999268693326618633 16 3.43362938564082704615 196.73247220931713402877 218.59163578813014892086 3497.4661726100823827337 57.2957795 0.74711173538372170767 42.80634926218202230527 47.56261029131335811697 761.00176466101372987153 359 0.85843749076357081526 49.18484519655319477054 54.64982799617021641171 874.39724793872346258733 399 3.15932564768605195371 181.01602571984602984246 201.12891746649558871385 3218.06267946392941942158 6399 2.71735729118096649006 155.69310421377129063139 172.99233801530143403488 2767.87740824482294455809 1000000 5.92562114009385143291 339.51308232087679815481 377.23675813430755350535 6035.78813014892085608558