Angle difference between two bearings

Revision as of 13:53, 28 June 2022 by rosettacode>VincentArm (add task to aarch64 assembly raspberry pi)

Finding the angle between two bearings is often confusing.[1]

Task
Angle difference between two bearings
You are encouraged to solve this task according to the task description, using any language you may know.


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

<lang 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))</lang>

Output:
25
90
175
-175
170
-170
170
-170
-118.118
-80.7109

-139.583
-72.3439
-161.503
37.2989

360 Assembly

Translation of: Rexx

<lang 360asm>* 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</lang>
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

Works with: as version Raspberry Pi 3B version Buster 64 bits
or android 64 bits with application Termux

<lang 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" </lang>

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!

<lang 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</lang>

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. <lang Ada>


-- 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; </lang>

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

APL

Returns an angle in (-180,180]; so two opposite bearings have a difference of 180 degrees, which is more natural than -180 degrees. <lang APL>[0] D←B1 DIFF B2 [1] D←180+¯360|180+B2-B1 </lang>

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

Works with: as version Raspberry Pi
or android 32 bits with application Termux

<lang 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" </lang>

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

Translation of: Ruby

<lang rebol>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</lang>

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

<lang 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

}</lang>

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

<lang AWK>

  1. 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)

} </lang>

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

QBasic

Works with: QBasic version 1.1
Works with: QuickBasic version 4.5

<lang 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#)</lang>

True BASIC

<lang qbasic>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</lang>

BASIC256

Translation of: Python

<lang BASIC256># Rosetta Code problem: http://rosettacode.org/wiki/Angle_difference_between_two_bearings

  1. 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</lang>

Befunge

<lang 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<                              >                      ^

</lang> 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

C

This implementation either reads two bearings from the console or a file containing a list of bearings. Usage printed on incorrect invocation. <lang C>

  1. include<stdlib.h>
  2. include<stdio.h>
  3. 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; } </lang> 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#

<lang csharp>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;

// // // } } }</lang>

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++

<lang cpp>#include <cmath>

  1. 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; }</lang>

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

<lang 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 </lang>

COBOL

<lang 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
     ******************************************************************

</lang>

Common Lisp

<lang 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)))) </lang>

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

D

Translation of: Java

<lang 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));

}</lang>

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.

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. <lang Erlang> -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.

</lang>

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)

<lang lisp>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))
   )

)</lang>

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#

<lang fsharp>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</lang>
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

Translation of: F#
Works with: Factor version 0.99 development release 2019-03-17

<lang 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</lang>

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. <lang forth>

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. 

</lang>

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. <lang Fortran> 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</lang>

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

<lang freebasic>' version 28-01-2019 ' compile with: fbc -s console

  1. 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</lang>

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

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. <lang go>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
   }

}</lang>

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. <lang go>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

}</lang>

Output:
25
90
175
-175
170
-170
-118.11840000000001
-80.71089999999998
-139.58328312338563
-72.34391851868713
-161.50295230740448
37.29885558826936

Groovy

Solution A:

Translation of: C++

<lang groovy>def angleDifferenceA(double b1, double b2) {

   r = (b2 - b1) % 360.0
   (r > 180.0    ? r - 360.0
   : r <= -180.0 ? r + 360.0
                 : r)

}</lang>

Solution B:
In the spirit of the Fortran "Why branch when you can math?" solution, but without all the messy trigonometry. <lang groovy>def angleDifferenceB(double b1, double b2) {

   ((b2 - b1) % 360.0 - 540.0) % 360.0 + 180.0

}</lang> 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: <lang groovy>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))

}</lang>

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

<lang 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 *)</lang>

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

<lang 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</lang>

J

<lang j>relativeBearing=: (180 -~ 360 | 180 + -~)/"1</lang> <lang j>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 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</lang>

Java

Translation of: C++

<lang 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));
   }

}</lang>

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.

<lang javascript>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";

}</lang>

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

<lang JavaScript>(() => {

   "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();

})();</lang>

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

