Angle difference between two bearings
You are encouraged to solve this task according to the task description, using any language you may know.
Finding the angle between two bearings is often confusing.[1]
- Task
Find the angle which is the result of the subtraction b2 - b1, where b1 and b2 are the bearings.
Input bearings are expressed in the range -180 to +180 degrees.
The result is also expressed in the range -180 to +180 degrees.
Compute the angle for the following pairs:
- 20 degrees (b1) and 45 degrees (b2)
- -45 and 45
- -85 and 90
- -95 and 90
- -45 and 125
- -45 and 145
- 29.4803 and -88.6381
- -78.3251 and -159.036
- Optional extra
Allow the input bearings to be any (finite) value.
- Test cases
- -70099.74233810938 and 29840.67437876723
- -165313.6666297357 and 33693.9894517456
- 1174.8380510598456 and -154146.66490124757
- 60175.77306795546 and 42213.07192354373
11l
F get_difference(b1, b2)
R wrap(b2 - b1, -180.0, 180.0)
print(get_difference( 20.0, 45.0))
print(get_difference(-45.0, 45.0))
print(get_difference(-85.0, 90.0))
print(get_difference(-95.0, 90.0))
print(get_difference(-45.0, 125.0))
print(get_difference(-45.0, 145.0))
print(get_difference(-45.0, 125.0))
print(get_difference(-45.0, 145.0))
print(get_difference(29.4803, -88.6381))
print(get_difference(-78.3251, -159.036))
print(‘’)
print(get_difference(-70099.74233810938, 29840.67437876723))
print(get_difference(-165313.6666297357, 33693.9894517456))
print(get_difference(1174.8380510598456, -154146.66490124757))
print(get_difference(60175.77306795546, 42213.07192354373))
- Output:
25 90 175 -175 170 -170 170 -170 -118.118 -80.7109 -139.583 -72.3439 -161.503 37.2989
360 Assembly
* Angle difference between two bearings - 06/06/2018
ANGLEDBB CSECT
USING ANGLEDBB,R13 base register
B 72(R15) skip savearea
DC 17F'0' savearea
SAVE (14,12) save previous context
ST R13,4(R15) link backward
ST R15,8(R13) link forward
LR R13,R15 set addressability
LA R10,T-4 @t
LA R6,1 i=1
DO WHILE=(C,R6,LE,N) do i=1 to n
LA R10,4(R10) next @t
L R7,0(R10) a=t(i,1)
LA R10,4(R10) next @t
L R8,0(R10) b=t(i,2)
LR R4,R8 b
SR R4,R7 b-a
SRDA R4,32 ~
D R4,=F'3600000' /360
A R4,=F'5400000' +540
SRDA R4,32 ~
D R4,=F'3600000' /360
S R4,=F'1800000' x=((((b-a)//360)+540)//360)-180
XDECO R7,XDEC edit a
MVC PG(8),XDEC output a
MVC PG+9(4),XDEC+8 output a decimals
XDECO R8,XDEC edit b
MVC PG+14(8),XDEC output b
MVC PG+23(4),XDEC+8 output b decimals
XDECO R4,XDEC edit x
MVC PG+28(8),XDEC output x
MVC PG+37(4),XDEC+8 output x decimals
XPRNT PG,L'PG print
LA R6,1(R6) i++
ENDDO , enddo i
L R13,4(0,R13) restore previous savearea pointer
RETURN (14,12),RC=0 restore registers from calling sav
N DC F'8' number of pairs
T DC F'200000',F'450000',F'-450000',F'450000'
DC F'-850000',F'900000',F'-950000',F'900000'
DC F'-450000',F'1250000',F'450000',F'1450000'
DC F'294803',F'-886361',F'-783251',F'-1590360'
PG DC CL80'12345678.1234 12345678.1234 12345678.1234'
XDEC DS CL12 temp
YREGS
END ANGLEDBB
- Output:
20.0000 45.0000 25.0000 -45.0000 45.0000 90.0000 -85.0000 90.0000 175.0000 -95.0000 90.0000 -175.0000 -45.0000 125.0000 170.0000 45.0000 145.0000 100.0000 29.4803 -88.6361 -118.1164 -78.3251 -159.0360 -80.7109
AArch64 Assembly
/* ARM assembly AARCH64 Raspberry PI 3B */
/* program diffAngle64.s */
/************************************/
/* Constantes */
/************************************/
.include "../includeConstantesARM64.inc"
/*********************************/
/* Initialized data */
/*********************************/
.data
szCarriageReturn: .asciz "\n"
szMessResult: .asciz "Difference between @ and @ = @ \n"
.align 8
fB1: .double 0F20.0
fB2: .double 0F45.0
fB3: .double 0F-45.0
fB4: .double 0F-85.0
fB5: .double 90.0
fB6: .double -95.0
fB7: .double 125.0
fB8: .double 145.0
fB9: .double 0F29.4803
fB10: .double 0F-88.6381
fB11: .double 0F-78.3251
fB12: .double 0F-159.036
fB13: .double 0F-70099.74233810938
fB14: .double 0F29840.67437876723
/*********************************/
/* UnInitialized data */
/*********************************/
.bss
sZoneConv: .skip 24
/*********************************/
/* code section */
/*********************************/
.text
.global main
main:
ldr x0,qAdrfB1
ldr x1,qAdrfB2
bl testComputeAngle
//b 100f
ldr x0,qAdrfB3
ldr x1,qAdrfB2
bl testComputeAngle
ldr x0,qAdrfB4
ldr x1,qAdrfB5
bl testComputeAngle
ldr x0,qAdrfB6
ldr x1,qAdrfB5
bl testComputeAngle
ldr x0,qAdrfB3
ldr x1,qAdrfB7
bl testComputeAngle
ldr x0,qAdrfB3
ldr x1,qAdrfB8
bl testComputeAngle
ldr x0,qAdrfB9
ldr x1,qAdrfB10
bl testComputeAngle
ldr x0,qAdrfB11
ldr x1,qAdrfB12
bl testComputeAngle
ldr x0,qAdrfB13
ldr x1,qAdrfB14
bl testComputeAngle
100: // standard end of the program
mov x0, #0 // return code
mov x8,EXIT
svc #0 // perform the system call
qAdrszCarriageReturn: .quad szCarriageReturn
qAdrsZoneConv: .quad sZoneConv
qAdrfB1: .quad fB1
qAdrfB2: .quad fB2
qAdrfB3: .quad fB3
qAdrfB4: .quad fB4
qAdrfB5: .quad fB5
qAdrfB6: .quad fB6
qAdrfB7: .quad fB7
qAdrfB8: .quad fB8
qAdrfB9: .quad fB9
qAdrfB10: .quad fB10
qAdrfB11: .quad fB11
qAdrfB12: .quad fB12
qAdrfB13: .quad fB13
qAdrfB14: .quad fB14
/******************************************************************/
/* compute difference and display result */
/******************************************************************/
/* s0 contains bearing 1 */
/* s1 contains bearing 2 */
testComputeAngle:
stp x1,lr,[sp,-16]! // save registers
stp x2,x3,[sp,-16]! // save registers
ldr d0,[x0]
fmov d2,d0
ldr d1,[x1]
bl computeDiffAngle
fmov d3,d0
fmov d0,d2
ldr x0,qAdrsZoneConv
bl convertirFloat
ldr x0,qAdrszMessResult
ldr x1,qAdrsZoneConv
bl strInsertAtCharInc
mov x3,x0
fmov d0,d1
ldr x0,qAdrsZoneConv
bl convertirFloat
mov x0,x3
ldr x1,qAdrsZoneConv
bl strInsertAtCharInc
mov x3,x0
fmov d0,d3
ldr x0,qAdrsZoneConv
bl convertirFloat
mov x0,x3
ldr x1,qAdrsZoneConv
bl strInsertAtCharInc
bl affichageMess
100:
ldp x2,x3,[sp],16 // restaur registers
ldp x1,lr,[sp],16 // restaur registers
ret
qAdrszMessResult: .quad szMessResult
/******************************************************************/
/* compute difference of two bearing */
/******************************************************************/
/* d0 contains bearing 1 */
/* d1 contains bearing 2 */
computeDiffAngle:
stp x1,lr,[sp,-16]! // save registers
stp x2,x3,[sp,-16]! // save registers
stp x4,x5,[sp,-16]! // save registers
stp d1,d2,[sp,-16]! // save registres
stp d3,d4,[sp,-16]! // save registres
mov x1,#360
mov x4,#0 // top positive/negative
fcvtzs d4,d0 // conversion.integer
scvtf d2,d4 // conversion float
fsub d2,d0,d2 // partie décimale
fmov x0,d4 // partie entière
cmp x0,#0 // negative ?
bge 1f
neg x0,x0 // yes -> inversion
mov x4,#1
1:
udiv x2,x0,x1 // divide by 360
msub x3,x2,x1,x0
cmp x4,#0 // value negative ?
neg x5,x3
csel x3,x5,x3,ne // inversion remainder
fmov d3,x3
scvtf d3,d3 // and conversion float
fadd d0,d3,d2 // add decimal part
mov x4,#0 // bearing 2
fcvtzs d4,d1 // conversion integer
scvtf d2,d4 // conversion float
fsub d2,d1,d2 // partie décimale
fmov x0,d4
cmp x0,#0
bge 2f
neg x0,x0
mov x4,#1
2:
udiv x2,x0,x1 // divide by 360
msub x3,x2,x1,x0
cmp x4,#0
neg x5,x3
csel x3,x5,x3,ne // inversion remainder
fmov d3,x3
scvtf d3,d3 // conversion float
fadd d1,d3,d2
fsub d0,d1,d0 // calculate the difference between the 2 values
mov x0,180
fmov d3,x0
scvtf d3,d3 // conversion float 180
fmov d4,x1 // 360
scvtf d4,d4 // conversion float 360
fcmp d0,#0.0 // difference is negative ?
blt 2f
// difference is positive
fcmp d0,d4 // difference > 360
ble 3f
fsub d0,d0,d4 // yes -> difference - 360
3:
fcmp d0,d3 // compare difference and 180
ble 100f
fsub d0,d4,d0 // > 180 calculate 360 - difference
fneg d0,d0 // and negate
b 100f
2: // différence is négative
fneg d2,d4 // -360
fcmp d0,d2 // compare différence et - 360
ble 3f
fsub d0,d0,d4 // sub 360 to différence
3:
fneg d3,d3 // -180
fcmp d0,d3 // compare difference and -180
bge 100f
fadd d0,d4,d0 // calculate 360 + différence
100:
ldp d3,d4,[sp],16 // restaur registers
ldp d1,d2,[sp],16 // restaur registers
ldp x4,x5,[sp],16 // restaur registers
ldp x2,x3,[sp],16 // restaur registers
ldp x1,lr,[sp],16 // restaur registers
ret
/******************************************************************/
/* Conversion Float */
/******************************************************************/
/* d0 contains Float */
/* x0 contains address conversion area mini 20 charactèrs */
/* x0 return result length */
/* see https://blog.benoitblanchon.fr/lightweight-float-to-string/ */
convertirFloat:
stp x1,lr,[sp,-16]! // save registres
stp x2,x3,[sp,-16]! // save registres
stp x4,x5,[sp,-16]! // save registres
stp x6,x7,[sp,-16]! // save registres
stp x8,x9,[sp,-16]! // save registres
stp d1,d2,[sp,-16]! // save registres
mov x6,x0 // save area address
fmov x0,d0
mov x8,#0 // result length
mov x3,#'+'
strb w3,[x6] // signe + forcing
mov x2,x0
tbz x2,63,1f
mov x2,1
lsl x2,x2,63
bic x0,x0,x2
mov x3,#'-' // sign -
strb w3,[x6]
1:
adds x8,x8,#1 // next position
cmp x0,#0 // case 0 positive or negative
bne 2f
mov x3,#'0'
strb w3,[x6,x8] // store character 0
adds x8,x8,#1
strb wzr,[x6,x8] // store 0 final
mov x0,x8 // return length
b 100f
2:
ldr x2,iMaskExposant
mov x1,x0
and x1,x1,x2 // exposant
cmp x1,x2
bne 4f
tbz x0,51,3f // test bit 51 to zéro
mov x2,#'N' // case Nan. store byte no possible store integer
strb w2,[x6] // area no aligned
mov x2,#'a'
strb w2,[x6,#1]
mov x2,#'n'
strb w2,[x6,#2]
mov x2,#0 // 0 final
strb w2,[x6,#3]
mov x0,#3
b 100f
3: // case infini positive or négative
mov x2,#'I'
strb w2,[x6,x8]
adds x8,x8,#1
mov x2,#'n'
strb w2,[x6,x8]
adds x8,x8,#1
mov x2,#'f'
strb w2,[x6,x8]
adds x8,x8,#1
mov x2,#0
strb w2,[x6,x8]
mov x0,x8
b 100f
4:
bl normaliserFloat
mov x5,x0 // save exposant
fcvtzu d2,d0
fmov x0,d2 // part integer
scvtf d1,d2 // conversion float
fsub d1,d0,d1 // extraction part fractional
ldr d2,dConst1
fmul d1,d2,d1 // to crop it in full
fcvtzu d1,d1 // convertion integer
fmov x4,d1 // fract value
// conversion part integer to x0
mov x2,x6 // save address begin area
adds x6,x6,x8
mov x1,x6
bl conversion10
add x6,x6,x0
mov x3,#','
strb w3,[x6]
adds x6,x6,#1
mov x0,x4 // conversion part fractionnaire
mov x1,x6
bl conversion10SP
add x6,x6,x0
sub x6,x6,#1
// remove trailing zeros
5:
ldrb w0,[x6]
cmp w0,#'0'
bne 6f
sub x6,x6,#1
b 5b
6:
cmp w0,#','
bne 7f
sub x6,x6,#1
7:
cmp x5,#0 // if exposant = 0 no display
bne 8f
add x6,x6,#1
b 10f
8:
add x6,x6,#1
mov x3,#'E'
strb w3,[x6]
add x6,x6,#1
mov x0,x5 // conversion exposant
mov x3,x0
tbz x3,63,9f // exposant negative ?
neg x0,x0
mov x3,#'-'
strb w3,[x6]
adds x6,x6,#1
9:
mov x1,x6
bl conversion10
add x6,x6,x0
10:
strb wzr,[x6] // store 0 final
adds x6,x6,#1
mov x0,x6
subs x0,x0,x2 // retour de la longueur de la zone
subs x0,x0,#1 // sans le 0 final
100:
ldp d1,d2,[sp],16 // restaur registres
ldp x8,x9,[sp],16 // restaur registres
ldp x6,x7,[sp],16 // restaur registres
ldp x4,x5,[sp],16 // restaur registres
ldp x2,x3,[sp],16 // restaur registres
ldp x1,lr,[sp],16 // restaur registres
ret
iMaskExposant: .quad 0x7FF<<52
dConst1: .double 0f1E17
/***************************************************/
/* normaliser float */
/***************************************************/
/* x0 contain float value (always positive value and <> Nan) */
/* d0 return new value */
/* x0 return exposant */
normaliserFloat:
stp x1,lr,[sp,-16]! // save registers
fmov d0,x0 // value float
mov x0,#0 // exposant
ldr d1,dConstE7 // no normalisation for value < 1E7
fcmp d0,d1
blo 10f // if d0 < dConstE7
ldr d1,dConstE256
fcmp d0,d1
blo 1f
fdiv d0,d0,d1
adds x0,x0,#256
1:
ldr d1,dConstE128
fcmp d0,d1
blo 1f
fdiv d0,d0,d1
adds x0,x0,#128
1:
ldr d1,dConstE64
fcmp d0,d1
blo 1f
fdiv d0,d0,d1
adds x0,x0,#64
1:
ldr d1,dConstE32
fcmp d0,d1
blo 1f
fdiv d0,d0,d1
adds x0,x0,#32
1:
ldr d1,dConstE16
fcmp d0,d1
blo 2f
fdiv d0,d0,d1
adds x0,x0,#16
2:
ldr d1,dConstE8
fcmp d0,d1
blo 3f
fdiv d0,d0,d1
adds x0,x0,#8
3:
ldr d1,dConstE4
fcmp d0,d1
blo 4f
fdiv d0,d0,d1
adds x0,x0,#4
4:
ldr d1,dConstE2
fcmp d0,d1
blo 5f
fdiv d0,d0,d1
adds x0,x0,#2
5:
ldr d1,dConstE1
fcmp d0,d1
blo 10f
fdiv d0,d0,d1
adds x0,x0,#1
10:
ldr d1,dConstME5 // pas de normalisation pour les valeurs > 1E-5
fcmp d0,d1
bhi 100f // fin
ldr d1,dConstME255
fcmp d0,d1
bhi 11f
ldr d1,dConstE256
fmul d0,d0,d1
subs x0,x0,#256
11:
ldr d1,dConstME127
fcmp d0,d1
bhi 11f
ldr d1,dConstE128
fmul d0,d0,d1
subs x0,x0,#128
11:
ldr d1,dConstME63
fcmp d0,d1
bhi 11f
ldr d1,dConstE64
fmul d0,d0,d1
subs x0,x0,#64
11:
ldr d1,dConstME31
fcmp d0,d1
bhi 11f
ldr d1,dConstE32
fmul d0,d0,d1
subs x0,x0,#32
11:
ldr d1,dConstME15
fcmp d0,d1
bhi 12f
ldr d1,dConstE16
fmul d0,d0,d1
subs x0,x0,#16
12:
ldr d1,dConstME7
fcmp d0,d1
bhi 13f
ldr d1,dConstE8
fmul d0,d0,d1
subs x0,x0,#8
13:
ldr d1,dConstME3
fcmp d0,d1
bhi 14f
ldr d1,dConstE4
fmul d0,d0,d1
subs x0,x0,#4
14:
ldr d1,dConstME1
fcmp d0,d1
bhi 15f
ldr d1,dConstE2
fmul d0,d0,d1
subs x0,x0,#2
15:
ldr d1,dConstE0
fcmp d0,d1
bhi 100f
ldr d1,dConstE1
fmul d0,d0,d1
subs x0,x0,#1
100: // fin standard de la fonction
ldp x1,lr,[sp],16 // restaur registres
ret
.align 2
dConstE7: .double 0f1E7
dConstE256: .double 0f1E256
dConstE128: .double 0f1E128
dConstE64: .double 0f1E64
dConstE32: .double 0f1E32
dConstE16: .double 0f1E16
dConstE8: .double 0f1E8
dConstE4: .double 0f1E4
dConstE2: .double 0f1E2
dConstE1: .double 0f1E1
dConstME5: .double 0f1E-5
dConstME255: .double 0f1E-255
dConstME127: .double 0f1E-127
dConstME63: .double 0f1E-63
dConstME31: .double 0f1E-31
dConstME15: .double 0f1E-15
dConstME7: .double 0f1E-7
dConstME3: .double 0f1E-3
dConstME1: .double 0f1E-1
dConstE0: .double 0f1E0
/******************************************************************/
/* Décimal Conversion */
/******************************************************************/
/* x0 contain value et x1 address conversion area */
conversion10SP:
stp x1,lr,[sp,-16]! // save registers
stp x2,x3,[sp,-16]! // save registers
stp x4,x5,[sp,-16]! // save registers
mov x5,x1
mov x4,#16
mov x2,x0
mov x1,#10 // décimal conversion
1: // conversion loop
mov x0,x2 // copy begin number or quotient
udiv x2,x0,x1 // division by 10
msub x3,x1,x2,x0 // compute remainder
add x3,x3,#48 // compute digit
strb w3,[x5,x4] // store byte address area (x5) + offset (x4)
subs x4,x4,#1 // position precedente
bge 1b
strb wzr,[x5,16] // 0 final
100:
ldp x4,x5,[sp],16 // restaur registers
ldp x2,x3,[sp],16 // restaur registers
ldp x1,lr,[sp],16 // restaur registers
ret
/***************************************************/
/* ROUTINES INCLUDE */
/***************************************************/
.include "../includeARM64.inc"
Difference between +20 and +45 = +25 Difference between -45 and +45 = +90 Difference between -85 and +90 = +175 Difference between -95 and +90 = -175 Difference between -45 and +125 = +170 Difference between -45 and +145 = -170 Difference between +29,4802 and -88,638099 = -118,1 Difference between -78,325 and -159 = -80,7108999 Difference between -70099,7423381 and +29840,674378 = -139,58328
Action!
INCLUDE "H6:REALMATH.ACT"
INT FUNC AngleI(INT a1,a2)
INT r
r=a2-a1
WHILE r>180 DO r==-360 OD
WHILE r<-180 DO r==+360 OD
RETURN (r)
PROC TestI(INT a1,a2)
INT r
r=AngleI(a1,a2)
PrintF("%I .. %I = %I%E",a1,a2,r)
RETURN
PROC AngleR(REAL POINTER r1,r2,r)
REAL tmp,r180,rm180,r360
ValR("180",r180)
ValR("-180",rm180)
ValR("360",r360)
RealSub(r2,r1,r)
WHILE RealGreaterOrEqual(r,r180)
DO
RealSub(r,r360,tmp) RealAssign(tmp,r)
OD
WHILE RealGreaterOrEqual(rm180,r)
DO
RealAdd(r,r360,tmp) RealAssign(tmp,r)
OD
RETURN
PROC TestR(CHAR ARRAY s1,s2)
REAL r1,r2,r
ValR(s1,r1) ValR(s2,r2)
AngleR(r1,r2,r)
PrintR(r1) Print(" .. ") PrintR(r2)
Print(" = ") PrintRE(r)
RETURN
PROC Main()
Put(125) PutE() ;clear screen
TestI(20,45)
TestI(-45,45)
TestI(-85,90)
TestI(-95,90)
TestI(-45,125)
TestI(-45,145)
TestR("29.4803","-88.6381")
TestR("-78.3251","-159.036")
TestR("-70099.74233810938","29840.67437876723")
TestR("-165313.6666297357","33693.9894517456")
TestR("1174.8380510598456","-154146.66490124757")
TestR("60175.77306795546","42213.07192354373")
RETURN
- Output:
Screenshot from Atari 8-bit computer
20 .. 45 = 25 -45 .. 45 = 90 -85 .. 90 = 175 -95 .. 90 = -175 -45 .. 125 = 170 -45 .. 145 = -170 29.4803 .. -88.6381 = -118.1184 -78.3251 .. -159.036 = -80.7109 -70099.7423 .. 29840.6743 = -139.5834 -165313.666 .. 33693.9894 = -72.3446 1174.83805 .. -154146.664 = -161.502 60175.773 .. 42213.0719 = 37.2989
Ada
Ada does not provide a built-in mod function for floating point types. This program supplies one.
-----------------------------------------------------------------------
-- Angle difference between two bearings
-----------------------------------------------------------------------
with Ada.Text_IO; use Ada.Text_IO;
procedure Bearing_Angles is
type Real is digits 8;
Package Real_Io is new Ada.Text_IO.Float_IO(Real);
use Real_IO;
type Angles is record
B1 : Real;
B2 : Real;
end record;
type Angle_Arr is array(Positive range <>) of Angles;
function fmod(Left, Right : Real) return Real is
Result : Real;
begin
Result := Left - Right*Real'Truncation(Left / Right);
return Result;
end fmod;
The_Angles : Angle_Arr := ((20.0,45.0),(-45.0, 45.0), (-85.0, 90.0),
(-95.0, 90.0), (-14.0, 125.0), (29.4803, -88.6381),
(-78.3251, -159.036),
(-70099.74233810938, 29840.67437876723),
(-165313.6666297357, 33693.9894517456),
(1174.8380510598456, -154146.66490124757),
(60175.77306795546, 42213.07192354373));
Diff : Real;
begin
for A of The_Angles loop
Diff := fmod(A.b2 - A.b1, 360.0);
If Diff < -180.0 then
Diff := Diff + 360.0;
elsif Diff > 180.0 then
Diff := Diff - 360.0;
end if;
Put("Difference between ");
Put(Item => A.B2, Fore => 7, Aft => 4, Exp => 0);
Put(" and ");
Put(Item => A.B1, Fore => 7, Aft => 4, Exp => 0);
Put(" is ");
Put(Item => Diff, Fore => 4, Aft => 4, Exp => 0);
New_Line;
end loop;
end Bearing_Angles;
- Output:
Difference between 45.0000 and 20.0000 is 25.0000 Difference between 45.0000 and -45.0000 is 90.0000 Difference between 90.0000 and -85.0000 is 175.0000 Difference between 90.0000 and -95.0000 is -175.0000 Difference between 125.0000 and -14.0000 is 139.0000 Difference between -88.6381 and 29.4803 is -118.1184 Difference between -159.0360 and -78.3251 is -80.7109 Difference between 29840.6744 and -70099.7423 is -139.5833 Difference between 33693.9895 and -165313.6666 is -72.3439 Difference between -154146.6649 and 1174.8381 is -161.5030 Difference between 42213.0719 and 60175.7731 is 37.2989
ALGOL 68
BEGIN # angle difference between 2 bearings - translated from the 11l sample #
PROC wrap = (REAL v, l1, l2 )REAL:
BEGIN
REAL result := v;
WHILE result < l1 DO result +:= 2 * l2 OD;
WHILE result > l2 DO result +:= 2 * l1 OD;
result
END # wrap # ;
PROC get_difference = ( REAL b1, b2 )REAL: wrap( b2 - b1, -180.0, 180.0 );
OP FMT = ( REAL v )STRING:
BEGIN
STRING result := fixed( ABS v, 0, 3 );
IF result[ LWB result ] = "." THEN "0" +=: result FI;
WHILE result[ UPB result ] = "0" DO result := result[ : UPB result - 1 ] OD;
IF result[ UPB result ] = "." THEN result := result[ : UPB result - 1 ] FI;
IF v < 0 THEN "-" ELSE " " FI + result
END # FMT # ;
print( ( FMT get_difference( 20.0, 45.0 ), newline ) );
print( ( FMT get_difference( -45.0, 45.0 ), newline ) );
print( ( FMT get_difference( -85.0, 90.0 ), newline ) );
print( ( FMT get_difference( -95.0, 90.0 ), newline ) );
print( ( FMT get_difference( -45.0, 125.0 ), newline ) );
print( ( FMT get_difference( -45.0, 145.0 ), newline ) );
print( ( FMT get_difference( -45.0, 125.0 ), newline ) );
print( ( FMT get_difference( -45.0, 145.0 ), newline ) );
print( ( FMT get_difference( 29.4803, -88.6381 ), newline ) );
print( ( FMT get_difference( -78.3251, -159.036 ), newline ) );
print( ( newline ) );
print( ( FMT get_difference( -70099.74233810938, 29840.67437876723 ), newline ) );
print( ( FMT get_difference( -165313.6666297357, 33693.9894517456 ), newline ) );
print( ( FMT get_difference( 1174.8380510598456, -154146.66490124757 ), newline ) );
print( ( FMT get_difference( 60175.77306795546, 42213.07192354373 ), newline ) )
END
- Output:
25 90 175 -175 170 -170 170 -170 -118.118 -80.711 -139.583 -72.344 -161.503 37.299
APL
Returns an angle in (-180,180]; so two opposite bearings have a difference of 180 degrees, which is more natural than -180 degrees.
[0] D←B1 DIFF B2
[1] D←180+¯360|180+B2-B1
- Output:
'B1' 'B2' 'DIFFERENCE'⍪(⊂'¯¯¯¯¯¯¯¯¯¯')⍪(⊃B),DIFF/¨B B1 B2 DIFFERENCE ¯¯¯¯¯¯¯¯¯¯ ¯¯¯¯¯¯¯¯¯¯ ¯¯¯¯¯¯¯¯¯¯ 20 45 25 ¯45 45 90 ¯85 90 175 ¯95 90 ¯175 ¯45 125 170 ¯45 145 ¯170 29.48 ¯88.64 ¯118.12 ¯78.33 ¯159.04 ¯80.71 ¯70099.74 29840.67 ¯139.59 ¯165313.67 3369.99 ¯156.34 1174.84 ¯154146.66 ¯161.5 60175.77 42213.07 37.3 270 DIFF 90.01 ¯179.99 270 DIFF 90 180
ARM Assembly
/* ARM assembly Raspberry PI or android with termux */
/* program diffAngle.s */
/* REMARK 1 : this program use routines in a include file
see task Include a file language arm assembly
for the routine affichageMess conversion10
see at end of this program the instruction include */
/* for constantes see task include a file in arm assembly */
/************************************/
/* Constantes */
/************************************/
.include "../constantes.inc"
/*********************************/
/* Initialized data */
/*********************************/
.data
szCarriageReturn: .asciz "\n"
szMessResult: .asciz "Difference between @ and @ = @ \n"
.align 4
fB1: .float 20.0
fB2: .float 45.0
fB3: .float -45.0
fB4: .float -85.0
fB5: .float 90.0
fB6: .float -95.0
fB7: .float 125.0
fB8: .float 145.0
fB9: .float 29.4803
fB10: .float -88.6381
fB11: .float -78.3251
fB12: .float -159.036
fB13: .float -70099.74233810938
fB14: .float 29840.67437876723
/*********************************/
/* UnInitialized data */
/*********************************/
.bss
sZoneConv: .skip 24
/*********************************/
/* code section */
/*********************************/
.text
.global main
main:
ldr r0,iAdrfB1
ldr r1,iAdrfB2
bl testComputeAngle
ldr r0,iAdrfB3
ldr r1,iAdrfB2
bl testComputeAngle
ldr r0,iAdrfB4
ldr r1,iAdrfB5
bl testComputeAngle
ldr r0,iAdrfB6
ldr r1,iAdrfB5
bl testComputeAngle
ldr r0,iAdrfB3
ldr r1,iAdrfB7
bl testComputeAngle
ldr r0,iAdrfB3
ldr r1,iAdrfB8
bl testComputeAngle
ldr r0,iAdrfB9
ldr r1,iAdrfB10
bl testComputeAngle
ldr r0,iAdrfB11
ldr r1,iAdrfB12
bl testComputeAngle
ldr r0,iAdrfB13
ldr r1,iAdrfB14
bl testComputeAngle
100: @ standard end of the program
mov r0, #0 @ return code
mov r7, #EXIT @ request to exit program
svc #0 @ perform the system call
iAdrszCarriageReturn: .int szCarriageReturn
iAdrsZoneConv: .int sZoneConv
iAdrfB1: .int fB1
iAdrfB2: .int fB2
iAdrfB3: .int fB3
iAdrfB4: .int fB4
iAdrfB5: .int fB5
iAdrfB6: .int fB6
iAdrfB7: .int fB7
iAdrfB8: .int fB8
iAdrfB9: .int fB9
iAdrfB10: .int fB10
iAdrfB11: .int fB11
iAdrfB12: .int fB12
iAdrfB13: .int fB13
iAdrfB14: .int fB14
/******************************************************************/
/* compute difference and display result */
/******************************************************************/
/* s0 contains bearing 1 */
/* s1 contains bearing 2 */
testComputeAngle:
push {r1-r3,lr} @ save registers
vldr.f32 s0,[r0]
vmov s2,s0
vldr.f32 s1,[r1]
bl computeDiffAngle
vmov s3,s0
vmov s0,s2
ldr r0,iAdrsZoneConv
bl convertirFloat
ldr r0,iAdrszMessResult
ldr r1,iAdrsZoneConv
bl strInsertAtCharInc
mov r3,r0
vmov s0,s1
ldr r0,iAdrsZoneConv
bl convertirFloat
mov r0,r3
ldr r1,iAdrsZoneConv
bl strInsertAtCharInc
mov r3,r0
vmov s0,s3
ldr r0,iAdrsZoneConv
bl convertirFloat
mov r0,r3
ldr r1,iAdrsZoneConv
bl strInsertAtCharInc
bl affichageMess
100:
pop {r1-r3,pc} @ restaur registers
iAdrszMessResult: .int szMessResult
/******************************************************************/
/* compute difference of two bearing */
/******************************************************************/
/* s0 contains bearing 1 */
/* s1 contains bearing 2 */
computeDiffAngle:
push {r1-r4,lr} @ save registers
vpush {s1-s4}
mov r1,#360
mov r4,#0 @ top positive/negative
vcvt.s32.f32 s4,s0 @ conversion integer
vcvt.f32.s32 s2,s4 @ conversion float
vsub.f32 s2,s0,s2 @ partie décimale
vmov r0,s4 @ partie entière
cmp r0,#0 @ negative ?
neglt r0,r0 @ yes -> inversion
movlt r4,#1
bl division @ divide by 360 (r0 dividende r1 divisor r2 quotient r3 remainder)
cmp r4,#0 @ value negative ?
negne r3,r3 @ inversion remainder
vmov s3,r3
vcvt.f32.s32 s3,s3 @ and conversion float
vadd.f32 s0,s3,s2 @ add decimal part
mov r4,#0 @ bearing 2
vcvt.s32.f32 s4,s1 @ conversion integer
vcvt.f32.s32 s2,s4 @ conversion float
vsub.f32 s2,s1,s2 @ partie décimale
vmov r0,s4
cmp r0,#0
neglt r0,r0
movlt r4,#1
bl division @ divide by 360
cmp r4,#0
negne r3,r3 @ negate remainder
vmov s3,r3
vcvt.f32.s32 s3,s3 @ conversion float
vadd.f32 s1,s3,s2
vsub.f32 s0,s1,s0 @ calculate the difference between the 2 values
mov r0,#180
vmov s3,r0
vcvt.f32.s32 s3,s3 @ conversion float 180
vmov s4,r1 @ 360
vcvt.f32.s32 s4,s4 @ conversion float 360
vcmp.f32 s0,#0.0 @ difference is negative ?
vmrs APSR_nzcv, FPSCR @ flags transfert (do not forget this instruction !!!)
blt 2f
@ difference is positive
vcmp.f32 s0,s4 @ difference > 360
vmrs APSR_nzcv, FPSCR @ flags transfert (do not forget this instruction !!!)
vsubgt.f32 s0,s4 @ yes -> difference - 360
vcmp.f32 s0,s3 @ compare difference and 180
vmrs APSR_nzcv, FPSCR @ flags transfert (do not forget this instruction !!!)
vsubgt.f32 s0,s4,s0 @ > 180 calculate 360 - difference
vneggt.f32 s0,s0 @ and negate
b 100f
2: @ différence is négative
vneg.f32 s2,s4 @ -360
vcmp.f32 s0,s2 @ compare différence et - 360
vmrs APSR_nzcv, FPSCR @ flags transfert (do not forget this instruction !!!)
vsubgt.f32 s0,s4 @ sub 360 to différence
vneg.f32 s3,s3 @ -180
vcmp.f32 s0,s3 @ compare difference and -180
vmrs APSR_nzcv, FPSCR @ flags transfert (do not forget this instruction !!!)
vaddlt.f32 s0,s4,s0 @ calculate 360 + différence
100:
vpop {s1-s4}
pop {r1-r4,pc} @ restaur registers
/******************************************************************/
/* Conversion Float */
/******************************************************************/
/* s0 contains Float */
/* r0 contains address conversion area mini 20 charactèrs*/
/* r0 return result length */
convertirFloat:
push {r1-r7,lr}
vpush {s0-s2}
mov r6,r0 @ save area address
vmov r0,s0
movs r7,#0 @ result length
movs r3,#'+'
strb r3,[r6] @ sign + forcing
mov r2,r0
lsls r2,#1 @ extraction bit 31
bcc 1f @ positive ?
lsrs r0,r2,#1 @ raz sign if negative
movs r3,#'-' @ sign -
strb r3,[r6]
1:
adds r7,#1 @ next position
cmp r0,#0 @ case of positive or negative 0
bne 2f
movs r3,#'0'
strb r3,[r6,r7] @ store character 0
adds r7,#1 @ next position
movs r3,#0
strb r3,[r6,r7] @ store 0 final
mov r0,r7 @ return length
b 100f @ and end
2:
ldr r2,iMaskExposant
mov r1,r0
ands r1,r2 @ exposant = 255 ?
cmp r1,r2
bne 4f
lsls r0,#10 @ bit 22 à 0 ?
bcc 3f @ yes
movs r2,#'N' @ case of Nan. store byte, if not possible store int
strb r2,[r6] @ area no aligned
movs r2,#'a'
strb r2,[r6,#1]
movs r2,#'n'
strb r2,[r6,#2]
movs r2,#0 @ 0 final
strb r2,[r6,#3]
movs r0,#3 @ return length 3
b 100f
3: @ case infini positive or négative
movs r2,#'I'
strb r2,[r6,r7]
adds r7,#1
movs r2,#'n'
strb r2,[r6,r7]
adds r7,#1
movs r2,#'f'
strb r2,[r6,r7]
adds r7,#1
movs r2,#0
strb r2,[r6,r7]
mov r0,r7
b 100f
4:
bl normaliserFloat
mov r5,r0 @ save exposant
VCVT.U32.f32 s2,s0 @ integer value of integer part
vmov r0,s2 @ integer part
VCVT.F32.U32 s1,s2 @ conversion float
vsub.f32 s1,s0,s1 @ extraction fract part
vldr s2,iConst1
vmul.f32 s1,s2,s1 @ to crop it in full
VCVT.U32.f32 s1,s1 @ integer conversion
vmov r4,s1 @ fract value
@ integer conversion in r0
mov r2,r6 @ save address area begin
adds r6,r7
mov r1,r6
bl conversion10
add r6,r0
movs r3,#','
strb r3,[r6]
adds r6,#1
mov r0,r4 @ conversion fractional part
mov r1,r6
bl conversion10SP @ spécial routine with conservation begin 0
add r6,r0
subs r6,#1
@ remove trailing zeros
5:
ldrb r0,[r6]
cmp r0,#'0'
bne 6f
subs r6,#1
b 5b
6:
cmp r0,#','
bne 7f
subs r6,#1
7:
adds r6,#1
movs r3,#'E'
strb r3,[r6]
adds r6,#1
mov r0,r5 @ conversion exposant
mov r3,r0
lsls r3,#1
bcc 4f
rsbs r0,r0,#0
movs r3,#'-'
strb r3,[r6]
adds r6,#1
4:
mov r1,r6
bl conversion10
add r6,r0
movs r3,#0
strb r3,[r6]
adds r6,#1
mov r0,r6
subs r0,r2 @ return length result
subs r0,#1 @ - 0 final
100:
vpop {s0-s2}
pop {r1-r7,pc}
iMaskExposant: .int 0xFF<<23
iConst1: .float 0f1E9
/***************************************************/
/* normaliser float */
/***************************************************/
/* r0 contain float value (always positive value and <> Nan) */
/* s0 return new value */
/* r0 return exposant */
normaliserFloat:
push {lr} @ save registre
vmov s0,r0 @ value float
movs r0,#0 @ exposant
vldr s1,iConstE7 @ no normalisation for value < 1E7
vcmp.f32 s0,s1
vmrs APSR_nzcv,FPSCR
blo 10f @ if s0 < iConstE7
vldr s1,iConstE32
vcmp.f32 s0,s1
vmrs APSR_nzcv,FPSCR
blo 1f
vldr s1,iConstE32
vdiv.f32 s0,s0,s1
adds r0,#32
1:
vldr s1,iConstE16
vcmp.f32 s0,s1
vmrs APSR_nzcv,FPSCR
blo 2f
vldr s1,iConstE16
vdiv.f32 s0,s0,s1
adds r0,#16
2:
vldr s1,iConstE8
vcmp.f32 s0,s1
vmrs APSR_nzcv,FPSCR
blo 3f
vldr s1,iConstE8
vdiv.f32 s0,s0,s1
adds r0,#8
3:
vldr s1,iConstE4
vcmp.f32 s0,s1
vmrs APSR_nzcv,FPSCR
blo 4f
vldr s1,iConstE4
vdiv.f32 s0,s0,s1
adds r0,#4
4:
vldr s1,iConstE2
vcmp.f32 s0,s1
vmrs APSR_nzcv,FPSCR
blo 5f
vldr s1,iConstE2
vdiv.f32 s0,s0,s1
adds r0,#2
5:
vldr s1,iConstE1
vcmp.f32 s0,s1
vmrs APSR_nzcv,FPSCR
blo 10f
vldr s1,iConstE1
vdiv.f32 s0,s0,s1
adds r0,#1
10:
vldr s1,iConstME5 @ pas de normalisation pour les valeurs > 1E-5
vcmp.f32 s0,s1
vmrs APSR_nzcv,FPSCR
bhi 100f
vldr s1,iConstME31
vcmp.f32 s0,s1
vmrs APSR_nzcv,FPSCR
bhi 11f
vldr s1,iConstE32
vmul.f32 s0,s0,s1
subs r0,#32
11:
vldr s1,iConstME15
vcmp.f32 s0,s1
vmrs APSR_nzcv,FPSCR
bhi 12f
vldr s1,iConstE16
vmul.f32 s0,s0,s1
subs r0,#16
12:
vldr s1,iConstME7
vcmp.f32 s0,s1
vmrs APSR_nzcv,FPSCR
bhi 13f
vldr s1,iConstE8
vmul.f32 s0,s0,s1
subs r0,#8
13:
vldr s1,iConstME3
vcmp.f32 s0,s1
vmrs APSR_nzcv,FPSCR
bhi 14f
vldr s1,iConstE4
vmul.f32 s0,s0,s1
subs r0,#4
14:
vldr s1,iConstME1
vcmp.f32 s0,s1
vmrs APSR_nzcv,FPSCR
bhi 15f
vldr s1,iConstE2
vmul.f32 s0,s0,s1
subs r0,#2
15:
vldr s1,iConstE0
vcmp.f32 s0,s1
vmrs APSR_nzcv,FPSCR
bhi 100f
vldr s1,iConstE1
vmul.f32 s0,s0,s1
subs r0,#1
100: @ fin standard de la fonction
pop {pc} @ restaur des registres
.align 2
iConstE7: .float 0f1E7
iConstE32: .float 0f1E32
iConstE16: .float 0f1E16
iConstE8: .float 0f1E8
iConstE4: .float 0f1E4
iConstE2: .float 0f1E2
iConstE1: .float 0f1E1
iConstME5: .float 0f1E-5
iConstME31: .float 0f1E-31
iConstME15: .float 0f1E-15
iConstME7: .float 0f1E-7
iConstME3: .float 0f1E-3
iConstME1: .float 0f1E-1
iConstE0: .float 0f1E0
/******************************************************************/
/* Décimal Conversion */
/******************************************************************/
/* r0 contain value et r1 address conversion area */
conversion10SP:
push {r1-r6,lr} @ save registers
mov r5,r1
mov r4,#8
mov r2,r0
mov r1,#10 @ conversion decimale
1: @ begin loop
mov r0,r2 @ copy number or quotients
bl division @ r0 dividende r1 divisor r2 quotient r3 remainder
add r3,#48 @ compute digit
strb r3,[r5,r4] @ store byte area address (r5) + offset (r4)
subs r4,r4,#1 @ position précedente
bge 1b @ and loop if not < zero
mov r0,#8
mov r3,#0
strb r3,[r5,r0] @ store 0 final
100:
pop {r1-r6,pc} @ restaur registers
/***************************************************/
/* ROUTINES INCLUDE */
/***************************************************/
.include "../affichage.inc"
Difference between +20E0 and +45E0 = +25E0 Difference between -45E0 and +45E0 = +90E0 Difference between -85E0 and +90E0 = +175E0 Difference between -95E0 and +90E0 = -175E0 Difference between -45E0 and +125E0 = +170E0 Difference between -45E0 and +145E0 = -170E0 Difference between +29,48030089E0 and -88,63809964E0 = -118,1184082E0 Difference between -78,32510374E0 and -159,03599548E0 = -80,71087648E0 Difference between -70099,74218752E0 and +29840,67382809E0 = -139,58398438E0
Arturo
getDifference: function [b1, b2][
r: (b2 - b1) % 360.0
if r >= 180.0 ->
r: r - 360.0
return r
]
print "Input in -180 to +180 range"
print getDifference 20.0 45.0
print getDifference neg 45.0 45.0
print getDifference neg 85.0 90.0
print getDifference neg 95.0 90.0
print getDifference neg 45.0 125.0
print getDifference neg 45.0 145.0
print getDifference neg 45.0 125.0
print getDifference neg 45.0 145.0
print getDifference 29.4803 neg 88.6381
print getDifference neg 78.3251 neg 159.036
print ""
print "Input in wider range"
print getDifference neg 70099.74233810938 29840.67437876723
print getDifference neg 165313.6666297357 33693.9894517456
print getDifference 1174.8380510598456 neg 154146.66490124757
print getDifference 60175.77306795546 42213.07192354373
- Output:
Input in -180 to +180 range 25.0 90.0 175.0 -175.0 170.0 -170.0 170.0 -170.0 -118.1184 -80.7109 Input in wider range -139.5832831233856 -72.34391851868713 -161.5029523074045 -322.7011444117306
AutoHotkey
Angles:= [[20, 45]
,[-45, 45]
,[-85, 90]
,[-95, 90]
,[-45, 125]
,[-45, 145]
,[29.4803, -88.6381]
,[-78.3251, -159.036]
,[-70099.74233810938, 29840.67437876723]
,[-165313.6666297357, 33693.9894517456]
,[1174.8380510598456, -154146.66490124757]
,[60175.77306795546, 42213.07192354373]]
for i, set in angles
result .= set.2 " to " set.1 " = " Angle_difference_between_two_bearings(set) "`n"
MsgBox, 262144, , % result
return
Angle_difference_between_two_bearings(set){
return (diff := Mod(set.2, 360) - Mod(set.1, 360)) >180 ? diff-360 : diff
}
- Output:
45 to 20 = 25 45 to -45 = 90 90 to -85 = 175 90 to -95 = -175 125 to -45 = 170 145 to -45 = -170 -88.6381 to 29.4803 = -118.118400 -159.036 to -78.3251 = -80.710900 29840.67437876723 to -70099.74233810938 = 220.416717 33693.9894517456 to -165313.6666297357 = -72.343919 -154146.66490124757 to 1174.8380510598456 = -161.502952 42213.07192354373 to 60175.77306795546 = 37.298856
AWK
# syntax: GAWK -f ANGLE_DIFFERENCE_BETWEEN_TWO_BEARINGS.AWK
BEGIN {
fmt = "%11s %11s %11s\n"
while (++i <= 11) { u = u "-" }
printf(fmt,"B1","B2","DIFFERENCE")
printf(fmt,u,u,u)
main(20,45)
main(-45,45)
main(-85,90)
main(-95,90)
main(-45,125)
main(-45,145)
main(29.4803,-88.6381)
main(-78.3251,-159.036)
main(-70099.74233810938,29840.67437876723)
main(-165313.6666297357,33693.9894517456)
main(1174.8380510598456,-154146.66490124757)
main(60175.77306795546,42213.07192354373)
exit(0)
}
function main(b1,b2) {
printf("%11.2f %11.2f %11.2f\n",b1,b2,angle_difference(b1,b2))
}
function angle_difference(b1,b2, r) {
r = (b2 - b1) % 360
if (r < -180) {
r += 360
}
if (r >= 180) {
r -= 360
}
return(r)
}
- Output:
B1 B2 DIFFERENCE ----------- ----------- ----------- 20.00 45.00 25.00 -45.00 45.00 90.00 -85.00 90.00 175.00 -95.00 90.00 -175.00 -45.00 125.00 170.00 -45.00 145.00 -170.00 29.48 -88.64 -118.12 -78.33 -159.04 -80.71 -70099.74 29840.67 -139.58 -165313.67 33693.99 -72.34 1174.84 -154146.66 -161.50 60175.77 42213.07 37.30
BASIC
Chipmunk Basic
100 cls
110 sub getdifference(b1,b2)
120 r = (b2-b1) mod 360
130 if r >= 180 then r = r-360
140 print using "#######.######";b1;
150 print using " #######.######";b2;
160 print using " #######.######";r
170 end sub
180 print "Input in -180 to +180 range:"
190 print " b1 b2 difference"
200 print " -------------------------------------------------"
210 getdifference(20,45)
220 getdifference(-45,45)
230 getdifference(-85,90)
240 getdifference(-95,90)
250 getdifference(-45,125)
260 getdifference(-45,145)
270 getdifference(-45,125)
280 getdifference(-45,145)
290 getdifference(29.4803,-88.6381)
300 getdifference(-78.3251,-159.036)
310 getdifference(-70099.742338,29840.674379)
320 getdifference(-165313.66663,33693.989452)
330 getdifference(1174.838051,-154146.664901)
340 print
350 print "Input in wider range:"
360 print " b1 b2 difference"
370 print " -------------------------------------------------"
380 getdifference(-70099.742338,29840.674379)
390 getdifference(-165313.66663,33693.989452)
400 getdifference(1174.838051,-154146.664901)
410 getdifference(60175.773068,42213.071924)
- Output:
Input in -180 to +180 range: b1 b2 difference ------------------------------------------------- 20.000000 45.000000 25.000000 -45.000000 45.000000 90.000000 -85.000000 90.000000 175.000000 -95.000000 90.000000 -175.000000 -45.000000 125.000000 170.000000 -45.000000 145.000000 -170.000000 -45.000000 125.000000 170.000000 -45.000000 145.000000 -170.000000 29.480300 -88.638100 -118.000000 -78.325100 -159.036000 -80.000000 -70099.742338 29840.674379 -140.000000 -165313.666630 33693.989452 -73.000000 1174.838051 -154146.664901 -161.000000 Input in wider range: b1 b2 difference ------------------------------------------------- -70099.742338 29840.674379 -140.000000 -165313.666630 33693.989452 -73.000000 1174.838051 -154146.664901 -161.000000 60175.773068 42213.071924 -322.000000
QBasic
SUB getDifference (b1!, b2!)
r! = (b2 - b1) MOD 360!
IF r >= 180! THEN r = r - 360!
PRINT USING "#######.###### #######.###### #######.######"; b1; b2; r
END SUB
PRINT " Bearing 1 Bearing 2 Difference"
CALL getDifference(20!, 45!)
CALL getDifference(-45!, 45!)
CALL getDifference(-85!, 90!)
CALL getDifference(-95!, 90!)
CALL getDifference(-45!, 125!)
CALL getDifference(-45!, 145!)
CALL getDifference(-45!, 125!)
CALL getDifference(-45!, 145!)
CALL getDifference(29.4803, -88.6381)
CALL getDifference(-78.3251, -159.036)
CALL getDifference(-70099.74233810938#, 29840.67437876723#)
CALL getDifference(-165313.6666297357#, 33693.9894517456#)
CALL getDifference(1174.838051059846#, -154146.6649012476#)
True BASIC
SUB getdifference (b1,b2)
LET r = REMAINDER(b2-b1, 360.0)
IF r >= 180.0 THEN LET r = r-360.0
PRINT USING "#######.###### #######.###### #######.######": b1, b2, r
END SUB
PRINT " Bearing 1 Bearing 2 Difference"
CALL getdifference(20.0, 45.0)
CALL getdifference(-45.0, 45.0)
CALL getdifference(-85.0, 90.0)
CALL getdifference(-95.0, 90.0)
CALL getdifference(-45.0, 125.0)
CALL getdifference(-45.0, 145.0)
CALL getdifference(-45.0, 125.0)
CALL getdifference(-45.0, 145.0)
CALL getdifference(29.4803, -88.6381)
CALL getdifference(-78.3251, -159.036)
CALL getdifference(-70099.74233810938, 29840.67437876723)
CALL getdifference(-165313.6666297357, 33693.9894517456)
CALL getdifference(1174.8380510598456, -154146.66490124757)
END
BASIC256
# Rosetta Code problem: http://rosettacode.org/wiki/Angle_difference_between_two_bearings
# by Jjuanhdez, 06/2022
print "Input in -180 to +180 range:"
call getDifference(20.0, 45.0)
call getDifference(-45.0, 45.0)
call getDifference(-85.0, 90.0)
call getDifference(-95.0, 90.0)
call getDifference(-45.0, 125.0)
call getDifference(-45.0, 145.0)
call getDifference(-45.0, 125.0)
call getDifference(-45.0, 145.0)
call getDifference(29.4803, -88.6381)
call getDifference(-78.3251, -159.036)
print
print "Input in wider range:"
call getDifference(-70099.74233810938, 29840.67437876723)
call getDifference(-165313.6666297357, 33693.9894517456)
call getDifference(1174.8380510598456, -154146.66490124757)
end
subroutine getDifference(b1, b2)
r = (b2 - b1) mod 360
if r >= 180.0 then r -= 360.0
print ljust(b1,16); ljust(b2,16); ljust(r,12)
end subroutine
Befunge
012pv1 2 3 4 5 6 7 8
>&:v >859**%:459**1-`#v_ >12g!:12p#v_\-:459**1-`#v_ >.>
>0`#^_8v >859**-^ >859**-^
^:+**95< > ^
The labelled points are: 1. Initialise write/not write and read input, 2. Put in the range 0-360 if negative, 3. Likewise if positive, 4. Put in range -180 - 180, 5. Check if write/not write step, 6. If write find difference, 7. Scale to -180 - 180, 8. Write out and onto next pair.
Unfortunately, due to the lack of floating-point arithmetic in befunge, it is impossible to do the full challenge, however, given the integer truncations of these values it works.
Input:
20 45 -45 45 -85 90 -95 90 -45 125 -45 145 29 -88 -78 -159 -70099 29840 -165313 33693 1174 -154146 60175 42213
- Output:
25 90 175 -175 170 -170 -117 -81 -141 -74 -160 38
BQN
Adiff ← 180 - 360 | 180 + -
tests ← [20‿45, ¯45‿45, ¯85‿90, ¯95‿90, ¯45‿125, ¯45‿145
99‿279, 29.4803‿¯88.6381, ¯78.3251‿¯159.036
¯70099.74233810938‿29840.67437876723
¯165313.6666297357‿33693.9894517456
1174.8380510598456‿¯154146.66490124757
60175.77306795546‿42213.07192354373]
Round ← ⌊∘+⟜0.5⌾(1e3⊸×)
Round∘∾⟜(Adiff´)˘ tests
- Output:
┌─ ╵ 20 45 25 ¯45 45 90 ¯85 90 175 ¯95 90 ¯175 ¯45 125 170 ¯45 145 ¯170 99 279 180 29.48 ¯88.638 ¯118.118 ¯78.325 ¯159.036 ¯80.711 ¯70099.742 29840.674 ¯139.583 ¯165313.667 33693.989 ¯72.344 1174.838 ¯154146.665 ¯161.503 60175.773 42213.072 37.299 ┘
C
This implementation either reads two bearings from the console or a file containing a list of bearings. Usage printed on incorrect invocation.
#include<stdlib.h>
#include<stdio.h>
#include<math.h>
void processFile(char* name){
int i,records;
double diff,b1,b2;
FILE* fp = fopen(name,"r");
fscanf(fp,"%d\n",&records);
for(i=0;i<records;i++){
fscanf(fp,"%lf%lf",&b1,&b2);
diff = fmod(b2-b1,360.0);
printf("\nDifference between b2(%lf) and b1(%lf) is %lf",b2,b1,(diff<-180)?diff+360:((diff>=180)?diff-360:diff));
}
fclose(fp);
}
int main(int argC,char* argV[])
{
double diff;
if(argC < 2)
printf("Usage : %s <bearings separated by a space OR full file name which contains the bearing list>",argV[0]);
else if(argC == 2)
processFile(argV[1]);
else{
diff = fmod(atof(argV[2])-atof(argV[1]),360.0);
printf("Difference between b2(%s) and b1(%s) is %lf",argV[2],argV[1],(diff<-180)?diff+360:((diff>=180)?diff-360:diff));
}
return 0;
}
Invocation and output for two bearings :
C:\rosettaCode>bearingDiff.exe 29.4803 -88.6381 Difference between b2(-88.6381) and b1(29.4803) is -118.118400
File format for bearing list :
<Number of records> <Each record consisting of two bearings separated by a space>
Input file :
12 20 45 -45 45 -85 90 -95 90 -45 125 -45 145 29.4803 -88.6381 -78.3251 -159.036 -70099.74233810938 29840.67437876723 -165313.6666297357 33693.9894517456 1174.8380510598456 -154146.66490124757 60175.77306795546 42213.07192354373
Invocation and output for above bearing list file :
C:\rosettaCode>bearingDiff.exe bearingList.txt Difference between b2(45.000000) and b1(20.000000) is 25.000000 Difference between b2(45.000000) and b1(-45.000000) is 90.000000 Difference between b2(90.000000) and b1(-85.000000) is 175.000000 Difference between b2(90.000000) and b1(-95.000000) is -175.000000 Difference between b2(125.000000) and b1(-45.000000) is 170.000000 Difference between b2(145.000000) and b1(-45.000000) is -170.000000 Difference between b2(-88.638100) and b1(29.480300) is -118.118400 Difference between b2(-159.036000) and b1(-78.325100) is -80.710900 Difference between b2(29840.674379) and b1(-70099.742338) is -139.583283 Difference between b2(33693.989452) and b1(-165313.666630) is -72.343919 Difference between b2(-154146.664901) and b1(1174.838051) is -161.502952 Difference between b2(42213.071924) and b1(60175.773068) is 37.298856
C#
using System;
namespace Angle_difference_between_two_bearings
{
class Program
{
public static void Main(string[] args)
{
Console.WriteLine();
Console.WriteLine("Hello World!");
Console.WriteLine();
// Calculate standard test cases
Console.WriteLine(Delta_Bearing( 20M,45));
Console.WriteLine(Delta_Bearing(-45M,45M));
Console.WriteLine(Delta_Bearing(-85M,90M));
Console.WriteLine(Delta_Bearing(-95M,90M));
Console.WriteLine(Delta_Bearing(-45M,125M));
Console.WriteLine(Delta_Bearing(-45M,145M));
Console.WriteLine(Delta_Bearing( 29.4803M,-88.6381M));
Console.WriteLine(Delta_Bearing(-78.3251M, -159.036M));
// Calculate optional test cases
Console.WriteLine(Delta_Bearing(-70099.74233810938M, 29840.67437876723M));
Console.WriteLine(Delta_Bearing(-165313.6666297357M, 33693.9894517456M));
Console.WriteLine(Delta_Bearing( 1174.8380510598456M, -154146.66490124757M));
Console.WriteLine(Delta_Bearing( 60175.77306795546M, 42213.07192354373M));
Console.WriteLine();
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
static decimal Delta_Bearing(decimal b1, decimal b2)
{
/*
* Optimal solution
*
decimal d = 0;
d = (b2-b1)%360;
if(d>180)
d -= 360;
else if(d<-180)
d += 360;
return d;
*
*
*/
//
//
//
decimal d = 0;
// Convert bearing to W.C.B
if(b1<0)
b1 += 360;
if(b2<0)
b2 += 360;
///Calculate delta bearing
//and
//Convert result value to Q.B.
d = (b2 - b1)%360;
if(d>180)
d -= 360;
else if(d<-180)
d += 360;
return d;
//
//
//
}
}
}
- Output:
Hello World! 25 90 175 -175 170 -170 -118,1184 -80,7109 -139,58328312339 -72,3439185187 -161,5029523074156 37,29885558827 Press any key to continue . . .
C++
#include <cmath>
#include <iostream>
using namespace std;
double getDifference(double b1, double b2) {
double r = fmod(b2 - b1, 360.0);
if (r < -180.0)
r += 360.0;
if (r >= 180.0)
r -= 360.0;
return r;
}
int main()
{
cout << "Input in -180 to +180 range" << endl;
cout << getDifference(20.0, 45.0) << endl;
cout << getDifference(-45.0, 45.0) << endl;
cout << getDifference(-85.0, 90.0) << endl;
cout << getDifference(-95.0, 90.0) << endl;
cout << getDifference(-45.0, 125.0) << endl;
cout << getDifference(-45.0, 145.0) << endl;
cout << getDifference(-45.0, 125.0) << endl;
cout << getDifference(-45.0, 145.0) << endl;
cout << getDifference(29.4803, -88.6381) << endl;
cout << getDifference(-78.3251, -159.036) << endl;
cout << "Input in wider range" << endl;
cout << getDifference(-70099.74233810938, 29840.67437876723) << endl;
cout << getDifference(-165313.6666297357, 33693.9894517456) << endl;
cout << getDifference(1174.8380510598456, -154146.66490124757) << endl;
cout << getDifference(60175.77306795546, 42213.07192354373) << endl;
return 0;
}
- Output:
Input in -180 to +180 range 25 90 175 -175 170 -170 170 -170 -118.118 -80.7109 Input in wider range -139.583 -72.3439 -161.503 37.2989
Clojure
(defn angle-difference [a b]
(let [r (mod (- b a) 360)]
(if (>= r 180)
(- r 360)
r)))
(angle-difference 20 45) ; 25
(angle-difference -45 45) ; 90
(angle-difference -85 90) ; 175
(angle-difference -95 90) ; -175
(angle-difference -70099.74 29840.67) ; -139.59
COBOL
******************************************************************
* COBOL solution to Angle difference challange
* The program was run on OpenCobolIDE
* I chose to read the input data from a .txt file that I
* created on my PC rather than to hard code it into the
* program or enter it as the program was executing.
******************************************************************
IDENTIFICATION DIVISION.
PROGRAM-ID. ANGLE-DIFFERENCE.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT IN-FILE ASSIGN TO 'C:\Both\Rosetta\Angle_diff.txt'
ORGANIZATION IS LINE SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD IN-FILE.
01 IN-RECORD.
05 ALPHA-BEARING-1 PIC X(20).
05 FILLER PIC X.
05 ALPHA-BEARING-2 PIC X(20).
WORKING-STORAGE SECTION.
01 SWITCHES.
05 EOF-SWITCH PIC X VALUE 'N'.
01 COUNTERS.
05 REC-CTR PIC 9(3) VALUE 0.
01 WS-ALPHA-BEARING.
05 WS-AB-SIGN PIC X.
88 WS-AB-NEGATIVE VALUE "-".
05 WS-AB-INTEGER-PART PIC X(6).
05 WS-AB-DEC-POINT PIC X.
05 WS-AB-DECIMAL-PART PIC X(12).
01 WS-BEARING-1 PIC S9(6)V9(12).
01 WS-BEARING-2 PIC S9(6)V9(12).
01 WS-BEARING PIC S9(6)V9(12).
01 FILLER REDEFINES WS-BEARING.
05 WSB-INTEGER-PART PIC X(6).
05 WSB-DECIMAL-PART PIC X9(12).
77 WS-RESULT PIC S9(6)V9(12).
77 WS-RESULT-POS PIC 9(6)V9(12).
77 WS-INTEGER-PART PIC 9(6).
77 WS-DECIMAL-PART PIC V9(12).
77 WS-RESULT-OUT PIC ------9.9999.
PROCEDURE DIVISION.
000-MAIN.
PERFORM 100-INITIALIZE.
PERFORM 200-PROCESS-RECORD
UNTIL EOF-SWITCH = 'Y'.
PERFORM 300-TERMINATE.
STOP RUN.
100-INITIALIZE.
OPEN INPUT IN-FILE.
PERFORM 150-READ-RECORD.
150-READ-RECORD.
READ IN-FILE
AT END
MOVE 'Y' TO EOF-SWITCH
NOT AT END
COMPUTE REC-CTR = REC-CTR + 1
END-READ.
200-PROCESS-RECORD.
MOVE ALPHA-BEARING-1 TO WS-ALPHA-BEARING.
PERFORM 250-CONVERT-DATA.
MOVE WS-BEARING TO WS-BEARING-1.
MOVE ALPHA-BEARING-2 TO WS-ALPHA-BEARING.
PERFORM 250-CONVERT-DATA.
MOVE WS-BEARING TO WS-BEARING-2.
COMPUTE WS-RESULT = WS-BEARING-2 - WS-BEARING-1.
MOVE WS-RESULT TO WS-RESULT-POS.
MOVE WS-RESULT-POS TO WS-INTEGER-PART.
COMPUTE WS-DECIMAL-PART = WS-RESULT-POS - WS-INTEGER-PART.
COMPUTE WS-INTEGER-PART = FUNCTION MOD(WS-INTEGER-PART 360).
IF WS-RESULT > 0
COMPUTE WS-RESULT = WS-INTEGER-PART + WS-DECIMAL-PART
ELSE
COMPUTE WS-RESULT =
(WS-INTEGER-PART + WS-DECIMAL-PART) * -1
END-IF.
IF WS-RESULT < -180
COMPUTE WS-RESULT = WS-RESULT + 360.
IF WS-RESULT > 180
COMPUTE WS-RESULT = WS-RESULT - 360.
COMPUTE WS-RESULT-OUT ROUNDED = WS-RESULT.
DISPLAY REC-CTR ' ' WS-RESULT-OUT.
PERFORM 150-READ-RECORD.
250-CONVERT-DATA.
MOVE WS-AB-INTEGER-PART TO WSB-INTEGER-PART.
MOVE WS-AB-DECIMAL-PART TO WSB-DECIMAL-PART.
IF WS-AB-NEGATIVE
SUBTRACT WS-BEARING FROM ZERO
GIVING WS-BEARING
END-IF.
300-TERMINATE.
DISPLAY 'RECORDS PROCESSED: ' REC-CTR.
CLOSE IN-FILE.
******************************************************************
* INPUT FILE ('Angle_diff.txt' stored on my PC at:
* 'C:\Both\Rosetta\Angle_diff.txt'
******************************************************************
* +000020.000000000000 +000045.000000000000
* -000045.000000000000 +000045.000000000000
* -000085.000000000000 +000090.000000000000
* -000095.000000000000 +000090.000000000000
* -000045.000000000000 +000125.000000000000
* -000045.000000000000 +000145.000000000000
* +000029.480300000000 -000088.638100000000
* -000078.325100000000 -000159.036000000000
* -070099.742338109380 +029840.674378767230
* -165313.666629735700 +033693.989451745600
* +001174.838051059846 -154146.664901247570
* +060175.773067955460 +042213.071923543730
******************************************************************
* OUTPUT:
******************************************************************
* 001 25.0000
* 002 90.0000
* 003 175.0000
* 004 -175.0000
* 005 170.0000
* 006 -170.0000
* 007 -118.1184
* 008 -80.7109
* 009 -139.5833
* 010 -72.3439
* 011 -161.5030
* 012 37.2989
******************************************************************
Common Lisp
(defun angle-difference (b1 b2)
(let ((diff (mod (- b2 b1) 360)))
(if (< diff -180)
(incf diff 360)
(if (> diff 180)
(decf diff 360)
diff))))
- Output:
CL-USER> (angle-difference 20 45) 25 CL-USER> (angle-difference -45 45) 90 CL-USER> (angle-difference -85 90) 175 CL-USER> (angle-difference -95 90) -175 CL-USER> (angle-difference -70099.74 29840.67) -139.58594
Craft Basic
precision 4
define s1 = 0, s2 = 0
dim b1[20, -45, -85, -95, -45, -45, 29.4803, -78.3251]
dim b2[45, 45, 90, 90, 125, 145, -88.6381, -159.036]
arraysize s1, b1
arraysize s2, b2
if s1 = s2 then
for i = 0 to s1 - 1
let r = (b2[i] - b1[i]) % 360
if r >= 180 then
let r = r - 360
endif
print "bearing 1: ", b1[i], " bearing 2: ", b2[i], " difference: ", r
next i
endif
- Output:
bearing 1: 20 bearing 2: 45 difference: 25 bearing 1: -45 bearing 2: 45 difference: 90 bearing 1: -85 bearing 2: 90 difference: 175 bearing 1: -95 bearing 2: 90 difference: -175 bearing 1: -45 bearing 2: 125 difference: 170 bearing 1: -45 bearing 2: 145 difference: -170 bearing 1: 29.4803 bearing 2: -88.6381 difference: -118 bearing 1: -78.3251 bearing 2: -159.0360 difference: -80
D
import std.stdio;
double getDifference(double b1, double b2) {
double r = (b2 - b1) % 360.0;
if (r < -180.0) {
r += 360.0;
}
if (r >= 180.0) {
r -= 360.0;
}
return r;
}
void main() {
writeln("Input in -180 to +180 range");
writeln(getDifference(20.0, 45.0));
writeln(getDifference(-45.0, 45.0));
writeln(getDifference(-85.0, 90.0));
writeln(getDifference(-95.0, 90.0));
writeln(getDifference(-45.0, 125.0));
writeln(getDifference(-45.0, 145.0));
writeln(getDifference(-45.0, 125.0));
writeln(getDifference(-45.0, 145.0));
writeln(getDifference(29.4803, -88.6381));
writeln(getDifference(-78.3251, -159.036));
writeln("Input in wider range");
writeln(getDifference(-70099.74233810938, 29840.67437876723));
writeln(getDifference(-165313.6666297357, 33693.9894517456));
writeln(getDifference(1174.8380510598456, -154146.66490124757));
writeln(getDifference(60175.77306795546, 42213.07192354373));
}
- Output:
Input in -180 to +180 range 25 90 175 -175 170 -170 170 -170 -118.118 -80.7109 Input in wider range -139.583 -72.3439 -161.503 37.2989
Delphi
See #Pascal.
EasyLang
func angdiff a b .
r = (b - a) mod 360
if r < -180
r += 360
elif r >= 180
r -= 360
.
return r
.
proc pd a b . .
print b & " " & a & " -> " & angdiff a b
.
pd 20 45
pd -45 45
pd -85 90
pd -95 90
pd -45 125
pd -45 145
pd 29.4803 -88.6381
pd -78.3251 -159.036
pd -70099.74233810938 29840.67437876723
pd -165313.6666297357 33693.9894517456
pd 1174.8380510598456 -154146.66490124757
pd 60175.77306795546 42213.07192354373
Erlang
The real number calculations are done using integer arithmetic to better handle rounding errors. Erlang uses extended precision integers so there will be no overflow. The module is tested by running the test function, which in turn matches expected results with the result of function call.
-module(bearings).
%% API
-export([angle_sub_degrees/2,test/0]).
-define(RealAngleMultiplier,16#10000000000).
-define(DegreesPerTurn,360).
-define(Precision,9).
%%%===================================================================
%%% API
%%%===================================================================
%%--------------------------------------------------------------------
%% @doc
%% @spec
%% @end
%%--------------------------------------------------------------------
%%
angle_sub_degrees(B1,B2) when is_integer(B1), is_integer(B2) ->
angle_sub(B2-B1,?DegreesPerTurn);
angle_sub_degrees(B1,B2) ->
NewB1 = trunc(B1*?RealAngleMultiplier),
NewB2 = trunc(B2*?RealAngleMultiplier),
round(angle_sub(NewB2 - NewB1,
?DegreesPerTurn*?RealAngleMultiplier)
/?RealAngleMultiplier,?Precision).
%%%===================================================================
%%% Internal functions
%%%===================================================================
%% delta normalises the angle difference. Consider a turn from 350 degrees
%% to 20 degrees. Subtraction results in 330 degress. This is equivalent of
%% a turn in the other direction of 30 degrees, thus 330 degrees is equal
%% to -30 degrees.
angle_sub(Value,TurnSize) ->
NormalisedValue = Value rem TurnSize,
minimise_angle(NormalisedValue,TurnSize).
% X rem Turn result in 0..Turn for X > 0 and -Turn..0 for X < 0
% specification requires -Turn/2 < X < Turn/2. This is achieved
% by adding or removing a turn as required.
% bsr 1 divides an integer by 2
minimise_angle(Angle,Turn) when Angle + (Turn bsr 1) < 0 ->
Angle+Turn;
minimise_angle(Angle,Turn) when Angle - (Turn bsr 1) > 0 ->
Angle-Turn;
minimise_angle(Angle,_) ->
Angle.
round(Number,Precision) ->
P = math:pow(10,Precision),
round(Number*P)/P.
test() ->
25 = angle_sub_degrees(20,45),
90 = angle_sub_degrees(-45,45),
175 = angle_sub_degrees(-85,90),
-175 = angle_sub_degrees(-95,90),
170 = angle_sub_degrees(-45,125),
-170 = angle_sub_degrees(-45,145),
-118.1184 = angle_sub_degrees( 29.4803,-88.6381),
-139.583283124=angle_sub_degrees(-70099.742338109,29840.674378767),
-72.343918514=angle_sub_degrees( -165313.66662974,33693.989451746),
-161.50295231=angle_sub_degrees( 1174.8380510598,-154146.66490125),
37.298855589=angle_sub_degrees( 60175.773067955,42213.071923544),
passed.
Excel
LAMBDA
Binding the names ANGLEBETWEENBEARINGS and BEARINGDELTA to the following lambda expressions in the Name Manager of the Excel WorkBook:
(See LAMBDA: The ultimate Excel worksheet function)
ANGLEBETWEENBEARINGS
=LAMBDA(ab,
DEGREES(
BEARINGDELTA(
RADIANS(ab)
)
)
)
BEARINGDELTA
=LAMBDA(ab,
LET(
sinab, SIN(ab),
cosab, COS(ab),
ax, INDEX(sinab, 1),
bx, INDEX(sinab, 2),
ay, INDEX(cosab, 1),
by, INDEX(cosab, 2),
rem, "Sign * dot product",
IF(0 < ((ay * bx) - (by * ax)),
1,
-1
) * ACOS((ax * bx) + (ay * by))
)
)
Using an Excel custom number format to display the degree symbol°
- Output:
fx | =ANGLEBETWEENBEARINGS(D2#) | |||||
---|---|---|---|---|---|---|
A | B | C | D | E | ||
1 | Difference | b1 | b2 | |||
2 | 25.00° | 20 | 45 | |||
3 | 90.00° | -45 | 45 | |||
4 | 175.00° | -85 | 90 | |||
5 | -175.00° | -95 | 90 | |||
6 | 170.00° | -45 | 125 | |||
7 | -170.00° | -45 | 145 | |||
8 | -118.12° | 29.4803 | -88.6381 | |||
9 | -80.71° | -78.3251 | -159.0360 | |||
10 | ||||||
11 | -139.58° | -70099.7423381093 | 29840.6743787672 | |||
12 | -72.34° | -165313.6666297350 | 33693.9894517456 | |||
13 | -161.50° | 1174.8380510598 | -154146.6649012470 | |||
14 | 37.30° | 60175.7730679554 | 42213.0719235437 |
F#
let deltaBearing (b1:double) (b2:double) =
let r = (b2 - b1) % 360.0;
if r > 180.0 then
r - 360.0
elif r < -180.0 then
r + 360.0
else
r
[<EntryPoint>]
let main _ =
printfn "%A" (deltaBearing 20.0 45.0)
printfn "%A" (deltaBearing -45.0 45.0)
printfn "%A" (deltaBearing -85.0 90.0)
printfn "%A" (deltaBearing -95.0 90.0)
printfn "%A" (deltaBearing -45.0 125.0)
printfn "%A" (deltaBearing -45.0 145.0)
printfn "%A" (deltaBearing 29.4803 -88.6381)
printfn "%A" (deltaBearing -78.3251 -159.036)
printfn "%A" (deltaBearing -70099.74233810938 29840.67437876723)
printfn "%A" (deltaBearing -165313.6666297357 33693.9894517456)
printfn "%A" (deltaBearing 1174.8380510598456 -154146.66490124757)
printfn "%A" (deltaBearing 60175.77306795546 42213.07192354373)
0 // return an integer exit code
- Output:
25.0 90.0 175.0 -175.0 170.0 -170.0 -118.1184 -80.7109 -139.5832831 -72.34391852 -161.5029523 37.29885559
Factor
USING: combinators generalizations kernel math prettyprint ;
IN: rosetta-code.bearings
: delta-bearing ( x y -- z )
swap - 360 mod {
{ [ dup 180 > ] [ 360 - ] }
{ [ dup -180 < ] [ 360 + ] }
[ ]
} cond ;
: bearings-demo ( -- )
20 45
-45 45
-85 90
-95 90
-45 125
-45 145
29.4803 -88.6381
-78.3251 -159.036
-70099.74233810938 29840.67437876723
-165313.6666297357 33693.9894517456
1174.8380510598456 -154146.66490124757
60175.77306795546 42213.07192354373
[ delta-bearing . ] 2 12 mnapply ;
MAIN: bearings-demo
- Output:
25 90 175 -175 170 -170 -118.1184 -80.7109 -139.5832831233856 -72.34391851868713 -161.5029523074045 37.29885558826936
Forth
Developed with Gforth 0.7.9_20211014 using floating point math.
: Angle-Difference-stack ( b1 b2 - a +/-180)
\ Algorithm with stack manipulation without branches ( s. Frotran Groovy)
fswap f- \ Delta angle
360e fswap fover fmod \ mod 360
fover 1.5e f* f+ \ + 540
fover fmod \ mod 360
fswap f2/ f- \ - 180
;
: Angle-Difference-const ( b1 b2 - a +/-180)
\ Algorithm without Branches ( s. Fotran Groovy)
fswap f-
360e fmod
540e f+
360e fmod
180e f-
;
\ Test Word for requested tests
: test-ad ( b1 b2 -- )
fover fover
Angle-Difference-stack f.
Angle-Difference-const f.
;
- Output:
20e 45e test-ad 25. 25. -45e 45e test-ad 90. 90. -85e 90e test-ad 175. 175. -95e 90e test-ad -175. -175. -45e 125e test-ad 170. 170. -45e 145e test-ad -170. -170. 29.4803e -88.6381e test-ad -118.1184 -118.1184 -78.3251e -159.036e test-ad -80.7109 -80.7109 -70099.74233810938e 29840.67437876723e test-ad -139.583283123386 -139.583283123386 -165313.6666297357e 33693.9894517456e test-ad -72.3439185186871 -72.3439185186871 1174.8380510598456e -154146.66490124757e test-ad -161.502952307404 -161.502952307404 60175.77306795546e 42213.07192354373e test-ad 37.2988555882694 37.2988555882694
Fortran
Rather than calculate angle differences and mess about with folding the results into ±180 and getting the sign right, why not use some mathematics? These days, trigonometrical functions are calculated swiftly by specialised hardware (well, microcode), and with the availability of functions working in degrees, matters are eased further nor is precision lost in converting from degrees to radians. So, the first step is to convert a bearing into an (x,y) unit vector via function CIS(t) = cos(t) + i.sin(t), which will handle all the annoyance of bearings specified in values above 360. Then, using the dot product of the two vectors allows the cosine of the angle to be known, and the cross product determines the sign.
However, this relies on the unit vectors being accurately so, and their subsequent dot product not exceeding one in size: given the rounding of results with the limited precision actual floating-point arithmetic, there may be problems. Proving that a calculation will not suffer these on a specific computer is difficult, especially as the desire for such a result may mean that any apparent pretext leading to that belief will be seized upon. Because calculations on the IBM pc and similar computers are conducted with 80-bit floating-point arithmetic, rounding errors for 64-bit results are likely to be small, but past experience leads to a "fog of fear" about the precise behaviour of floating-point arithmetic.
As it happens, the test data did not provoke any objections from the ACOSD function, but even so, a conversion to using arctan instead of arccos to recover angles would be safer. By using the four-quadrant arctan(x,y) function, the sign of the angle difference is also delivered and although that result could be in 0°-360° it turns out to be in ±180° as desired. On the other hand, the library of available functions did not include an arctan for complex parameters, so the complex number Z had to be split into its real and imaginary parts, thus requiring two appearances and to avoid repeated calculation, a temporary variable Z is needed. Otherwise, the statement could have been just T = ATAN2D(Z1*CONJG(Z2))
and the whole calculation could be effected in one statement, T = ATAN2D(CIS(90 - B1)*CONJG(CIS(90 - B2)))
And, since cis(t) = exp(i.t), T = ATAN2D(EXP(CMPLX(0,90 - B1))*CONJG(EXP(CMPLX(0,90 - B2))))
- although using the arithmetic statement function does seem less intimidating.
The source style is F77 (even using the old-style arithmetic statement function) except for the convenience of generic functions taking the type of their parameters to save on the bother of DCMPLX instead of just CMPLX, etc. Floating-point constants in the test data are specified with ~D0, the exponential form that signifies double precision otherwise they would be taken as single precision values. Some compilers offer an option stating that all floating-point constants are to be taken as double precision. REAL*8 precision amounts to about sixteen decimal digits, so some of the supplied values will not be accurately represented, unless something beyond REAL*8 is available.
SUBROUTINE BDIFF (B1,B2) !Difference B2 - B1, as bearings. All in degrees, not radians.
REAL*8 B1,B2 !Maximum precision, for large-angle folding.
COMPLEX*16 CIS,Z1,Z2,Z !Scratchpads.
CIS(T) = CMPLX(COSD(T),SIND(T)) !Convert an angle into a unit vector.
Z1 = CIS(90 - B1) !Bearings run clockwise from north (y) around to east (x).
Z2 = CIS(90 - B2) !Mathematics runs counterclockwise from x (east).
Z = Z1*CONJG(Z2) !(Z1x,Z1y)(Z2x,-Z2y) = (Z1x.Z2x + Z1y.Z2y, Z1y.Z2x - Z1x.Z2y)
T = ATAN2D(AIMAG(Z),REAL(Z)) !Madly, arctan(x,y) is ATAN(Y,X)!
WRITE (6,10) B1,Z1,B2,Z2,T !Two sets of numbers, and a result.
10 FORMAT (2(F14.4,"(",F9.6,",",F9.6,")"),F9.3) !Two lots, and a tail.
END SUBROUTINE BDIFF !Having functions in degrees saves some bother.
PROGRAM ORIENTED
REAL*8 B(24) !Just prepare a wad of values.
DATA B/20D0,45D0, -45D0,45D0, -85D0,90D0, -95D0,90D0, !As specified.
1 -45D0,125D0, -45D0,145D0, 29.4803D0,-88.6381D0,
2 -78.3251D0, -159.036D0,
3 -70099.74233810938D0, 29840.67437876723D0,
4 -165313.6666297357D0, 33693.9894517456D0,
5 1174.8380510598456D0, -154146.66490124757D0,
6 60175.77306795546D0, 42213.07192354373D0/
WRITE (6,1) ("B",I,"x","y", I = 1,2) !Or, one could just list them twice.
1 FORMAT (28X,"Bearing calculations, in degrees"//
* 2(A13,I1,"(",A9,",",A9,")"),A9) !Compare format 10, above.
DO I = 1,23,2 !Step through the pairs.
CALL BDIFF(B(I),B(I + 1))
END DO
END
The output shows the stages:
Bearing calculations, in degrees B1( x, y) B2( x, y) 20.0000( 0.342020, 0.939693) 45.0000( 0.707107, 0.707107) 25.000 -45.0000(-0.707107, 0.707107) 45.0000( 0.707107, 0.707107) 90.000 -85.0000(-0.996195, 0.087156) 90.0000( 1.000000, 0.000000) 175.000 -95.0000(-0.996195,-0.087156) 90.0000( 1.000000, 0.000000) -175.000 -45.0000(-0.707107, 0.707107) 125.0000( 0.819152,-0.573576) 170.000 -45.0000(-0.707107, 0.707107) 145.0000( 0.573576,-0.819152) -170.000 29.4803( 0.492124, 0.870525) -88.6381(-0.999718, 0.023767) -118.118 -78.3251(-0.979312, 0.202358) -159.0360(-0.357781,-0.933805) -80.711 -70099.7423( 0.984016,-0.178078) 29840.6744(-0.633734, 0.773551) -139.584 -165313.6666(-0.959667, 0.281138) 33693.9895(-0.559023,-0.829152) -72.340 1174.8381( 0.996437,-0.084339) -154146.6649(-0.918252, 0.395996) -161.510 60175.7731( 0.826820, 0.562467) 42213.0719( 0.998565,-0.053561) 37.297
FreeBASIC
' version 28-01-2019
' compile with: fbc -s console
#Include "string.bi"
Function frmt(num As Double) As String
Dim As String temp = Format(num, "#######.#############")
Dim As Integer i = Len(temp) -1
If temp[i] = Asc(".") Then temp[i] = 32
If InStr(temp, ".") = 0 Then
Return Right(Space(10) + temp, 9) + Space(13)
End If
temp = Space(10) + temp + Space(13)
Return Mid(temp, InStr(temp, ".") -8, 22)
End Function
' ------=< MAIN >=------
Dim As Double b1, b2, bb1, bb2, diff
Print
Print " b1 b2 difference"
Print " -----------------------------------------------------------"
Do
Read b1, b2
If b1 = 0 And b2 = 0 Then Exit Do
diff = b2 - b1
diff = diff - Int(diff / 360) * 360
If diff > 180 Then diff -= 360
Print frmt(b1); frmt(b2); frmt(diff)
Loop
Data 20,45, -45,45, -85,90
Data -95,90, -45,125, -45,145
Data 29.4803,-88.6381, -78.3251,-159.036
Data -70099.74233810938, 29840.67437876723
Data -165313.6666297357, 33693.9894517456
Data 1174.8380510598456, -154146.66490124757
Data 60175.77306795546, 42213.07192354373
' empty keyboard buffer
While InKey <> "" : Wend
Print : Print "hit any key to end program"
Sleep
End
- Output:
b1 b2 difference ----------------------------------------------------------- 20 45 25 -45 45 90 -85 90 175 -95 90 -175 -45 125 170 -45 145 -170 29.4803 -88.6381 -118.1184 -78.3251 -159.036 -80.7109 -70099.7423381093831 29840.6743787672312 -139.5832831233856 -165313.6666297357006 33693.9894517455978 -72.3439185186871 1174.8380510598461 -154146.6649012475973 -161.5029523074336 60175.7730679554588 42213.0719235437282 37.2988555882694
FutureBasic
void local fn GetDifference( b1 as float, b2 as float )
float r = ( b2 - b1 ) mod 360.0
if r >= 180.0 then r = r - 360.0
printf @"%9.1f\u00B0 %10.1f\u00B0 = %7.1f\u00B0", b1, b2, r
end fn
printf @"Input in -180 to +180 range:"
printf @"-----------------------------------"
printf @"%9s %12s %15s", "b1", "b2", "distance"
printf @"-----------------------------------"
fn GetDifference( 20.0, 45.0 )
fn GetDifference( -45.0, 45.0 )
fn GetDifference( -85.0, 90.0 )
fn GetDifference( -95.0, 90.0 )
fn GetDifference( -45.0, 125.0 )
fn GetDifference( -45.0, 145.0 )
fn GetDifference( -45.0, 125.0 )
fn GetDifference( -45.0, 145.0 )
fn GetDifference( 29.4803, -88.6381 )
fn GetDifference( -78.3251, -159.036 )
fn GetDifference( -70099.74233810938, 29840.67437876723 )
fn GetDifference( -165313.6666297357, 33693.9894517456 )
fn GetDifference( 1174.8380510598456, -154146.66490124757 )
HandleEvents
- Output:
----------------------------------- b1 b2 distance ----------------------------------- 20.0° 45.0° = 25.0° -45.0° 45.0° = 90.0° -85.0° 90.0° = 175.0° -95.0° 90.0° = -175.0° -45.0° 125.0° = 170.0° -45.0° 145.0° = -170.0° -45.0° 125.0° = 170.0° -45.0° 145.0° = -170.0° 29.5° -88.6° = -118.1° -78.3° -159.0° = -80.7° -70099.7° 29840.7° = -139.6° -165313.7° 33694.0° = -72.3° 1174.8° -154146.7° = -161.5°
Go
Basic task solution:
One feature of this solution is that if you can rely on the input bearings being in the range -180 to 180, you don't have to use math.Mod. Another feature is the bearing type and method syntax.
package main
import "fmt"
type bearing float64
var testCases = []struct{ b1, b2 bearing }{
{20, 45},
{-45, 45},
{-85, 90},
{-95, 90},
{-45, 125},
{-45, 145},
{29.4803, -88.6381},
{-78.3251, -159.036},
}
func main() {
for _, tc := range testCases {
fmt.Println(tc.b2.Sub(tc.b1))
}
}
func (b2 bearing) Sub(b1 bearing) bearing {
switch d := b2 - b1; {
case d < -180:
return d + 360
case d > 180:
return d - 360
default:
return d
}
}
- Output:
25 90 175 -175 170 -170 -118.1184 -80.7109
Optional extra solution:
A feature here is that the function body is a one-liner sufficient for the task test cases.
package main
import (
"fmt"
"math"
)
var testCases = []struct{ b1, b2 float64 }{
{20, 45},
{-45, 45},
{-85, 90},
{-95, 90},
{-45, 125},
{-45, 145},
{29.4803, -88.6381},
{-78.3251, -159.036},
{-70099.74233810938, 29840.67437876723},
{-165313.6666297357, 33693.9894517456},
{1174.8380510598456, -154146.66490124757},
{60175.77306795546, 42213.07192354373},
}
func main() {
for _, tc := range testCases {
fmt.Println(angleDifference(tc.b2, tc.b1))
}
}
func angleDifference(b2, b1 float64) float64 {
return math.Mod(math.Mod(b2-b1, 360)+360+180, 360) - 180
}
- Output:
25 90 175 -175 170 -170 -118.11840000000001 -80.71089999999998 -139.58328312338563 -72.34391851868713 -161.50295230740448 37.29885558826936
Groovy
Solution A:
def angleDifferenceA(double b1, double b2) {
r = (b2 - b1) % 360.0
(r > 180.0 ? r - 360.0
: r <= -180.0 ? r + 360.0
: r)
}
Solution B:
In the spirit of the Fortran "Why branch when you can math?" solution, but without all the messy trigonometry.
def angleDifferenceB(double b1, double b2) {
((b2 - b1) % 360.0 - 540.0) % 360.0 + 180.0
}
NOTE: We could ADD 540 and SUBTRACT 180 instead (as did many others, notably 360_Assembly, NewLISP, Racket, and REXX). The difference is that my choice normalizes "about face" to +180° while the other (At least in Groovy and other C-derived languages) normalizes "about face" to -180°.
Test:
println " b1 b2 diff A diff B"
[
[b1: 20, b2: 45 ],
[b1: -45, b2: 45 ],
[b1: -85, b2: 90 ],
[b1: -95, b2: 90 ],
[b1: -45, b2: 125 ],
[b1: -45, b2: 145 ],
[b1: 29.4803, b2: -88.6381 ],
[b1: -78.3251, b2: -159.036 ],
[b1: -70099.74233810938, b2: 29840.67437876723 ],
[b1:-165313.6666297357, b2: 33693.9894517456 ],
[b1: 1174.8380510598456, b2:-154146.66490124757 ],
[b1: 60175.77306795546, b2: 42213.07192354373 ]
].each { bearings ->
def (b1,b2) = bearings.values().collect{ it as double }
printf ("%22.13f %22.13f %22.13f %22.13f\n", b1, b2, angleDifferenceA(b1, b2), angleDifferenceB(b1, b2))
}
Output:
b1 b2 diff A diff B 20.0000000000000 45.0000000000000 25.0000000000000 25.0000000000000 -45.0000000000000 45.0000000000000 90.0000000000000 90.0000000000000 -85.0000000000000 90.0000000000000 175.0000000000000 175.0000000000000 -95.0000000000000 90.0000000000000 -175.0000000000000 -175.0000000000000 -45.0000000000000 125.0000000000000 170.0000000000000 170.0000000000000 -45.0000000000000 145.0000000000000 -170.0000000000000 -170.0000000000000 29.4803000000000 -88.6381000000000 -118.1184000000000 -118.1184000000000 -78.3251000000000 -159.0360000000000 -80.7109000000000 -80.7109000000000 -70099.7423381093800 29840.6743787672300 -139.5832831233856 -139.5832831233856 -165313.6666297357000 33693.9894517456000 -72.3439185186871 -72.3439185186871 1174.8380510598456 -154146.6649012475700 -161.5029523074045 -161.5029523074045 60175.7730679554600 42213.0719235437300 37.2988555882694 37.2988555882694
Haskell
import Control.Monad (join)
import Data.Bifunctor (bimap)
import Text.Printf (printf)
type Radians = Float
type Degrees = Float
---------- ANGLE DIFFERENCE BETWEEN TWO BEARINGS ---------
bearingDelta :: (Radians, Radians) -> Radians
bearingDelta (a, b) -- sign * dot-product
=
sign * acos ((ax * bx) + (ay * by))
where
(ax, ay) = (sin a, cos a)
(bx, by) = (sin b, cos b)
sign
| ((ay * bx) - (by * ax)) > 0 = 1
| otherwise = -1
angleBetweenDegrees :: (Degrees, Degrees) -> Degrees
angleBetweenDegrees =
degrees
. bearingDelta
. join bimap radians
--------------------------- TEST -------------------------
main :: IO ()
main =
putStrLn . unlines $
fmap
( uncurry (printf "%6.2f° - %6.2f° -> %7.2f°")
<*> angleBetweenDegrees
)
[ (20.0, 45.0),
(-45.0, 45.0),
(-85.0, 90.0),
(-95.0, 90.0),
(-45.0, 125.0),
(-45.0, 145.0)
]
------------------------- GENERIC ------------------------
degrees :: Radians -> Degrees
degrees = (/ pi) . (180 *)
radians :: Degrees -> Radians
radians = (/ 180) . (pi *)
- Output:
20.00° - 45.00° -> 25.00° -45.00° - 45.00° -> 90.00° -85.00° - 90.00° -> 175.00° -95.00° - 90.00° -> -175.00° -45.00° - 125.00° -> 170.00° -45.00° - 145.00° -> -170.00°
IS-BASIC
100 INPUT PROMPT "1. angle: ":A1
110 INPUT PROMPT "2. angle: ":A2
120 LET B=MOD(A2-A1,360)
130 IF B>180 THEN LET B=B-360
140 IF B<-180 THEN LET B=B+360
150 PRINT "Difference: ";B
J
relativeBearing=: 180 - 360 | 180 + -
tests=: _99&".;._2 noun define
20 45
-45 45
-85 90
-95 90
-45 125
-45 145
29.4803 -88.6381
-78.3251 -159.036
-70099.74233810938 29840.67437876723
-165313.6666297357 33693.9894517456
1174.8380510598456 -154146.66490124757
60175.77306795546 42213.07192354373
)
tests ,. relativeBearing/"1 tests 20 45 25 _45 45 90 _85 90 175 _95 90 _175 _45 125 170 _45 145 _170 29.4803 _88.6381 _118.118 _78.3251 _159.036 _80.7109 _70099.7 29840.7 _139.583 _165314 33694 _72.3439 1174.84 _154147 _161.503 60175.8 42213.1 37.2989
Java
public class AngleDifference {
public static double getDifference(double b1, double b2) {
double r = (b2 - b1) % 360.0;
if (r < -180.0)
r += 360.0;
if (r >= 180.0)
r -= 360.0;
return r;
}
public static void main(String[] args) {
System.out.println("Input in -180 to +180 range");
System.out.println(getDifference(20.0, 45.0));
System.out.println(getDifference(-45.0, 45.0));
System.out.println(getDifference(-85.0, 90.0));
System.out.println(getDifference(-95.0, 90.0));
System.out.println(getDifference(-45.0, 125.0));
System.out.println(getDifference(-45.0, 145.0));
System.out.println(getDifference(-45.0, 125.0));
System.out.println(getDifference(-45.0, 145.0));
System.out.println(getDifference(29.4803, -88.6381));
System.out.println(getDifference(-78.3251, -159.036));
System.out.println("Input in wider range");
System.out.println(getDifference(-70099.74233810938, 29840.67437876723));
System.out.println(getDifference(-165313.6666297357, 33693.9894517456));
System.out.println(getDifference(1174.8380510598456, -154146.66490124757));
System.out.println(getDifference(60175.77306795546, 42213.07192354373));
}
}
- Output:
Input in -180 to +180 range 25.0 90.0 175.0 -175.0 170.0 -170.0 170.0 -170.0 -118.1184 -80.7109 Input in wider range -139.58328312338563 -72.34391851868713 -161.50295230740448 37.29885558826936
JavaScript
ES5
This approach should be reliable but it is also very inefficient.
function relativeBearing(b1Rad, b2Rad)
{
b1y = Math.cos(b1Rad);
b1x = Math.sin(b1Rad);
b2y = Math.cos(b2Rad);
b2x = Math.sin(b2Rad);
crossp = b1y * b2x - b2y * b1x;
dotp = b1x * b2x + b1y * b2y;
if(crossp > 0.)
return Math.acos(dotp);
return -Math.acos(dotp);
}
function test()
{
var deg2rad = 3.14159265/180.0;
var rad2deg = 180.0/3.14159265;
return "Input in -180 to +180 range\n"
+relativeBearing(20.0*deg2rad, 45.0*deg2rad)*rad2deg+"\n"
+relativeBearing(-45.0*deg2rad, 45.0*deg2rad)*rad2deg+"\n"
+relativeBearing(-85.0*deg2rad, 90.0*deg2rad)*rad2deg+"\n"
+relativeBearing(-95.0*deg2rad, 90.0*deg2rad)*rad2deg+"\n"
+relativeBearing(-45.0*deg2rad, 125.0*deg2rad)*rad2deg+"\n"
+relativeBearing(-45.0*deg2rad, 145.0*deg2rad)*rad2deg+"\n"
+relativeBearing(29.4803*deg2rad, -88.6381*deg2rad)*rad2deg+"\n"
+relativeBearing(-78.3251*deg2rad, -159.036*deg2rad)*rad2deg+"\n"
+ "Input in wider range\n"
+relativeBearing(-70099.74233810938*deg2rad, 29840.67437876723*deg2rad)*rad2deg+"\n"
+relativeBearing(-165313.6666297357*deg2rad, 33693.9894517456*deg2rad)*rad2deg+"\n"
+relativeBearing(1174.8380510598456*deg2rad, -154146.66490124757*deg2rad)*rad2deg+"\n"
+relativeBearing(60175.77306795546*deg2rad, 42213.07192354373*deg2rad)*rad2deg+"\n";
}
- Output:
Input in -180 to +180 range 25.000000000000004 90 174.99999999999997 -175.00000041135993 170.00000000000003 -170.00000041135996 -118.1184 -80.71089999999998 Input in wider range -139.5833974814558 -72.34414600076728 -161.50277501127033 37.2988761562732
ES6
(() => {
"use strict";
// ------ ANGLE DIFFERENCE BETWEEN TWO BEARINGS ------
// bearingDelta :: Radians -> Radians -> Radians
const bearingDelta = a =>
// The difference between two bearings: a and b.
b => {
const [ax, ay] = [sin(a), cos(a)];
const [bx, by] = [sin(b), cos(b)];
// Cross-product above zero ?
const sign = ((ay * bx) - (by * ax)) > 0 ? (
+1
) : -1;
// Sign * dot-product.
return sign * acos((ax * bx) + (ay * by));
};
// ---------------------- TEST -----------------------
// main :: IO ()
const main = () => [
[20, 45],
[-45, 45],
[-85, 90],
[-95, 90],
[-45, 125],
[-45, 145]
].map(xy => showMap(...xy))
.join("\n");
// ------------------- FORMATTING --------------------
// showMap :: Degrees -> Degrees -> String
const showMap = (da, db) => {
const
delta = degreesFromRadians(
bearingDelta(
radiansFromDegrees(da)
)(
radiansFromDegrees(db)
)
)
.toPrecision(4),
theta = `${da}° +`.padStart(6, " "),
theta1 = ` ${db}° -> `.padStart(11, " "),
diff = `${delta}°`.padStart(7, " ");
return `${theta}${theta1}${diff}`;
};
// --------------------- GENERIC ---------------------
// radiansFromDegrees :: Float -> Float
const radiansFromDegrees = n =>
Pi * n / 180.0;
// degreesFromRadians :: Float -> Float
const degreesFromRadians = x =>
180.0 * x / Pi;
// Abbreviations for trigonometric methods and
// properties of the standard Math library.
const [
Pi, sin, cos, acos
] = ["PI", "sin", "cos", "acos"]
.map(k => Math[k]);
// MAIN ---
return main();
})();
- Output:
20° + 45° -> 25.00° -45° + 45° -> 90.00° -85° + 90° -> 175.0° -95° + 90° -> -175.0° -45° + 125° -> 170.0° -45° + 145° -> -170.0°
Jsish
/* Angle difference between bearings, in Jsish */
function angleDifference(bearing1:number, bearing2:number):number {
var angle = (bearing2 - bearing1) % 360;
if (angle < -180) angle += 360;
if (angle >= 180) angle -= 360;
return angle;
}
if (Interp.conf('unitTest')) {
var dataSet = [[20, 45], [-45, 45], [-85, 90], [-95, 90], [-45, 125], [-45, 145],
[29.4803, -88.6381], [-78.3251, -159.036],
[-70099.74233810938, 29840.67437876723],
[-165313.6666297357, 33693.9894517456],
[1174.8380510598456, -154146.66490124757],
[60175.77306795546, 42213.07192354373]];
printf(" Bearing 1 Bearing 2 Difference\n");
for (var i = 0; i < dataSet.length; i++) {
printf("%17S° %17S° %17S°\n", dataSet[i][0], dataSet[i][1],
angleDifference(dataSet[i][0], dataSet[i][1])
);
}
}
/*
=!EXPECTSTART!=
Bearing 1 Bearing 2 Difference
20° 45° 25°
-45° 45° 90°
-85° 90° 175°
-95° 90° -175°
-45° 125° 170°
-45° 145° -170°
29.4803° -88.6381° -118.1184°
-78.3251° -159.036° -80.7109°
-70099.7423381094° 29840.6743787672° -139.583283123386°
-165313.666629736° 33693.9894517456° -72.3439185186871°
1174.83805105985° -154146.664901248° -161.502952307404°
60175.7730679555° 42213.0719235437° 37.2988555882694°
=!EXPECTEND!=
*/
- Output:
prompt$ jsish -u angleDifference.jsi [PASS] angleDifference.jsi
jq
Works with gojq, the Go implementation of jq
Note that the `%` operator in jq produces integral results.
# Angles are in degrees; the result is rounded to 4 decimal places:
def subtract($b1; $b2):
10000 as $scale
| (($scale * ($b2 - $b1)) % (360 * $scale)) | round / $scale
| if . < -180 then . + 360
elif . >= 180 then . - 360
else .
end;
def pairs:
[ 20, 45],
[-45, 45],
[-85, 90],
[-95, 90],
[-45, 125],
[-45, 145],
[ 29.4803, -88.6381],
[-78.3251, -159.036],
[-70099.74233810938, 29840.67437876723],
[-165313.6666297357, 33693.9894517456],
[1174.8380510598456, -154146.66490124757],
[60175.77306795546, 42213.07192354373] ;
"Differences (to 4dp) between these bearings:",
( pairs as [$p0, $p1]
| subtract($p0; $p1) as $diff
| (if $p0 < 0 then " " else " " end) as $offset
| "\($offset)\($p0) and \($p1) -> \($diff)" )
- Output:
Differences (to 4dp) between these bearings: 20 and 45 -> 25 -45 and 45 -> 90 -85 and 90 -> 175 -95 and 90 -> -175 -45 and 125 -> 170 -45 and 145 -> -170 29.4803 and -88.6381 -> -118.1184 -78.3251 and -159.036 -> -80.7109 -70099.74233810938 and 29840.67437876723 -> -139.5833 -165313.6666297357 and 33693.9894517456 -> -72.344 1174.8380510598456 and -154146.66490124757 -> -161.5029 60175.77306795546 and 42213.07192354373 -> 37.2989
Differences (to 4dp) between these bearings:
20 and 45 -> 25 -45 and 45 -> 90 -85 and 90 -> 175 -95 and 90 -> -175 -45 and 125 -> 170 -45 and 145 -> -170 29.4803 and -88.6381 -> -118.1184 -78.3251 and -159.036 -> -80.7109 -70099.74233810938 and 29840.67437876723 -> -139.5833 -165313.6666297357 and 33693.9894517456 -> -72.344 1174.8380510598456 and -154146.66490124757 -> -161.5029 60175.77306795546 and 42213.07192354373 -> 37.2989
Julia
using Printf
function angdiff(a, b)
r = (b - a) % 360.0
if r ≥ 180.0
r -= 360.0
end
return r
end
println("Input in -180 to +180 range:")
for (a, b) in [(20.0, 45.0), (-45.0, 45.0), (-85.0, 90.0), (-95.0, 90.0), (-45.0, 125.0), (-45.0, 145.0),
(-45.0, 125.0), (-45.0, 145.0), (29.4803, -88.6381), (-78.3251, -159.036)]
@printf("% 6.1f - % 6.1f = % 6.1f\n", a, b, angdiff(a, b))
end
println("\nInput in wider range:")
for (a, b) in [(-70099.74233810938, 29840.67437876723), (-165313.6666297357, 33693.9894517456),
(1174.8380510598456, -154146.66490124757), (60175.77306795546, 42213.07192354373)]
@printf("% 9.1f - % 9.1f = % 6.1f\n", a, b, angdiff(a, b))
end
- Output:
Input in -180 to +180 range: 20.0 - 45.0 = 25.0 -45.0 - 45.0 = 90.0 -85.0 - 90.0 = 175.0 -95.0 - 90.0 = -175.0 -45.0 - 125.0 = 170.0 -45.0 - 145.0 = -170.0 -45.0 - 125.0 = 170.0 -45.0 - 145.0 = -170.0 29.5 - -88.6 = -118.1 -78.3 - -159.0 = -80.7 Input in wider range: -70099.7 - 29840.7 = -139.6 -165313.7 - 33694.0 = -72.3 1174.8 - -154146.7 = -161.5 60175.8 - 42213.1 = -322.7
K
/ Angle difference between two angles
/ angledif.k
angdif: {[b1;b2]; :[(r:(b2-b1)!360.0)<-180.0;r+:360.0;r>180.0;r-:360.0];:r}
The output of a session is given below:
- Output:
K Console - Enter \ for help \l angledif angdif[20;45] 25.0 angdif[-45;45] 90.0 angdif[-85;90] 175.0 angdif[-95;90] -175.0 angdif[-45;125] 170.0 angdif[29.4803;-88.6381] -118.1184 angdif[-78.3251;-159.036] -80.7109 angdif[-70099.74233810938;29840.67437876723] -139.5833
Klingphix
include ..\Utilitys.tlhy
:bearing sub 360 mod 540 add 360 mod 180 sub ;
20 45 bearing
-45 45 bearing
-85 90 bearing
-95 90 bearing
-45 125 bearing
-45 145 bearing
29.4803 -88.6381 bearing
-78.3251 -159.036 bearing
-70099.74233810938 29840.67437876723 bearing
-165313.6666297357 33693.9894517456 bearing
1174.8380510598456 -154146.66490124757 bearing
60175.77306795546 42213.07192354373 bearing
pstack
" " input
- Output:
(-25, -90, -175, 175, -170, 170, 118.118, 80.7109, 139.583, 72.3439, 161.503, -37.2989)
Kotlin
// version 1.1.2
class Angle(d: Double) {
val value = when {
d in -180.0 .. 180.0 -> d
d > 180.0 -> (d - 180.0) % 360.0 - 180.0
else -> (d + 180.0) % 360.0 + 180.0
}
operator fun minus(other: Angle) = Angle(this.value - other.value)
}
fun main(args: Array<String>) {
val anglePairs = arrayOf(
20.0 to 45.0,
-45.0 to 45.0,
-85.0 to 90.0,
-95.0 to 90.0,
-45.0 to 125.0,
-45.0 to 145.0,
29.4803 to -88.6381,
-78.3251 to -159.036,
-70099.74233810938 to 29840.67437876723,
-165313.6666297357 to 33693.9894517456,
1174.8380510598456 to -154146.66490124757,
60175.77306795546 to 42213.07192354373
)
println(" b1 b2 diff")
val f = "% 12.4f % 12.4f % 12.4f"
for (ap in anglePairs) {
val diff = Angle(ap.second) - Angle(ap.first)
println(f.format(ap.first, ap.second, diff.value))
}
}
- Output:
b1 b2 diff 20.0000 45.0000 25.0000 -45.0000 45.0000 90.0000 -85.0000 90.0000 175.0000 -95.0000 90.0000 -175.0000 -45.0000 125.0000 170.0000 -45.0000 145.0000 -170.0000 29.4803 -88.6381 -118.1184 -78.3251 -159.0360 -80.7109 -70099.7423 29840.6744 -139.5833 -165313.6666 33693.9895 -72.3439 1174.8381 -154146.6649 -161.5030 60175.7731 42213.0719 37.2989
Lua
Each bearing will be stored in an object that inherits methods to accomplish all parts of the task: accept a new number of degrees, automatically adjusting to the range [-180, 180]; construct new bearing objects; subtract another bearing from itself and return the difference; construct a list of new bearing objects given a list of arbitrary degree sizes; and format the number of degrees into a modest human-readable format. Bearings will be zero-initialized by default if no degree size is provided.
bearing = {degrees = 0} -- prototype object
function bearing:assign(angle)
angle = tonumber(angle) or 0
while angle > 180 do
angle = angle - 360
end
while angle < -180 do
angle = angle + 360
end
self.degrees = angle
end
function bearing:new(size)
local child_object = {}
setmetatable(child_object, {__index = self})
child_object:assign(size)
return child_object
end
function bearing:subtract(other)
local difference = self.degrees - other.degrees
return self:new(difference)
end
function bearing:list(sizes)
local bearings = {}
for index, size in ipairs(sizes) do
table.insert(bearings, self:new(size))
end
return bearings
end
function bearing:text()
return string.format("%.4f deg", self.degrees)
end
function main()
local subtrahends = bearing:list{
20, -45, -85, -95, -45, -45, 29.4803, -78.3251,
-70099.74233810938, -165313.6666297357,
1174.8380510598456, 60175.77306795546
}
local minuends = bearing:list{
45, 45, 90, 90, 125, 145, -88.6381, -159.036,
29840.67437876723, 33693.9894517456,
-154146.66490124757, 42213.07192354373
}
for index = 1, #minuends do
local b2, b1 = minuends[index], subtrahends[index]
local b3 = b2:subtract(b1)
local statement = string.format(
"%s - %s = %s\n",
b2:text(), b1:text(), b3:text()
)
io.write(statement)
end
end
main()
- Output:
45.0000 deg - 20.0000 deg = 25.0000 deg 45.0000 deg - -45.0000 deg = 90.0000 deg 90.0000 deg - -85.0000 deg = 175.0000 deg 90.0000 deg - -95.0000 deg = -175.0000 deg 125.0000 deg - -45.0000 deg = 170.0000 deg 145.0000 deg - -45.0000 deg = -170.0000 deg -88.6381 deg - 29.4803 deg = -118.1184 deg -159.0360 deg - -78.3251 deg = -80.7109 deg -39.3256 deg - 100.2577 deg = -139.5833 deg -146.0105 deg - -73.6666 deg = -72.3439 deg -66.6649 deg - 94.8381 deg = -161.5030 deg 93.0719 deg - 55.7731 deg = 37.2989 deg
Maple
getDiff := proc(b1,b2)
local r:
r := frem(b2 - b1, 360):
if r >= 180 then r := r - 360: fi:
return r:
end proc:
getDiff(20,45);
getDiff(-45,45);
getDiff(-85,90);
getDiff(-95,90);
getDiff(-45,125);
getDiff(-45,145);
getDiff(29.4803, -88.6381);
getDiff(-78.3251,-159.036);
getDiff(-70099.74233810938,29840.67437876723);
getDiff(-165313.6666297357,33693.9894517456);
getDiff(1174.8380510598456,-154146.66490124757);
getDiff(60175.77306795546,42213.07192354373)
- Output:
25 90 175 -175 170 -170 -118.1184 -80.7109 -139.58328 -72.3340 -161.5030 37.29885
Mathematica /Wolfram Language
ClearAll[AngleDifference]
AngleDifference[b1_, b2_] := Mod[b2 - b1, 360, -180]
AngleDifference[20, 45]
AngleDifference[-45, 45]
AngleDifference[-85, 90]
AngleDifference[-95, 90]
AngleDifference[-45, 125]
AngleDifference[-45, 145]
AngleDifference[29.4803, -88.6381]
AngleDifference[-78.3251, -159.036]
AngleDifference[-70099.74233810938, 29840.67437876723]
AngleDifference[-165313.6666297357, 33693.9894517456]
AngleDifference[1174.8380510598456, -154146.66490124757]
AngleDifference[60175.77306795546, 42213.07192354373]
- Output:
25 90 175 -175 170 -170 -118.118 -80.7109 -139.583 -72.3439 -161.503 37.2989
Modula-2
FROM Terminal IMPORT *;
PROCEDURE WriteRealLn(value : REAL);
VAR str : ARRAY[0..16] OF CHAR;
BEGIN
RealToStr(value, str);
WriteString(str);
WriteLn;
END WriteRealLn;
PROCEDURE AngleDifference(b1, b2 : REAL) : REAL;
VAR r : REAL;
BEGIN
r := (b2 - b1);
WHILE r < -180.0 DO
r := r + 360.0;
END;
WHILE r >= 180.0 DO
r := r - 360.0;
END;
RETURN r;
END AngleDifference;
BEGIN
WriteString('Input in -180 to +180 range');
WriteLn;
WriteRealLn(AngleDifference(20.0, 45.0));
WriteRealLn(AngleDifference(-45.0, 45.0));
WriteRealLn(AngleDifference(-85.0, 90.0));
WriteRealLn(AngleDifference(-95.0, 90.0));
WriteRealLn(AngleDifference(-45.0, 125.0));
WriteRealLn(AngleDifference(-45.0, 145.0));
WriteRealLn(AngleDifference(29.4803, -88.6381));
WriteRealLn(AngleDifference(-78.3251, -159.036));
WriteString('Input in wider range');
WriteLn;
WriteRealLn(AngleDifference(-70099.74233810938, 29840.67437876723));
WriteRealLn(AngleDifference(-165313.6666297357, 33693.9894517456));
WriteRealLn(AngleDifference(1174.8380510598456, -154146.66490124757));
WriteRealLn(AngleDifference(60175.77306795546, 42213.07192354373));
ReadChar;
END Bearings.
NewLISP
Taken from Racket solution
#!/usr/bin/env newlisp
(define (bearing- bearing heading) (sub (mod (add (mod (sub bearing heading) 360.0) 540.0) 360.0) 180.0))
(bearing- 20 45)
(bearing- -45 45)
(bearing- -85 90)
(bearing- -95 90)
(bearing- -45 125)
(bearing- -45 145)
(bearing- 29.4803 -88.6381)
(bearing- -78.3251 -159.036)
(bearing- -70099.74233810938 29840.67437876723)
(bearing- -165313.6666297357 33693.9894517456)
(bearing- 1174.8380510598456 -154146.66490124757)
(bearing- 60175.77306795546 42213.07192354373))
- Output:
-25 -90 -175 175 -170 170 118.11839999999995 80.71090000000004 139.58328312338563 72.34391851868713 161.50295230740448 -37.29885558826936
Nim
import math
import strutils
proc delta(b1, b2: float) : float =
result = (b2 - b1) mod 360.0
if result < -180.0:
result += 360.0
elif result >= 180.0:
result -= 360.0
let testVectors : seq[tuple[b1, b2: float]] = @[
(20.00, 45.00 ),
(-45.00, 45.00 ),
(-85.00, 90.00 ),
(-95.00, 90.00 ),
(-45.00, 125.00 ),
(-45.00, 145.00 ),
( 29.48, -88.64 ),
(-78.33, -159.04 ),
(-70099.74, 29840.67 ),
(-165313.67, 33693.99 ),
(1174.84, -154146.66 ),
(60175.77, 42213.07 ) ]
for vector in testVectors:
echo vector.b1.formatFloat(ffDecimal, 2).align(13) &
vector.b2.formatFloat(ffDecimal, 2).align(13) &
delta(vector.b1, vector.b2).formatFloat(ffDecimal, 2).align(13)
- Output:
20.00 45.00 25.00 -45.00 45.00 90.00 -85.00 90.00 175.00 -95.00 90.00 -175.00 -45.00 125.00 170.00 -45.00 145.00 -170.00 29.48 -88.64 -118.12 -78.33 -159.04 -80.71 -70099.74 29840.67 -139.59 -165313.67 33693.99 -72.34 1174.84 -154146.66 -161.50 60175.77 42213.07 37.30
Nutt
module main
imports native.io.output.say
funct get_difference(b1:Float,b2:Float):Float=
var r:Float=(b2-b1)%360.0
doif r< -180.0 r=r+360.0
doif r>=180.0 r=r-360.0
yield r
return
say("Input in -180 to +180 range")
say(get_difference(20.0,45.0))
say(get_difference(-45.0,45.0))
say(get_difference(-85.0,90.0))
say(get_difference(-95.0,90.0))
say(get_difference(-45.0,125.0))
say(get_difference(-45.0,145.0))
say(get_difference(-45.0,125.0))
say(get_difference(-45.0,145.0))
say(get_difference(29.4803,-88.6381))
say(get_difference(-78.3251,-159.036))
say("Input in wider range")
say(get_difference(-70099.74233810938,29840.67437876723))
say(get_difference(-165313.6666297357,33693.9894517456))
say(get_difference(1174.8380510598456,-154146.66490124757))
say(get_difference(60175.77306795546,42213.07192354373))
end
- Output:
Input in -180 to +180 range 25.0 90.0 175.0 -175.0 170.0 -170.0 170.0 -170.0 -118.1184 -80.7109 Input in wider range -139.58328312339 -72.3439185187 -161.5029523074156 37.29885558827
Objeck
class AngleBearings {
function : Main(args : String[]) ~ Nil {
"Input in -180 to +180 range"->PrintLine();
GetDifference(20.0, 45.0)->PrintLine();
GetDifference(-45.0, 45.0)->PrintLine();
GetDifference(-85.0, 90.0)->PrintLine();
GetDifference(-95.0, 90.0)->PrintLine();
GetDifference(-45.0, 125.0)->PrintLine();
GetDifference(-45.0, 145.0)->PrintLine();
GetDifference(-45.0, 125.0)->PrintLine();
GetDifference(-45.0, 145.0)->PrintLine();
GetDifference(29.4803, -88.6381)->PrintLine();
GetDifference(-78.3251, -159.036)->PrintLine();
"Input in wider range"->PrintLine();
GetDifference(-70099.74233810938, 29840.67437876723)->PrintLine();
GetDifference(-165313.6666297357, 33693.9894517456)->PrintLine();
GetDifference(1174.8380510598456, -154146.66490124757)->PrintLine();
GetDifference(60175.77306795546, 42213.07192354373)->PrintLine();
}
function : native : GetDifference(b1 : Float, b2 : Float) ~ Float {
r := Float->Mod(b2 - b1, 360.0);
if (r < -180.0) {
r += 360.0;
};
if (r >= 180.0) {
r -= 360.0;
};
return r;
}
}
- Output:
Input in -180 to +180 range 25 90 175 -175 170 -170 170 -170 -118.118 -80.7109 Input in wider range -139.583 -72.3439 -161.503 37.2989
OCaml
let get_diff b1 b2 =
let r = mod_float (b2 -. b1) 360.0 in
if r < -180.0
then r +. 360.0
else if r >= 180.0
then r -. 360.0
else r
let () =
print_endline "Input in -180 to +180 range";
Printf.printf " %g\n" (get_diff 20.0 45.0);
Printf.printf " %g\n" (get_diff (-45.0) 45.0);
Printf.printf " %g\n" (get_diff (-85.0) 90.0);
Printf.printf " %g\n" (get_diff (-95.0) 90.0);
Printf.printf " %g\n" (get_diff (-45.0) 125.0);
Printf.printf " %g\n" (get_diff (-45.0) 145.0);
Printf.printf " %g\n" (get_diff (-45.0) 125.0);
Printf.printf " %g\n" (get_diff (-45.0) 145.0);
Printf.printf " %g\n" (get_diff 29.4803 (-88.6381));
Printf.printf " %g\n" (get_diff (-78.3251) (-159.036));
print_endline "Input in wider range";
Printf.printf " %g\n" (get_diff (-70099.74233810938) 29840.67437876723);
Printf.printf " %g\n" (get_diff (-165313.6666297357) 33693.9894517456);
Printf.printf " %g\n" (get_diff 1174.8380510598456 (-154146.66490124757));
Printf.printf " %g\n" (get_diff 60175.77306795546 42213.07192354373);
;;
- Output:
Input in -180 to +180 range 25 90 175 -175 170 -170 170 -170 -118.118 -80.7109 Input in wider range -139.583 -72.3439 -161.503 37.2989
PARI/GP
centerliftmod1(x)=frac(x+1/2)-1/2;
anglediff(x,y)=centerliftmod1((y-x)/360)*360;
vecFunc(f)=v->call(f,v);
apply(vecFunc(anglediff), [[20,45], [-45,45], [-85,90], [-95,90], [-45,125], [-45,145], [29.4803,-88.6381], [-78.3251,-159.036], [-70099.74233810938,29840.67437876723], [-165313.6666297357,33693.9894517456], [1174.8380510598456,-154146.66490124757], [60175.77306795546,42213.07192354373]])
- Output:
%1 = [25, 90, 175, -175, 170, -170, -118.11840000000000000000000000000000000, -80.710900000000000000000000000000000000, -139.58328312339000000000000000000000023, -72.343918518700000000000000000000000733, -161.50295230741560000000000000000000000, 37.298855588269999999999999999999999909]
Pascal
This program is meant to be saved in the same folder as a file angles.txt
containing the input. Each pair of angles to subtract appears on its own line in the input file.
Program Bearings;
{ Reads pairs of angles from a file and subtracts them }
Const
fileName = 'angles.txt';
Type
degrees = real;
Var
subtrahend, minuend: degrees;
angleFile: text;
function Simplify(angle: degrees): degrees;
{ Returns an number in the range [-180.0, 180.0] }
begin
while angle > 180.0 do
angle := angle - 360.0;
while angle < -180.0 do
angle := angle + 360.0;
Simplify := angle
end;
function Difference(b1, b2: degrees): degrees;
{ Subtracts b1 from b2 and returns a simplified result }
begin
Difference := Simplify(b2 - b1)
end;
procedure Subtract(b1, b2: degrees);
{ Subtracts b1 from b2 and shows the whole equation onscreen }
var
b3: degrees;
begin
b3 := Difference(b1, b2);
writeln(b2:20:11, ' - ', b1:20:11, ' = ', b3:20:11)
end;
Begin
assign(angleFile, fileName);
reset(angleFile);
while not eof(angleFile) do
begin
readln(angleFile, subtrahend, minuend);
Subtract(subtrahend, minuend)
end;
close(angleFile)
End.
- Input:
20 45 -45 45 -85 90 -95 90 -45 125 -45 145 29.4803 -88.6381 -78.3251 -159.036 -70099.74233810938 29840.67437876723 -165313.6666297357 33693.9894517456 1174.8380510598456 -154146.66490124757 60175.77306795546 42213.07192354373
- Output:
45.00000000000 - 20.00000000000 = 25.00000000000 45.00000000000 - -45.00000000000 = 90.00000000000 90.00000000000 - -85.00000000000 = 175.00000000000 90.00000000000 - -95.00000000000 = -175.00000000000 125.00000000000 - -45.00000000000 = 170.00000000000 145.00000000000 - -45.00000000000 = -170.00000000000 -88.63810000000 - 29.48030000000 = -118.11840000000 -159.03600000000 - -78.32510000000 = -80.71090000000 29840.67437876723 - -70099.74233810938 = -139.58328312339 33693.98945174560 - -165313.66662973570 = -72.34391851869 -154146.66490124760 - 1174.83805105985 = -161.50295230740 42213.07192354373 - 60175.77306795546 = 37.29885558827
PascalABC.NET
function delta(b1, b2: real): real;
begin
result := (b2 - b1) - Trunc((b2 - b1) / 360.0) * 360.0;
if result < -180.0 then result += 360.0
else if result >= 180.0 then result -= 360.0
end;
begin
var testVectors :=
|(20.00, 45.00), (-45.00, 45.00), (-85.00, 90.00),
(-95.00, 90.00), (-45.00, 125.00), (-45.00, 145.00),
(29.48, -88.64), (-78.33, -159.04), (-70099.74, 29840.67),
(-165313.67, 33693.99), (1174.84, -154146.66), (60175.77, 42213.07)|;
foreach var vector in testVectors do
writeln(vector[0]:10:2, vector[1]:12:2, delta(vector[0], vector[1]):10:2);
end.
Perl
Perl's built-in modulo is integer-only, so import a suitable one from the POSIX
core module
use POSIX 'fmod';
sub angle {
my($b1,$b2) = @_;
my $b = fmod( ($b2 - $b1 + 720) , 360);
$b -= 360 if $b > 180;
$b += 360 if $b < -180;
return $b;
}
@bearings = (
20, 45,
-45, 45,
-85, 90,
-95, 90,
-45, 125,
-45, 145,
29.4803, -88.6381,
-78.3251, -159.036,
-70099.74233810938, 29840.67437876723,
-165313.6666297357, 33693.9894517456,
1174.8380510598456, -154146.66490124757,
60175.77306795546, 42213.07192354373
);
while(my ($b1,$b2) = splice(@bearings,0,2)) {
printf "%10.2f %10.2f = %8.2f\n", $b1, $b2, angle($b1,$b2);
}
- Output:
20.00 45.00 = 25.00 -45.00 45.00 = 90.00 -85.00 90.00 = 175.00 -95.00 90.00 = -175.00 -45.00 125.00 = 170.00 -45.00 145.00 = -170.00 29.48 -88.64 = -118.12 -78.33 -159.04 = -80.71 -70099.74 29840.67 = -139.58 -165313.67 33693.99 = -72.34 1174.84 -154146.66 = -161.50 60175.77 42213.07 = 37.30
Phix
function tz(atom a) -- trim trailing zeroes and decimal point string res = sprintf("%16f",a) for i=length(res) to 1 by -1 do integer ch = res[i] if ch='0' or ch='.' then res[i] = ' ' end if if ch!='0' then exit end if end for return res end function procedure test(atom b1, b2) atom diff = mod(b2-b1,360) diff -= iff(diff>180?360:0) printf(1,"%s %s %s\n",{tz(b1),tz(b2),tz(diff)}) end procedure puts(1," b1 b2 diff\n") puts(1,"---------------- ---------------- ----------------\n") test(20,45) test(-45,45) test(-85,90) test(-95,90) test(-45,125) test(-45,145) test(29.4803,-88.6381) test(-78.3251,-159.036) test(-70099.74233810938,29840.67437876723) test(-165313.6666297357,33693.9894517456) test(1174.8380510598456,-154146.66490124757) test(60175.77306795546,42213.07192354373)
- Output:
b1 b2 diff ---------------- ---------------- ---------------- 20 45 25 -45 45 90 -85 90 175 -95 90 -175 -45 125 170 -45 145 -170 29.4803 -88.6381 -118.1184 -78.3251 -159.036 -80.7109 -70099.742338 29840.674379 -139.583283 -165313.66663 33693.989452 -72.343919 1174.838051 -154146.664901 -161.502952 60175.773068 42213.071924 37.298856
Phixmonti
include ..\Utilitys.pmt
( "16" 1 "16" 1 "16" ) var al
def difAngle /# b1 b2 -- diff #/
swap - 360 mod
dup 180 > if 360 - endif
enddef
def test /# b1 b2 -- #/
over over difAngle >ps swap " " rot " " ps> 5 tolist
al lalign ?
enddef
( "b1" " " "b2" " " "diff" ) al lalign ?
"---------------- ---------------- ----------------" ?
20 45 test
-45 45 test
-85 90 test
-95 90 test
-45 125 test
-45 145 test
29.4803 -88.6381 test
-78.3251 -159.036 test
-70099.74233810938 29840.67437876723 test
-165313.6666297357 33693.9894517456 test
1174.8380510598456 -154146.66490124757 test
60175.77306795546 42213.07192354373 test
- Output:
b1 b2 diff ---------------- ---------------- ---------------- 20 45 25 -45 45 90 -85 90 175 -95 90 -175 -45 125 170 -45 145 -170 29.4803 -88.638099999999 -118.11840000000 -78.325100000000 -159.03600000000 -80.710899999999 -70099.742338109 29840.6743787672 -139.58328312338 -165313.66662973 33693.9894517455 -72.343918518687 1174.83805105984 -154146.66490124 -161.50295230740 60175.7730679554 42213.0719235437 37.2988555882693 === Press any key to exit ===
PowerShell
This implementation takes two user inputs with Get-AngleDiff or prints the examples with Get-Examples. There is also a full help file accessed by typing Get-Help Get-AngleDiff -full
<#
.Synopsis
Gets the difference between two angles between the values of -180 and 180.
To see examples use "Get-Examples"
.DESCRIPTION
This code uses the modulo operator, this is represented with the "%".
The modulo operator returns the remainder after division, as displayed below
3 % 2 = 1
20 % 15 = 5
200 % 146 = 54
.EXAMPLE
PS C:\WINDOWS\system32> Get-AngleDiff
cmdlet Get-AngleDiff at command pipeline position 1
Supply values for the following parameters:
angle1: 45
angle2: -85
The difference between 45 and -85 is -130
PS C:\WINDOWS\system32>
.EXAMPLE
PS C:\WINDOWS\system32> Get-AngleDiff -angle1 50 -angle2 -65
The difference between 50 and -65 is -115
PS C:\WINDOWS\system32>
.EXAMPLE
PS C:\WINDOWS\system32> Get-AngleDiff -89 50
The difference between -89 and 50 is 139
PS C:\WINDOWS\system32>
#>
function Get-AngleDiff
{
[CmdletBinding()]
Param
(
# Angle one input, must be a number
[Parameter(Mandatory=$true,
ValueFromPipelineByPropertyName=$true)][double]$angle1,
# Angle two input, must be a number
[Parameter(Mandatory=$true,
ValueFromPipelineByPropertyName=$true)][double]$angle2
)
Begin
{
#This is the equation to calculate the difference
[double]$Difference = ($angle2 - $angle1) % 360.0
}
Process
{
#If/IfElse/Else block to return results within the requested range
if ($Difference -lt -180.0)
{$Difference += 360.0
}
elseif ($Difference -gt 360.0)
{$Difference -= 360.0
}
#Writes the values given by the user and the result
Write-Host "The difference between $angle1 and $angle2 is $Difference"
}
End
{
}
}
<#
.Synopsis
This is simply the outputs of the Get-AngleDiff Function in a function
.EXAMPLE
PS C:\WINDOWS\system32> Get-Examples
Inputs from the -180 to 180 range
The difference between 20 and 45 is 25
The difference between -45 and 45 is 90
The difference between -85 and 90 is 175
The difference between -95 and 90 is 185
The difference between -45 and 125 is 170
The difference between -45 and 145 is 190
The difference between -45 and 125 is 170
The difference between -45 and 145 is 190
The difference between 29.4803 and -88.6381 is -118.1184
The difference between -78.3251 and -159.036 is -80.7109
Inputs from a wider range
The difference between -70099.7423381094 and 29840.6743787672 is 220.416716876614
The difference between -165313.666629736 and 33693.9894517456 is 287.656081481313
The difference between 1174.83805105985 and -154146.664901248 is -161.502952307404
The difference between 60175.7730679555 and 42213.0719235437 is 37.2988555882694
PS C:\WINDOWS\system32>
#>
function Get-Examples
{
#blank write-host is used for a blank line to make the output look a lil cleaner
Write-Host
Write-Host "Inputs from the -180 to 180 range"
Get-AngleDiff 20.0 45.0
Get-AngleDiff -45.0 45.0
Get-AngleDiff -85.0 90.0
Get-AngleDiff -95.0 90.0
Get-AngleDiff -45.0 125.0
Get-AngleDiff -45.0 145.0
Get-AngleDiff -45.0 125.0
Get-AngleDiff -45.0 145.0
Get-AngleDiff 29.4803 -88.6381
Get-AngleDiff -78.3251 -159.036
Write-Host
Write-Host "Inputs from a wider range"
Get-AngleDiff -70099.74233810938 29840.67437876723
Get-AngleDiff -165313.6666297357 33693.9894517456
Get-AngleDiff 1174.8380510598456 -154146.66490124757
Get-AngleDiff 60175.77306795546 42213.07192354373
}
Results of user inputs
using -45 and 98 with Get-AngleDiff:
PS C:\WINDOWS\system32> Get-AngleDiff -45 98
The difference between -45 and 98 is 143
Results of Get-Examples
PS C:\WINDOWS\system32> Get-Examples Inputs from the -180 to 180 range The difference between 20 and 45 is 25 The difference between -45 and 45 is 90 The difference between -85 and 90 is 175 The difference between -95 and 90 is 185 The difference between -45 and 125 is 170 The difference between -45 and 145 is 190 The difference between -45 and 125 is 170 The difference between -45 and 145 is 190 The difference between 29.4803 and -88.6381 is -118.1184 The difference between -78.3251 and -159.036 is -80.7109 Inputs from a wider range The difference between -70099.7423381094 and 29840.6743787672 is 220.416716876614 The difference between -165313.666629736 and 33693.9894517456 is 287.656081481313 The difference between 1174.83805105985 and -154146.664901248 is -161.502952307404 The difference between 60175.7730679555 and 42213.0719235437 is 37.2988555882694
PureBasic
Procedure.f getDifference (b1.f, b2.f)
r.f = Mod((b2 - b1), 360)
If r >= 180: r - 360
EndIf
PrintN(StrF(b1) + #TAB$ + StrF(b2) + #TAB$ + StrF(r));
EndProcedure
If OpenConsole()
PrintN("Input in -180 to +180 range:")
getDifference(20.0, 45.0)
getDifference(-45.0, 45.0)
getDifference(-85.0, 90.0)
getDifference(-95.0, 90.0)
getDifference(-45.0, 125.0)
getDifference(-45.0, 145.0)
getDifference(-45.0, 125.0)
getDifference(-45.0, 145.0)
getDifference(29.4803, -88.6381)
getDifference(-78.3251, -159.036)
PrintN(#CRLF$ + "Input in wider range:")
getDifference(-70099.74233810938, 29840.67437876723)
getDifference(-165313.6666297357, 33693.9894517456)
getDifference(1174.8380510598456, -154146.66490124757)
getDifference(60175.77306795546, 42213.07192354373)
Repeat: Until Inkey() <> ""
EndIf
Python
from __future__ import print_function
def getDifference(b1, b2):
r = (b2 - b1) % 360.0
# Python modulus has same sign as divisor, which is positive here,
# so no need to consider negative case
if r >= 180.0:
r -= 360.0
return r
if __name__ == "__main__":
print ("Input in -180 to +180 range")
print (getDifference(20.0, 45.0))
print (getDifference(-45.0, 45.0))
print (getDifference(-85.0, 90.0))
print (getDifference(-95.0, 90.0))
print (getDifference(-45.0, 125.0))
print (getDifference(-45.0, 145.0))
print (getDifference(-45.0, 125.0))
print (getDifference(-45.0, 145.0))
print (getDifference(29.4803, -88.6381))
print (getDifference(-78.3251, -159.036))
print ("Input in wider range")
print (getDifference(-70099.74233810938, 29840.67437876723))
print (getDifference(-165313.6666297357, 33693.9894517456))
print (getDifference(1174.8380510598456, -154146.66490124757))
print (getDifference(60175.77306795546, 42213.07192354373))
- Output:
Input in -180 to +180 range 25.0 90.0 175.0 -175.0 170.0 -170.0 170.0 -170.0 -118.11840000000001 -80.71089999999998 Input in wider range -139.58328312338563 -72.34391851868713 -161.50295230740448 37.29885558826936
Or, generalising a little by deriving the degrees from a (Radians -> Radians) function, and formatting the output in columns:
'''Difference between two bearings'''
from math import (acos, cos, pi, sin)
# bearingDelta :: Radians -> Radians -> Radians
def bearingDelta(ar):
'''Difference between two bearings,
expressed in radians.'''
def go(br):
[(ax, ay), (bx, by)] = [
(sin(x), cos(x)) for x in [ar, br]
]
# cross-product > 0 ?
sign = +1 if 0 < ((ay * bx) - (by * ax)) else -1
# sign * dot-product
return sign * acos((ax * bx) + (ay * by))
return lambda br: go(br)
# TEST ----------------------------------------------------
# main :: IO ()
def main():
'''Test and display'''
# showMap :: Degrees -> Degrees -> String
def showMap(da, db):
return unwords(
str(x).rjust(n) for n, x in
[
(22, str(da) + ' +'),
(24, str(db) + ' -> '),
(7, round(
degrees(
bearingDelta
(radians(da))
(radians(db))
), 2)
)
]
)
print(__doc__ + ':')
print(
unlines(showMap(a, b) for a, b in [
(20, 45),
(-45, 45),
(-85, 90),
(-95, 90),
(-45, 125),
(-45, 145),
(-70099.74233810938, 29840.67437876723),
(-165313.6666297357, 33693.9894517456),
(1174.8380510598456, -154146.66490124757),
(60175.77306795546, 42213.07192354373)
]))
# GENERIC ----------------------------------------------
# radians :: Float x => Degrees x -> Radians x
def radians(x):
'''Radians derived from degrees.'''
return pi * x / 180
# degrees :: Float x => Radians x -> Degrees x
def degrees(x):
'''Degrees derived from radians.'''
return 180 * x / pi
# unlines :: [String] -> String
def unlines(xs):
'''A single newline-delimited string derived
from a list of strings.'''
return '\n'.join(xs)
# unwords :: [String] -> String
def unwords(xs):
'''A space-separated string derived from
a list of words.'''
return ' '.join(xs)
if __name__ == '__main__':
main()
- Output:
Difference between two bearings: 20 + 45 -> 25.0 -45 + 45 -> 90.0 -85 + 90 -> 175.0 -95 + 90 -> -175.0 -45 + 125 -> 170.0 -45 + 145 -> -170.0 -70099.74233810938 + 29840.67437876723 -> -139.58 -165313.6666297357 + 33693.9894517456 -> -72.34 1174.8380510598456 + -154146.66490124757 -> -161.5 60175.77306795546 + 42213.07192354373 -> 37.3
Hopefully a lot simpler, elegant and efficient by avoiding conditional statement and trigonometric functions
The table output use print formatting only available from python 3. Tested with 3.6.
"""
Difference between two bearings
"""
def delta_bearing(b1 , b2):
return ((b2-b1+540)%360)-180
dataSet = [[20, 45], [-45, 45], [-85, 90], [-95, 90], [-45, 125], [-45, 145], \
[29.4803, -88.6381], [-78.3251, -159.036], \
[-70099.74233810938, 29840.67437876723], \
[-165313.6666297357, 33693.9894517456], \
[1174.8380510598456, -154146.66490124757], \
[60175.77306795546, 42213.07192354373]]
print('.{:-^19}.{:-^19}.{:-^9}.' .format(" b1 ", " b2 ", " Δ b " ))
for Δ in dataSet:
print('|{: > 19}|{: > 19}|{: > 9.4f}|' .format(Δ[0], Δ[1],delta_bearing(Δ[0],Δ[1])))
- Output:
.------- b1 --------.------- b2 --------.-- Δ b --. | 20| 45| 25.0000| | -45| 45| 90.0000| | -85| 90| 175.0000| | -95| 90|-175.0000| | -45| 125| 170.0000| | -45| 145|-170.0000| | 29.4803| -88.6381|-118.1184| | -78.3251| -159.036| -80.7109| | -70099.74233810938| 29840.67437876723|-139.5833| | -165313.6666297357| 33693.9894517456| -72.3439| | 1174.8380510598456|-154146.66490124757|-161.5030| | 60175.77306795546| 42213.07192354373| 37.2989|
Quackery
Using the Quackery big number rational arithmetic library bigrat.qky
.
[ $ "bigrat.qky" loadfile ] now!
[ v- -v
proper rot
360 mod
unrot improper
180 1 2over v< iff
[ 360 1 v- ] done
2dup -180 1 v< if
[ 360 1 v+ ] ] is angledelta ( n/d n/d --> n/d )
' [ [ $ "20" $ "45" ]
[ $ "-45" $ "45" ]
[ $ "85" $ "90" ]
[ $ "-95" $ "90" ]
[ $ "-45" $ "125" ]
[ $ "45" $ "145" ]
[ $ "29.4803" $ "-88.6361" ]
[ $ "-78.3251" $ "-159.0360" ]
[ $ "-70099.74233810938" $ "29840.67437876723" ]
[ $ "-165313.6666297357" $ "33693.9894517456" ]
[ $ "1174.8380510598456" $ "-154146.66490124757" ]
[ $ "60175.773067955546" $ "42213.07192354373" ] ]
witheach
[ do
dip [ $->v drop ]
$->v drop
angledelta
20 point$ echo$ cr ]
- Output:
25 90 5 -175 170 100 -118.1164 -80.7109 -139.58328312339 -72.3439185187 -161.5029523074156 37.298855588184
Racket
see my comments in discussion regards bearing-heading or vice versa
#lang racket
(define (% a b) (- a (* b (truncate (/ a b)))))
(define (bearing- bearing heading)
(- (% (+ (% (- bearing heading) 360) 540) 360) 180))
(module+ main
(bearing- 20 45)
(bearing- -45 45)
(bearing- -85 90)
(bearing- -95 90)
(bearing- -45 125)
(bearing- -45 145)
(bearing- 29.4803 -88.6381)
(bearing- -78.3251 -159.036)
(bearing- -70099.74233810938 29840.67437876723)
(bearing- -165313.6666297357 33693.9894517456)
(bearing- 1174.8380510598456 -154146.66490124757)
(bearing- 60175.77306795546 42213.07192354373))
(module+ test
(require rackunit)
(check-equal? (% 7.5 10) 7.5)
(check-equal? (% 17.5 10) 7.5)
(check-equal? (% -7.5 10) -7.5)
(check-equal? (% -17.5 10) -7.5))
- Output:
-25 -90 -175 175 -170 170 118.11839999999995 80.71090000000004 139.58328312338563 72.34391851868713 161.50295230740448 -37.29885558826936
Raku
(formerly Perl 6)
sub infix:<∠> (Real $b1, Real $b2) {
(my $b = ($b2 - $b1 + 720) % 360) > 180 ?? $b - 360 !! $b;
}
for 20, 45,
-45, 45,
-85, 90,
-95, 90,
-45, 125,
-45, 145,
29.4803, -88.6381,
-78.3251, -159.036,
-70099.74233810938, 29840.67437876723,
-165313.6666297357, 33693.9894517456,
1174.8380510598456, -154146.66490124757,
60175.77306795546, 42213.07192354373
-> $b1, $b2 { printf "%10.2f %10.2f = %8.2f\n", $b1, $b2, $b1 ∠ $b2 }
- Output:
20.00 45.00 = 25.00 -45.00 45.00 = 90.00 -85.00 90.00 = 175.00 -95.00 90.00 = -175.00 -45.00 125.00 = 170.00 -45.00 145.00 = -170.00 29.48 -88.64 = -118.12 -78.33 -159.04 = -80.71 -70099.74 29840.67 = -139.58 -165313.67 33693.99 = -72.34 1174.84 -154146.66 = -161.50 60175.77 42213.07 = 37.30
REXX
Some extra coding was added for a better visual presentation; the angles were centered, the answers were aligned.
/*REXX pgm calculates difference between two angles (in degrees), normalizes the result.*/
numeric digits 25 /*use enough dec. digits for angles*/
call show 20, 45 /*display angular difference (deg).*/
call show -45, 45 /* " " " " */
call show -85, 90 /* " " " " */
call show -95, 90 /* " " " " */
call show -45, 125 /* " " " " */
call show 45, 145 /* " " " " */
call show 29.4803, -88.6361 /* " " " " */
call show -78.3251, -159.036 /* " " " " */
call show -70099.74233810938, 29840.67437876723 /* " " " " */
call show -165313.6666297357, 33693.9894517456 /* " " " " */
call show 1174.8380510598456, -154146.66490124757 /* " " " " */
call show 60175.773067955546, 42213.07192354373 /* " " " " */
exit /*stick a fork in it, we're done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
show: parse arg a,b; d=digits(); $='º' /*obtain the 2 angles (are in degrees).*/
x=format( ( ( ((b-a) // 360) + 540) // 360) - 180, 4, d) /*compute and format. */
if pos(., x)\==0 then x=strip( strip(x, 'T', 0), "T", .) /*strip trailing chaff.*/
say center(a || $, d) '─' center(b || $, d) " ────► " x || $
return /* [↑] display the angular difference.*/
- output:
20º ─ 45º ────► 25º -45º ─ 45º ────► 90º -85º ─ 90º ────► 175º -95º ─ 90º ────► -175º -45º ─ 125º ────► 170º 45º ─ 145º ────► 100º 29.4803º ─ -88.6361º ────► -118.1164º -78.3251º ─ -159.036º ────► -80.7109º -70099.74233810938º ─ 29840.67437876723º ────► -139.58328312339º -165313.6666297357º ─ 33693.9894517456º ────► -72.3439185187º 1174.8380510598456º ─ -154146.66490124757º ────► -161.5029523074156º 60175.773067955546º ─ 42213.07192354373º ────► 37.298855588184º
Ring
# Project : Angle difference between two bearings
decimals(4)
see "Input in -180 to +180 range:" + nl
see getDifference(20.0, 45.0) + nl
see getDifference(-45.0, 45.0) + nl
see getDifference(-85.0, 90.0) + nl
see getDifference(-95.0, 90.0) + nl
see getDifference(-45.0, 125.0) + nl
see getDifference(-45.0, 145.0) + nl
see getDifference(-45.0, 125.0) + nl
see getDifference(-45.0, 145.0) + nl
see getDifference(29.4803, -88.6381) + nl
see getDifference(-78.3251, -159.036) + nl
func getDifference(b1, b2)
r = (b2 - b1) % 360.0
if r >= 180.0
r = r - 360.0
end
return r
Output:
Input in -180 to +180 range: 25 90 175 -175 170 -170 170 -170 -118.1184 -80.7109
RPL
≪ SWAP - 360 MOD IF DUP 180 > THEN 360 - END ≫ 'BDIFF' STO
- Input:
20 45 BDIFF -45 45 BDIFF -85 90 BDIFF -95 90 BDIFF -45 125 BDIFF -45 145 BDIFF 29.4803 -88.6381 BDIFF -78.3251 -159.036 BDIFF
- Output:
8: 25 7: 90 6 175 5: -175 4: 170 3: -170 2: -118.1184 1: -80.7109
Ruby
def getDifference(b1, b2)
r = (b2 - b1) % 360.0
# Ruby modulus has same sign as divisor, which is positive here,
# so no need to consider negative case
if r >= 180.0
r -= 360.0
end
return r
end
if __FILE__ == $PROGRAM_NAME
puts "Input in -180 to +180 range"
puts getDifference(20.0, 45.0)
puts getDifference(-45.0, 45.0)
puts getDifference(-85.0, 90.0)
puts getDifference(-95.0, 90.0)
puts getDifference(-45.0, 125.0)
puts getDifference(-45.0, 145.0)
puts getDifference(-45.0, 125.0)
puts getDifference(-45.0, 145.0)
puts getDifference(29.4803, -88.6381)
puts getDifference(-78.3251, -159.036)
puts "Input in wider range"
puts getDifference(-70099.74233810938, 29840.67437876723)
puts getDifference(-165313.6666297357, 33693.9894517456)
puts getDifference(1174.8380510598456, -154146.66490124757)
puts getDifference(60175.77306795546, 42213.07192354373)
end
- Output:
Input in -180 to +180 range 25.0 90.0 175.0 -175.0 170.0 -170.0 170.0 -170.0 -118.11840000000001 -80.71089999999998 Input in wider range -139.58328312338563 -72.34391851868713 -161.50295230740448 37.29885558826936
Run BASIC
sub getDifference b1, b2
r = (b2 - b1) mod 360
if r >= 180 then r = r - 360
print r
end sub
print "Input in -180 to +180 range:"
call getDifference 20, 45
call getDifference -45, 45
call getDifference -85, 90
call getDifference -95, 90
call getDifference -45, 125
call getDifference -45, 145
call getDifference -45, 125
call getDifference -45, 145
call getDifference 29.4803, -88.6381
call getDifference -78.3251, -159.036
print "Input in wider range:"
call getDifference -70099.74233810938, 29840.67437876723
call getDifference -165313.6666297357, 33693.9894517456
call getDifference 1174.8380510598456, -154146.66490124757
Rust
/// Calculate difference between two bearings, in -180 to 180 degrees range
pub fn angle_difference(bearing1: f64, bearing2: f64) -> f64 {
let diff = (bearing2 - bearing1) % 360.0;
if diff < -180.0 {
360.0 + diff
} else if diff > 180.0 {
-360.0 + diff
} else {
diff
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_angle_difference() {
assert_eq!(25.00, angle_difference(20.00, 45.00));
assert_eq!(90.00, angle_difference(-45.00, 45.00));
assert_eq!(175.00, angle_difference(-85.00, 90.00));
assert_eq!(-175.00, angle_difference(-95.00, 90.00));
assert_eq!(170.00, angle_difference(-45.00, 125.00));
assert_eq!(-170.00, angle_difference(-45.00, 145.00));
approx_eq(-118.1184, angle_difference(29.4803, -88.6381));
approx_eq(-80.7109, angle_difference(-78.3251 , -159.036));
approx_eq(-139.5832, angle_difference(-70099.74233810938, 29840.67437876723));
approx_eq(-72.3439, angle_difference(-165313.6666297357, 33693.9894517456));
approx_eq(-161.5029, angle_difference(1174.8380510598456, -154146.66490124757));
approx_eq(37.2988, angle_difference(60175.77306795546, 42213.07192354373));
}
// approximate equality on floats.
// see also https://crates.io/crates/float-cmp
fn approx_eq(f1: f64, f2: f64) {
assert!((f2-f1).abs() < 0.0001, "{} != {}", f1, f2)
}
}
Scala
- Output:
Best seen running in your browser either by ScalaFiddle (ES aka JavaScript, non JVM) or Scastie (remote JVM).
object AngleDifference extends App {
private def getDifference(b1: Double, b2: Double) = {
val r = (b2 - b1) % 360.0
if (r < -180.0) r + 360.0 else if (r >= 180.0) r - 360.0 else r
}
println("Input in -180 to +180 range")
println(getDifference(20.0, 45.0))
println(getDifference(-45.0, 45.0))
println(getDifference(-85.0, 90.0))
println(getDifference(-95.0, 90.0))
println(getDifference(-45.0, 125.0))
println(getDifference(-45.0, 145.0))
println(getDifference(-45.0, 125.0))
println(getDifference(-45.0, 145.0))
println(getDifference(29.4803, -88.6381))
println(getDifference(-78.3251, -159.036))
println("Input in wider range")
println(getDifference(-70099.74233810938, 29840.67437876723))
println(getDifference(-165313.6666297357, 33693.9894517456))
println(getDifference(1174.8380510598456, -154146.66490124757))
println(getDifference(60175.77306795546, 42213.07192354373))
}
Scheme
R6RS standard.
#!r6rs
(import (rnrs base (6))
(rnrs io simple (6)))
(define (bearing-difference bearing-2 bearing-1)
(- (mod (+ (mod (- bearing-2 bearing-1)
360)
540)
360)
180))
(define (bearing-difference-test)
(define test-cases
'((20 45)
(-45 45)
(-85 90)
(-95 90)
(-45 125)
(-45 145)
(29.4803 -88.6381)
(-78.3251 -159.036)
(-70099.74233810938 29840.67437876723)
(-165313.6666297357 33693.9894517456)
(1174.8380510598456 -154146.66490124757)
(60175.77306795546 42213.07192354373)))
(for-each
(lambda (argument-list)
(display (apply bearing-difference argument-list))
(newline))
test-cases))
- Output:
> (bearing-difference-test) -25 -90 -175 175 -170 170 118.11839999999995 80.71090000000004 139.58328312338563 72.34391851868713 161.50295230740448 -37.29885558826936
Seed7
The library float.s7i supports the operator mod, which can be used to solve this task easily.
$ include "seed7_05.s7i";
include "float.s7i";
const func float: getDifference (in float: b1, in float: b2) is func
result
var float: difference is 0.0;
begin
difference := (b2 - b1) mod 360.0;
if difference > 180.0 then
difference -:= 360.0;
end if;
end func;
const proc: main is func
begin
writeln("Input in -180 to +180 range");
writeln(getDifference(20.0, 45.0));
writeln(getDifference(-45.0, 45.0));
writeln(getDifference(-85.0, 90.0));
writeln(getDifference(-95.0, 90.0));
writeln(getDifference(-45.0, 125.0));
writeln(getDifference(-45.0, 145.0));
writeln(getDifference(-45.0, 125.0));
writeln(getDifference(-45.0, 145.0));
writeln(getDifference(29.4803, -88.6381));
writeln(getDifference(-78.3251, -159.036));
writeln("Input in wider range");
writeln(getDifference(-70099.74233810938, 29840.67437876723));
writeln(getDifference(-165313.6666297357, 33693.9894517456));
writeln(getDifference(1174.8380510598456, -154146.66490124757));
writeln(getDifference(60175.77306795546, 42213.07192354373));
end func;
- Output:
Input in -180 to +180 range 25.0 90.0 175.0 -175.0 170.0 -170.0 170.0 -170.0 -118.1184 -80.7109 Input in wider range -139.583283123386 -72.3439185186871 -161.502952307404 37.2988555882694
Sidef
func bearingAngleDiff(b1, b2) {
(var b = ((b2 - b1 + 720) % 360)) > 180 ? (b - 360) : b
}
printf("%25s %25s %25s\n", "B1", "B2", "Difference")
printf("%25s %25s %25s\n", "-"*20, "-"*20, "-"*20)
for b1,b2 in ([
20, 45
-45, 45
-85, 90
-95, 90
-45, 125
-45, 145
29.4803, -88.6381
-78.3251, -159.036
-70099.74233810938, 29840.67437876723
-165313.6666297357, 33693.9894517456
1174.8380510598456, -154146.66490124757
60175.77306795546, 42213.07192354373
].slices(2)
) {
printf("%25s %25s %25s\n", b1, b2, bearingAngleDiff(b1, b2))
}
- Output:
B1 B2 Difference -------------------- -------------------- -------------------- 20 45 25 -45 45 90 -85 90 175 -95 90 -175 -45 125 170 -45 145 -170 29.4803 -88.6381 -118.1184 -78.3251 -159.036 -80.7109 -70099.74233810938 29840.67437876723 -139.58328312339 -165313.6666297357 33693.9894517456 -72.3439185187 1174.8380510598456 -154146.66490124757 -161.5029523074156 60175.77306795546 42213.07192354373 37.29885558827
Swift
func angleDifference(a1: Double, a2: Double) -> Double {
let diff = (a2 - a1).truncatingRemainder(dividingBy: 360)
if diff < -180.0 {
return 360.0 + diff
} else if diff > 180.0 {
return -360.0 + diff
} else {
return diff
}
}
let testCases = [
(20.0, 45.0),
(-45, 45),
(-85, 90),
(-95, 90),
(-45, 125),
(-45, 145),
(29.4803, -88.6381),
(-78.3251, -159.036),
(-70099.74233810938, 29840.67437876723),
(-165313.6666297357, 33693.9894517456),
(1174.8380510598456, -154146.66490124757),
(60175.77306795546, 42213.07192354373)
]
print(testCases.map(angleDifference))
- Output:
[25.0, 90.0, 175.0, -175.0, 170.0, -170.0, -118.1184, -80.7109, -139.58328312338563, -72.34391851868713, -161.50295230740448, 37.29885558826936]
Tcl
proc angleDiff {b1 b2} {
set angle [::tcl::mathfunc::fmod [expr ($b2 - $b1)] 360]
if {$angle < -180.0} {
set angle [expr $angle + 360.0]
}
if {$angle >= 180.0} {
set angle [expr $angle - 360.0]
}
return $angle
}
puts "Input in -180 to +180 range"
puts [angleDiff 20.0 45.0]
puts [angleDiff -45.0 45.0]
puts [angleDiff -85.0 90.0]
puts [angleDiff -95.0 90.0]
puts [angleDiff -45.0 125.0]
puts [angleDiff -45.0 145.0]
puts [angleDiff -45.0 125.0]
puts [angleDiff -45.0 145.0]
puts [angleDiff 29.4803 -88.6381]
puts [angleDiff -78.3251 -159.036]
puts "Input in wider range"
puts [angleDiff -70099.74233810938 29840.67437876723]
puts [angleDiff -165313.6666297357 33693.9894517456]
puts [angleDiff 1174.8380510598456 -154146.66490124757]
puts [angleDiff 60175.77306795546 42213.07192354373]
- Output:
Input in -180 to +180 range 25.0 90.0 175.0 -175.0 170.0 -170.0 170.0 -170.0 -118.1184 -80.7109 Input in wider range -139.58328312338563 -72.34391851868713 -161.50295230740448 37.29885558826936
VBA
Private Function tx(a As Variant) As String
Dim s As String
s = CStr(Format(a, "0.######"))
If Right(s, 1) = "," Then
s = Mid(s, 1, Len(s) - 1) & " "
Else
i = InStr(1, s, ",")
s = s & String$(6 - Len(s) + i, " ")
End If
tx = s
End Function
Private Sub test(b1 As Variant, b2 As Variant)
Dim diff As Variant
diff = (b2 - b1) - ((b2 - b1) \ 360) * 360
diff = diff - IIf(diff > 180, 360, 0)
diff = diff + IIf(diff < -180, 360, 0)
Debug.Print Format(tx(b1), "@@@@@@@@@@@@@@@@"); Format(tx(b2), "@@@@@@@@@@@@@@@@@"); Format(tx(diff), "@@@@@@@@@@@@@@@@@")
End Sub
Public Sub angle_difference()
Debug.Print " b1 b2 diff"
Debug.Print "---------------- ---------------- ----------------"
test 20, 45
test -45, 45
test -85, 90
test -95, 90
test -45, 125
test -45, 145
test 29.4803, -88.6381
test -78.3251, -159.036
test -70099.7423381094, 29840.6743787672
test -165313.666629736, 33693.9894517456
test 1174.83805105985, -154146.664901248
test 60175.7730679555, 42213.0719235437
End Sub
- Output:
b1 b2 diff ---------------- ---------------- ---------------- 20 45 25 -45 45 90 -85 90 175 -95 90 -175 -45 125 170 -45 145 -170 29,4803 -88,6381 -118,1184 -78,3251 -159,036 -80,7109 -70099,742338 29840,674379 -139,583283 -165313,66663 33693,989452 -72,343919 1174,838051 -154146,664901 -161,502952 60175,773068 42213,071924 37,298856
Visual Basic .NET
Module Module1
Function Delta_Bearing(b1 As Decimal, b2 As Decimal) As Decimal
Dim d As Decimal = 0
' Convert bearing to W.C.B
While b1 < 0
b1 += 360
End While
While b1 > 360
b1 -= 360
End While
While b2 < 0
b2 += 360
End While
While b2 > 0
b2 -= 360
End While
' Calculate delta bearing
d = (b2 - b1) Mod 360
' Convert result to Q.B
If d > 180 Then
d -= 360
ElseIf d < -180 Then
d += 360
End If
Return d
End Function
Sub Main()
' Calculate standard test cases
Console.WriteLine(Delta_Bearing(20, 45))
Console.WriteLine(Delta_Bearing(-45, 45))
Console.WriteLine(Delta_Bearing(-85, 90))
Console.WriteLine(Delta_Bearing(-95, 90))
Console.WriteLine(Delta_Bearing(-45, 125))
Console.WriteLine(Delta_Bearing(-45, 145))
Console.WriteLine(Delta_Bearing(29.4803, -88.6381))
Console.WriteLine(Delta_Bearing(-78.3251, -159.036))
' Calculate optional test cases
Console.WriteLine(Delta_Bearing(-70099.742338109383, 29840.674378767231))
Console.WriteLine(Delta_Bearing(-165313.6666297357, 33693.9894517456))
Console.WriteLine(Delta_Bearing(1174.8380510598456, -154146.66490124757))
Console.WriteLine(Delta_Bearing(60175.773067955459, 42213.071923543728))
End Sub
End Module
- Output:
25 90 175 -175 170 -170 -118.1184 -80.7109 -139.5832831234 -72.3439185184 -161.50295230785 37.2988555882
V (Vlang)
import math
type Bearing = f64
const test_cases = [
[Bearing(20), 45],
[Bearing(-45), 45],
[Bearing(-85), 90],
[Bearing(-95), 90],
[Bearing(-45), 125],
[Bearing(-45), 145],
[Bearing(29.4803), -88.6381],
[Bearing(-78.3251), -159.036],
]
fn main() {
for tc in test_cases {
println(tc[1].sub(tc[0]))
println(angle_difference(tc[1],tc[0]))
}
}
fn (b2 Bearing) sub(b1 Bearing) Bearing {
d := b2 - b1
match true {
d < -180 {
return d + 360
}
d > 180 {
return d - 360
}
else {
return d
}
}
}
fn angle_difference(b2 Bearing, b1 Bearing) Bearing {
return math.mod(math.mod(b2-b1, 360)+360+180, 360) - 180
}
- Output:
25. 25. 90 90 175. 175. -175. -175. 170 170 -170 -170 -118.1184 -118.11840000000001 -80.7109 -80.71089999999998
Wren
var subtract = Fn.new { |b1, b2|
var d = (b2 - b1) % 360
if (d < -180) d = d + 360
if (d >= 180) d = d - 360
return (d * 10000).round / 10000 // to 4dp
}
var pairs = [
[ 20, 45],
[-45, 45],
[-85, 90],
[-95, 90],
[-45, 125],
[-45, 145],
[ 29.4803, -88.6381],
[-78.3251, -159.036],
[-70099.74233810938, 29840.67437876723],
[-165313.6666297357, 33693.9894517456],
[1174.8380510598456, -154146.66490124757],
[60175.77306795546, 42213.07192354373]
]
System.print("Differences (to 4dp) between these bearings:")
for (pair in pairs) {
var p0 = pair[0]
var p1 = pair[1]
var diff = subtract.call(p0, p1)
var offset = (p0 < 0) ? " " : " "
System.print("%(offset)%(p0) and %(p1) -> %(diff)")
}
- Output:
Differences (to 4dp) between these bearings: 20 and 45 -> 25 -45 and 45 -> 90 -85 and 90 -> 175 -95 and 90 -> -175 -45 and 125 -> 170 -45 and 145 -> -170 29.4803 and -88.6381 -> -118.1184 -78.3251 and -159.036 -> -80.7109 -70099.742338109 and 29840.674378767 -> -139.5833 -165313.66662974 and 33693.989451746 -> -72.3439 1174.8380510598 and -154146.66490125 -> -161.503 60175.773067955 and 42213.071923544 -> 37.2989
XBS
settype Bearing = {Angle:number}
class Bearing {
private method construct(Angle:number=0)
self.Angle=(((Angle%360)+540)%360)-180;
method ToString():string
send tostring(math.nround(self.Angle,4))+"°";
private method __sub(b2:Bearing):Bearing{
send new Bearing(self.Angle-b2.Angle);
}
}
const BearingAngles:[[number]] = [
[20,45],
[-45,45],
[-85,90],
[-95,90],
[-45,125],
[-45,145],
[29.4803,-88.6381],
[-78.3251,-159.036],
[-70099.74233810938,29840.67437876723],
[-165313.6666297357,33693.9894517456],
[1174.8380510598456,-154146.66490124757],
[60175.77306795546,42213.07192354373]
];
foreach(v of BearingAngles){
set b1:Bearing=new Bearing(v[0]);
set b2:Bearing=new Bearing(v[1]);
log(b2::ToString()+" - "+b1::ToString()+" = "+(b2-b1)::ToString());
}
- Output:
45° - 20° = 25° 45° - -45° = 90° 90° - -85° = 175° 90° - -95° = -175° 125° - -45° = 170° 145° - -45° = -170° -88.6381° - 29.4803° = -118.1184° -159.036° - -78.3251° = -80.7109° -39.3256° - 100.2577° = -139.5833° -146.0105° - -73.6666° = -72.3439° -66.6649° - 94.8381° = -161.503° 93.0719° - 55.7731° = 37.2989°
XPL0
Pairs of bearing angles are input from the console or from a file (terminated with Ctrl+C) redirected on the command line.
real B1, B2, Ang;
[Text(0, " Bearing 1 Bearing 2 Difference");
loop [B1:= RlIn(1);
B2:= RlIn(1);
Ang:= B2 - B1;
while Ang > 180. do Ang:= Ang - 360.;
while Ang < -180. do Ang:= Ang + 360.;
CrLf(0);
RlOut(0, B1); ChOut(0, 9);
RlOut(0, B2); ChOut(0, 9);
RlOut(0, Ang);
];
]
- Output:
Bearing 1 Bearing 2 Difference 20.00000 45.00000 25.00000 -45.00000 45.00000 90.00000 -85.00000 90.00000 175.00000 -95.00000 90.00000 -175.00000 -45.00000 125.00000 170.00000 -45.00000 145.00000 -170.00000 29.48030 -88.63810 -118.11840 -78.32510 -159.03600 -80.71090 -70099.74234 29840.67438 -139.58328 -165313.66663 33693.98945 -72.34392 1174.83805 -154146.66490 -161.50295 60175.77307 42213.07192 37.29886
Yabasic
// Rosetta Code problem: http://rosettacode.org/wiki/Angle_difference_between_two_bearings
// by Jjuanhdez, 06/2022
print "Input in -180 to +180 range:"
getDifference(20.0, 45.0)
getDifference(-45.0, 45.0)
getDifference(-85.0, 90.0)
getDifference(-95.0, 90.0)
getDifference(-45.0, 125.0)
getDifference(-45.0, 145.0)
getDifference(-45.0, 125.0)
getDifference(-45.0, 145.0)
getDifference(29.4803, -88.6381)
getDifference(-78.3251, -159.036)
print "\nInput in wider range:"
getDifference(-70099.74233810938, 29840.67437876723)
getDifference(-165313.6666297357, 33693.9894517456)
getDifference(1174.8380510598456, -154146.66490124757)
end
sub getDifference(b1, b2)
r = mod((b2 - b1), 360.0)
if r >= 180.0 r = r - 360.0
print r
end sub
zkl
fcn bearingAngleDiff(b1,b2){ // -->Float, b1,b2 can be int or float
( (b:=(0.0 + b2 - b1 + 720)%360) > 180 ) and b - 360 or b;
}
T( 20,45, -45,45, -85,90, -95,90, -45,125, -45,145 )
.pump(Console.println,Void.Read,
fcn(b1,b2){ "%.1f\UB0; + %.1f\UB0; = %.1f\UB0;"
.fmt(b1,b2,bearingAngleDiff(b1,b2)) });
- Output:
20.0° + 45.0° = 25.0° -45.0° + 45.0° = 90.0° -85.0° + 90.0° = 175.0° -95.0° + 90.0° = -175.0° -45.0° + 125.0° = 170.0° -45.0° + 145.0° = -170.0°
References
- Geometry
- Programming Tasks
- Solutions by Programming Task
- 11l
- 360 Assembly
- AArch64 Assembly
- Action!
- Action! Tool Kit
- Action! Real Math
- Ada
- ALGOL 68
- APL
- ARM Assembly
- Arturo
- AutoHotkey
- AWK
- BASIC
- Chipmunk Basic
- QBasic
- True BASIC
- BASIC256
- Befunge
- BQN
- C
- C sharp
- C++
- Clojure
- COBOL
- Common Lisp
- Craft Basic
- D
- Delphi
- EasyLang
- Erlang
- Excel
- F Sharp
- Factor
- Forth
- Fortran
- FreeBASIC
- FutureBasic
- Go
- Groovy
- Haskell
- IS-BASIC
- J
- Java
- JavaScript
- Jsish
- Jq
- Julia
- K
- Klingphix
- Kotlin
- Lua
- Maple
- Mathematica
- Wolfram Language
- Modula-2
- NewLISP
- Nim
- Nutt
- Objeck
- OCaml
- PARI/GP
- Pascal
- PascalABC.NET
- Perl
- Phix
- Phixmonti
- PowerShell
- PureBasic
- Python
- Quackery
- Racket
- Raku
- REXX
- Ring
- RPL
- Ruby
- Run BASIC
- Rust
- Scala
- Scheme
- Seed7
- Sidef
- Swift
- Tcl
- VBA
- Visual Basic .NET
- V (Vlang)
- Wren
- XBS
- XPL0
- Yabasic
- Zkl