<lang javascript>/* 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!

  • /</lang>
Output:
prompt$ jsish -u angleDifference.jsi
[PASS] angleDifference.jsi

jq

Works with: jq

Works with gojq, the Go implementation of jq

Note that the `%` operator in jq produces integral results. <lang jq># 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)" )</lang>
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

Translation of: Python

<lang 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</lang>

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

<lang 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} </lang>

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

Translation of: NewLISP

<lang 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</lang>

Output:
(-25, -90, -175, 175, -170, 170, 118.118, 80.7109, 139.583, 72.3439, 161.503, -37.2989)

Kotlin

<lang scala>// 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))
   }

}</lang>

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.

<lang lua>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()</lang>

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

Translation of: C++

<lang 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)</lang>

Output:
25
90
175
-175
170
-170
-118.1184
-80.7109
-139.58328
-72.3340
-161.5030
37.29885


Mathematica/Wolfram Language

<lang Mathematica>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]</lang>

Output:
25
90
175
-175
170
-170
-118.118
-80.7109
-139.583
-72.3439
-161.503
37.2989

Modula-2

Translation of: Java

<lang modula2>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.</lang>

NewLISP

Taken from Racket solution

<lang lisp>

  1. !/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)) </lang>

Output:
-25
-90
-175
175
-170
170
118.11839999999995
80.71090000000004
139.58328312338563
72.34391851868713
161.50295230740448
-37.29885558826936

Nim

<lang 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)

</lang>

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

Objeck

Translation of: Java

<lang 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;
  }

}</lang>

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

Translation of: D

<lang 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);
</lang>
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

<lang parigp>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]])</lang>

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.

<lang Pascal> 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. </lang>

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

Perl

Perl's built-in modulo is integer-only, so import a suitable one from the POSIX core module <lang perl>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);

} </lang>

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

<lang 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</lang>

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 <lang PowerShell> <# .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> 


  1. >

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>

  1. >

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


}</lang>

Results of user inputs
using -45 and 98 with Get-AngleDiff: <lang PowerShell>PS C:\WINDOWS\system32> Get-AngleDiff -45 98 The difference between -45 and 98 is 143</lang>

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

Translation of: Python

<lang 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</lang>

Python

Translation of: C++

<lang 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))</lang>

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:

Works with: Python version 3.7

<lang python>Difference between two bearings

from math import (acos, cos, pi, sin)


  1. 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)


  1. TEST ----------------------------------------------------
  2. 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)
       ]))


  1. GENERIC ----------------------------------------------


  1. radians :: Float x => Degrees x -> Radians x

def radians(x):

   Radians derived from degrees.
   return pi * x / 180


  1. degrees :: Float x => Radians x -> Degrees x

def degrees(x):

   Degrees derived from radians.
   return 180 * x / pi


  1. unlines :: [String] -> String

def unlines(xs):

   A single newline-delimited string derived
      from a list of strings.
   return '\n'.join(xs)


  1. unwords :: [String] -> String

def unwords(xs):

   A space-separated string derived from
      a list of words.
   return ' '.join(xs)


if __name__ == '__main__':

   main()</lang>
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.

Works with: Python version 3.6

<lang python>""" 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])))</lang>

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.

<lang Quackery> [ $ "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 ]</lang>
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>#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))</lang>
Output:
-25
-90
-175
175
-170
170
118.11839999999995
80.71090000000004
139.58328312338563
72.34391851868713
161.50295230740448
-37.29885558826936

Raku

(formerly Perl 6)

Works with: Rakudo version 2016.11

<lang perl6>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 }</lang>
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. <lang rexx>/*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.*/</lang>
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

<lang ring>

  1. 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

</lang> Output:

Input in -180 to +180 range:
25
90
175
-175
170
-170
170
-170
-118.1184
-80.7109

Ruby

Translation of: C++

<lang 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</lang>

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

<lang runbasic>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</lang>

Rust

<lang 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
   }

}

  1. [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)
   }

} </lang>

Scala

Output:

Best seen running in your browser either by ScalaFiddle (ES aka JavaScript, non JVM) or Scastie (remote JVM).

<lang Scala>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))

}</lang>

Scheme

R6RS standard. <lang scheme>#!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))</lang>
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.

<lang seed7>$ 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;</lang>
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

<lang ruby>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))

}</lang>

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

<lang 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))</lang>

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

<lang 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] </lang>

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

Translation of: Phix

<lang vb>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</lang>

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

Translation of: C#

<lang vbnet>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</lang>

Output:
25
90
175
-175
170
-170
-118.1184
-80.7109
-139.5832831234
-72.3439185184
-161.50295230785
37.2988555882

Vlang

Translation of: go

<lang 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

}</lang>

Output:
25.
25.
90
90
175.
175.
-175.
-175.
170
170
-170
-170
-118.1184
-118.11840000000001
-80.7109
-80.71089999999998

Wren

<lang ecmascript>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)")

}</lang>

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

<lang 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());

}</lang>

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. <lang XPL0>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);
      ];

]</lang>

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

Translation of: Python

<lang freebasic>// 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</lang>

zkl

Translation of: Raku

<lang 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;

}</lang> <lang zkl>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)) });</lang>
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