
Finding the angle between two bearings is often confusing.[1]
Find the angle which is the result of the subtractionb2 - b1, whereb1 andb2 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:
Allow the input bearings to be any (finite) value.
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))
2590175-175170-170170-170-118.118-80.7109-139.583-72.3439-161.50337.2989
* Angle difference between two bearings - 06/06/2018ANGLEDBB 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 savN DC F'8' number of pairsT 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
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
/* ARM assembly AARCH64 Raspberry PI 3B *//* program diffAngle64.s *//************************************//* Constantes *//************************************/.include "../includeConstantesARM64.inc" /*********************************//* Initialized data *//*********************************/.dataszCarriageReturn: .asciz "\n"szMessResult: .asciz "Difference between @ and @ = @ \n".align 8fB1: .double 0F20.0fB2: .double 0F45.0fB3: .double 0F-45.0fB4: .double 0F-85.0fB5: .double 90.0fB6: .double -95.0fB7: .double 125.0fB8: .double 145.0fB9: .double 0F29.4803 fB10: .double 0F-88.6381fB11: .double 0F-78.3251fB12: .double 0F-159.036fB13: .double 0F-70099.74233810938fB14: .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 testComputeAngle100: // standard end of the program mov x0, #0 // return code mov x8,EXIT svc #0 // perform the system callqAdrszCarriageReturn: .quad szCarriageReturnqAdrsZoneConv: .quad sZoneConv qAdrfB1: .quad fB1qAdrfB2: .quad fB2qAdrfB3: .quad fB3qAdrfB4: .quad fB4qAdrfB5: .quad fB5qAdrfB6: .quad fB6qAdrfB7: .quad fB7qAdrfB8: .quad fB8qAdrfB9: .quad fB9qAdrfB10: .quad fB10qAdrfB11: .quad fB11qAdrfB12: .quad fB12qAdrfB13: .quad fB13qAdrfB14: .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,#11: 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,#12: 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 - 3603: fcmp d0,d3 // compare difference and 180 ble 100f fsub d0,d4,d0 // > 180 calculate 360 - difference fneg d0,d0 // and negate b 100f2: // 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érence3: fneg d3,d3 // -180 fcmp d0,d3 // compare difference and -180 bge 100f fadd d0,d4,d0 // calculate 360 + différence100: 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 100f2: 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 100f3: // 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 100f4: 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 zeros5: ldrb w0,[x6] cmp w0,#'0' bne 6f sub x6,x6,#1 b 5b6: cmp w0,#',' bne 7f sub x6,x6,#17: cmp x5,#0 // if exposant = 0 no display bne 8f add x6,x6,#1 b 10f8: 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,#19: mov x1,x6 bl conversion10 add x6,x6,x010: 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 final100: 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<<52dConst1: .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,#2561: ldr d1,dConstE128 fcmp d0,d1 blo 1f fdiv d0,d0,d1 adds x0,x0,#1281: ldr d1,dConstE64 fcmp d0,d1 blo 1f fdiv d0,d0,d1 adds x0,x0,#641: ldr d1,dConstE32 fcmp d0,d1 blo 1f fdiv d0,d0,d1 adds x0,x0,#321: ldr d1,dConstE16 fcmp d0,d1 blo 2f fdiv d0,d0,d1 adds x0,x0,#162: ldr d1,dConstE8 fcmp d0,d1 blo 3f fdiv d0,d0,d1 adds x0,x0,#83: ldr d1,dConstE4 fcmp d0,d1 blo 4f fdiv d0,d0,d1 adds x0,x0,#44: ldr d1,dConstE2 fcmp d0,d1 blo 5f fdiv d0,d0,d1 adds x0,x0,#25: ldr d1,dConstE1 fcmp d0,d1 blo 10f fdiv d0,d0,d1 adds x0,x0,#110: 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,#25611: ldr d1,dConstME127 fcmp d0,d1 bhi 11f ldr d1,dConstE128 fmul d0,d0,d1 subs x0,x0,#12811: ldr d1,dConstME63 fcmp d0,d1 bhi 11f ldr d1,dConstE64 fmul d0,d0,d1 subs x0,x0,#6411: ldr d1,dConstME31 fcmp d0,d1 bhi 11f ldr d1,dConstE32 fmul d0,d0,d1 subs x0,x0,#3211: ldr d1,dConstME15 fcmp d0,d1 bhi 12f ldr d1,dConstE16 fmul d0,d0,d1 subs x0,x0,#1612: ldr d1,dConstME7 fcmp d0,d1 bhi 13f ldr d1,dConstE8 fmul d0,d0,d1 subs x0,x0,#813: ldr d1,dConstME3 fcmp d0,d1 bhi 14f ldr d1,dConstE4 fmul d0,d0,d1 subs x0,x0,#414: ldr d1,dConstME1 fcmp d0,d1 bhi 15f ldr d1,dConstE2 fmul d0,d0,d1 subs x0,x0,#215: ldr d1,dConstE0 fcmp d0,d1 bhi 100f ldr d1,dConstE1 fmul d0,d0,d1 subs x0,x0,#1100: // fin standard de la fonction ldp x1,lr,[sp],16 // restaur registres ret.align 2dConstE7: .double 0f1E7dConstE256: .double 0f1E256dConstE128: .double 0f1E128dConstE64: .double 0f1E64dConstE32: .double 0f1E32dConstE16: .double 0f1E16dConstE8: .double 0f1E8dConstE4: .double 0f1E4dConstE2: .double 0f1E2dConstE1: .double 0f1E1dConstME5: .double 0f1E-5dConstME255: .double 0f1E-255dConstME127: .double 0f1E-127dConstME63: .double 0f1E-63dConstME31: .double 0f1E-31dConstME15: .double 0f1E-15dConstME7: .double 0f1E-7dConstME3: .double 0f1E-3dConstME1: .double 0f1E-1dConstE0: .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 conversion1: // 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 final100: ldp x4,x5,[sp],16 // restaur registers ldp x2,x3,[sp],16 // restaur registers ldp x1,lr,[sp],16 // restaur registers ret/***************************************************//* ROUTINES INCLUDE *//***************************************************/.include "../includeARM64.inc"
Difference between +20 and +45 = +25Difference between -45 and +45 = +90Difference between -85 and +90 = +175Difference between -95 and +90 = -175Difference between -45 and +125 = +170Difference between -45 and +145 = -170Difference between +29,4802 and -88,638099 = -118,1Difference between -78,325 and -159 = -80,7108999Difference between -70099,7423381 and +29840,674378 = -139,58328
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 ODRETURN (r)PROC TestI(INT a1,a2) INT r r=AngleI(a1,a2) PrintF("%I .. %I = %I%E",a1,a2,r)RETURNPROC 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) ODRETURNPROC 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)RETURNPROC 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")RETURNScreenshot from Atari 8-bit computer
20 .. 45 = 25-45 .. 45 = 90-85 .. 90 = 175-95 .. 90 = -175-45 .. 125 = 170-45 .. 145 = -17029.4803 .. -88.6381 = -118.1184-78.3251 .. -159.036 = -80.7109-70099.7423 .. 29840.6743 = -139.5834-165313.666 .. 33693.9894 = -72.34461174.83805 .. -154146.664 = -161.50260175.773 .. 42213.0719 = 37.2989
Ada does not provide a built-in mod function for floating point types. This program supplies one.
------------------------------------------------------------------------- Angle difference between two bearings-----------------------------------------------------------------------withAda.Text_IO;useAda.Text_IO;procedureBearing_AnglesistypeRealisdigits8;PackageReal_Iois newAda.Text_IO.Float_IO(Real);useReal_IO;typeAnglesisrecordB1:Real;B2:Real;end record;typeAngle_Arrisarray(Positiverange<>)ofAngles;functionfmod(Left,Right:Real)returnRealisResult:Real;beginResult:=Left-Right*Real'Truncation(Left/Right);returnResult;endfmod;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;beginforAofThe_AnglesloopDiff:=fmod(A.b2-A.b1,360.0);IfDiff<-180.0thenDiff:=Diff+360.0;elsifDiff>180.0thenDiff:=Diff-360.0;endif;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;endloop;endBearing_Angles;
Difference between 45.0000 and 20.0000 is 25.0000Difference between 45.0000 and -45.0000 is 90.0000Difference between 90.0000 and -85.0000 is 175.0000Difference between 90.0000 and -95.0000 is -175.0000Difference between 125.0000 and -14.0000 is 139.0000Difference between -88.6381 and 29.4803 is -118.1184Difference between -159.0360 and -78.3251 is -80.7109Difference between 29840.6744 and -70099.7423 is -139.5833Difference between 33693.9895 and -165313.6666 is -72.3439Difference between -154146.6649 and 1174.8381 is -161.5030Difference between 42213.0719 and 60175.7731 is 37.2989
Tested with Agena 5.0.0 Win32
# Angle difference between two bearingsproc getdiff(b1, b2) is r := (b2 - b1) symmod 360.0; if r >= 180.0 then r -:= 360.0 fi; if r < -180.0 then r +:= 360.0 fi; return rend;proc printrow(b1, b2) is printf("%14.6f %14.6f %14.6f\n", b1, b2, getdiff(b1, b2))end;scope print("Input in -180 to +180 range"); print(" Bearing 1 Bearing 2 Difference"); printrow(20.0, 45.0); printrow(-45.0, 45.0); printrow(-85.0, 90.0); printrow(-95.0, 90.0); printrow(-45.0, 125.0); printrow(-45.0, 145.0); printrow(-45.0, 125.0); printrow(-45.0, 145.0); printrow(29.4803, -88.6381); printrow(-78.3251, -159.036); print(); print("Input in wider range"); print(" Bearing 1 Bearing 2 Difference"); printrow(-70099.74233810938, 29840.67437876723); printrow(-165313.6666297357, 33693.9894517456); printrow(1174.8380510598456, -154146.66490124757); printrow(60175.77306795546, 42213.07192354373)epocsInput in -180 to +180 range Bearing 1 Bearing 2 Difference 20.000000 45.000000 25.000000 -45.000000 45.000000 90.000000 -85.000000 90.000000 175.000000 -95.000000 90.000000 -175.000000 -45.000000 125.000000 170.000000 -45.000000 145.000000 -170.000000 -45.000000 125.000000 170.000000 -45.000000 145.000000 -170.000000 29.480300 -88.638100 -118.118400 -78.325100 -159.036000 -80.710900Input in wider range Bearing 1 Bearing 2 Difference -70099.742338 29840.674379 -139.583283-165313.666630 33693.989452 -72.343919 1174.838051 -154146.664901 -161.502952 60175.773068 42213.071924 37.298856
BEGIN # angle difference between 2 bearings - translated from the 11l sample # PROC wrap = (REAL v, l1, l2 )REAL: BEGIN REAL result := v; WHILE result < l1 DO result +:= 2 * l2 OD; WHILE result > l2 DO result +:= 2 * l1 OD; result END # wrap # ; PROC get_difference = ( REAL b1, b2 )REAL: wrap( b2 - b1, -180.0, 180.0 ); OP FMT = ( REAL v )STRING: BEGIN STRING result := fixed( ABS v, 0, 3 ); IF result[ LWB result ] = "." THEN "0" +=: result FI; WHILE result[ UPB result ] = "0" DO result := result[ : UPB result - 1 ] OD; IF result[ UPB result ] = "." THEN result := result[ : UPB result - 1 ] FI; IF v < 0 THEN "-" ELSE " " FI + result END # FMT # ; print( ( FMT get_difference( 20.0, 45.0 ), newline ) ); print( ( FMT get_difference( -45.0, 45.0 ), newline ) ); print( ( FMT get_difference( -85.0, 90.0 ), newline ) ); print( ( FMT get_difference( -95.0, 90.0 ), newline ) ); print( ( FMT get_difference( -45.0, 125.0 ), newline ) ); print( ( FMT get_difference( -45.0, 145.0 ), newline ) ); print( ( FMT get_difference( -45.0, 125.0 ), newline ) ); print( ( FMT get_difference( -45.0, 145.0 ), newline ) ); print( ( FMT get_difference( 29.4803, -88.6381 ), newline ) ); print( ( FMT get_difference( -78.3251, -159.036 ), newline ) ); print( ( newline ) ); print( ( FMT get_difference( -70099.74233810938, 29840.67437876723 ), newline ) ); print( ( FMT get_difference( -165313.6666297357, 33693.9894517456 ), newline ) ); print( ( FMT get_difference( 1174.8380510598456, -154146.66490124757 ), newline ) ); print( ( FMT get_difference( 60175.77306795546, 42213.07192354373 ), newline ) )END
25 90 175-175 170-170 170-170-118.118-80.711-139.583-72.344-161.503 37.299
Returns an angle in (-180,180]; so two opposite bearings have a difference of 180 degrees, which is more natural than -180 degrees.
[0]D←B1DIFFB2[1]D←180+¯360|180+B2-B1
'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 90180
ondiff_bearing({b1,b2})setrto(b2-b1)mod360ifr>180thenr-360elseifr<-180thenr+360elserendifenddiff_bearingsettest_bearingsto{{20,45},{-45,45},{-85,90},{-95,90},{-45,125},{-45,145},{29.4803,-88.6381},{-78.3251,-159.036}}setbig_bearingsto{{-7.00997423381094E+4,2.98406743787672E+4},{-1.65313666629736E+5,3.36939894517456E+4},{1174.838051059846,-1.54146664901248E+5},{6.01757730679555E+4,4.22130719235437E+4}}repeatwithbintest_bearings&big_bearingslogdiff_bearing(b)endrepeat
(*25*)(*90*)(*175*)(*-175*)(*170*)(*-170*)(*-118.1184*)(*-80.7109*)(*-139.5832831234*)(*-72.343918518396*)(*-161.502952307841*)(*37.298855588197*)
/* 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 *//*********************************/.dataszCarriageReturn: .asciz "\n"szMessResult: .asciz "Difference between @ and @ = @ \n".align 4fB1: .float 20.0fB2: .float 45.0fB3: .float -45.0fB4: .float -85.0fB5: .float 90.0fB6: .float -95.0fB7: .float 125.0fB8: .float 145.0fB9: .float 29.4803 fB10: .float -88.6381fB11: .float -78.3251fB12: .float -159.036fB13: .float -70099.74233810938fB14: .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 testComputeAngle100: @ standard end of the program mov r0, #0 @ return code mov r7, #EXIT @ request to exit program svc #0 @ perform the system calliAdrszCarriageReturn: .int szCarriageReturniAdrsZoneConv: .int sZoneConv iAdrfB1: .int fB1iAdrfB2: .int fB2iAdrfB3: .int fB3iAdrfB4: .int fB4iAdrfB5: .int fB5iAdrfB6: .int fB6iAdrfB7: .int fB7iAdrfB8: .int fB8iAdrfB9: .int fB9iAdrfB10: .int fB10iAdrfB11: .int fB11iAdrfB12: .int fB12iAdrfB13: .int fB13iAdrfB14: .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 registersiAdrszMessResult: .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 100f2: @ 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érence100: 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 end2: 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 100f3: @ 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 100f4: 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 zeros5: ldrb r0,[r6] cmp r0,#'0' bne 6f subs r6,#1 b 5b6: cmp r0,#',' bne 7f subs r6,#17: 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,#14: 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 final100: vpop {s0-s2} pop {r1-r7,pc}iMaskExposant: .int 0xFF<<23iConst1: .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,#321: vldr s1,iConstE16 vcmp.f32 s0,s1 vmrs APSR_nzcv,FPSCR blo 2f vldr s1,iConstE16 vdiv.f32 s0,s0,s1 adds r0,#162: vldr s1,iConstE8 vcmp.f32 s0,s1 vmrs APSR_nzcv,FPSCR blo 3f vldr s1,iConstE8 vdiv.f32 s0,s0,s1 adds r0,#83: vldr s1,iConstE4 vcmp.f32 s0,s1 vmrs APSR_nzcv,FPSCR blo 4f vldr s1,iConstE4 vdiv.f32 s0,s0,s1 adds r0,#44: vldr s1,iConstE2 vcmp.f32 s0,s1 vmrs APSR_nzcv,FPSCR blo 5f vldr s1,iConstE2 vdiv.f32 s0,s0,s1 adds r0,#25: vldr s1,iConstE1 vcmp.f32 s0,s1 vmrs APSR_nzcv,FPSCR blo 10f vldr s1,iConstE1 vdiv.f32 s0,s0,s1 adds r0,#110: 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,#3211: vldr s1,iConstME15 vcmp.f32 s0,s1 vmrs APSR_nzcv,FPSCR bhi 12f vldr s1,iConstE16 vmul.f32 s0,s0,s1 subs r0,#1612: vldr s1,iConstME7 vcmp.f32 s0,s1 vmrs APSR_nzcv,FPSCR bhi 13f vldr s1,iConstE8 vmul.f32 s0,s0,s1 subs r0,#813: vldr s1,iConstME3 vcmp.f32 s0,s1 vmrs APSR_nzcv,FPSCR bhi 14f vldr s1,iConstE4 vmul.f32 s0,s0,s1 subs r0,#414: vldr s1,iConstME1 vcmp.f32 s0,s1 vmrs APSR_nzcv,FPSCR bhi 15f vldr s1,iConstE2 vmul.f32 s0,s0,s1 subs r0,#215: vldr s1,iConstE0 vcmp.f32 s0,s1 vmrs APSR_nzcv,FPSCR bhi 100f vldr s1,iConstE1 vmul.f32 s0,s0,s1 subs r0,#1100: @ fin standard de la fonction pop {pc} @ restaur des registres.align 2iConstE7: .float 0f1E7iConstE32: .float 0f1E32iConstE16: .float 0f1E16iConstE8: .float 0f1E8iConstE4: .float 0f1E4iConstE2: .float 0f1E2iConstE1: .float 0f1E1iConstME5: .float 0f1E-5iConstME31: .float 0f1E-31iConstME15: .float 0f1E-15iConstME7: .float 0f1E-7iConstME3: .float 0f1E-3iConstME1: .float 0f1E-1iConstE0: .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 decimale1: @ 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 final100: pop {r1-r6,pc} @ restaur registers /***************************************************//* ROUTINES INCLUDE *//***************************************************/.include "../affichage.inc"Difference between +20E0 and +45E0 = +25E0Difference between -45E0 and +45E0 = +90E0Difference between -85E0 and +90E0 = +175E0Difference between -95E0 and +90E0 = -175E0Difference between -45E0 and +125E0 = +170E0Difference between -45E0 and +145E0 = -170E0Difference between +29,48030089E0 and -88,63809964E0 = -118,1184082E0Difference between -78,32510374E0 and -159,03599548E0 = -80,71087648E0Difference between -70099,74218752E0 and +29840,67382809E0 = -139,58398438E0
getDifference:function[b1,b2][r:(b2- b1)%360.0ifr>=180.0->r:r-360.0returnr]print"Input in -180 to +180 range"printgetDifference20.045.0printgetDifferenceneg45.045.0printgetDifferenceneg85.090.0printgetDifferenceneg95.090.0printgetDifferenceneg45.0125.0printgetDifferenceneg45.0145.0printgetDifferenceneg45.0125.0printgetDifferenceneg45.0145.0printgetDifference29.4803neg88.6381printgetDifferenceneg78.3251neg159.036print""print"Input in wider range"printgetDifferenceneg70099.7423381093829840.67437876723printgetDifferenceneg165313.666629735733693.9894517456printgetDifference1174.8380510598456neg154146.66490124757printgetDifference60175.7730679554642213.07192354373
Input in -180 to +180 range25.090.0175.0-175.0170.0-170.0170.0-170.0-118.1184-80.7109Input in wider range-139.5832831233856-72.34391851868713-161.5029523074045-322.7011444117306
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]]fori,setinanglesresult.=set.2" to "set.1" = "Angle_difference_between_two_bearings(set)"`n"MsgBox,262144,,%resultreturnAngle_difference_between_two_bearings(set){return(diff:=Mod(set.2,360)-Mod(set.1,360))>180?diff-360:diff}
45 to 20 = 2545 to -45 = 9090 to -85 = 17590 to -95 = -175125 to -45 = 170145 to -45 = -170-88.6381 to 29.4803 = -118.118400-159.036 to -78.3251 = -80.71090029840.67437876723 to -70099.74233810938 = 220.41671733693.9894517456 to -165313.6666297357 = -72.343919-154146.66490124757 to 1174.8380510598456 = -161.50295242213.07192354373 to 60175.77306795546 = 37.298856
# syntax: GAWK -f ANGLE_DIFFERENCE_BETWEEN_TWO_BEARINGS.AWKBEGIN{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)}functionmain(b1,b2){printf("%11.2f %11.2f %11.2f\n",b1,b2,angle_difference(b1,b2))}functionangle_difference(b1,b2,r){r=(b2-b1)%360if(r<-180){r+=360}if(r>=180){r-=360}return(r)}
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
importballerina/io;functionsubtract(floatb1,floatb2)returnsfloat{floatd=(b2-b1)%360.0;ifd<-180.0{d+=360.0;}ifd>=180.0{d-=360.0;}returnd.round(4);}publicfunctionmain(){float[][]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]];io:println("Differences (to 4dp) between these bearings:");foreachvarpairinpairs{floatp0=pair[0];floatp1=pair[1];floatdiff=subtract(p0,p1);stringoffset=p0<0.0?" ":" ";io:println(`${offset}${p0} and ${p1} -> ${diff}`);}}
Differences (to 4dp) between these bearings: 20.0 and 45.0 -> 25.0 -45.0 and 45.0 -> 90.0 -85.0 and 90.0 -> 175.0 -95.0 and 90.0 -> -175.0 -45.0 and 125.0 -> 170.0 -45.0 and 145.0 -> -170.0 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.3439 1174.8380510598456 and -154146.66490124757 -> -161.503 60175.77306795546 and 42213.07192354373 -> 37.2989
100REM Angle difference between two bearings110DECLAREEXTERNALFUNCTIONGetDiff120REM130SUBPrintRow(B1,B2)140PRINTUSING"#######.###### #######.###### #######.######":B1,B2,GetDiff(B1,B2)150ENDSUB160REM170print"Input in -180 to +180 range"180PRINT" Bearing 1 Bearing 2 Difference"190CALLPrintRow(20.0,45.0)200CALLPrintRow(-45.0,45.0)210CALLPrintRow(-85.0,90.0)220CALLPrintRow(-95.0,90.0)230CALLPrintRow(-45.0,125.0)240CALLPrintRow(-45.0,145.0)250CALLPrintRow(-45.0,125.0)260CALLPrintRow(-45.0,145.0)270CALLPrintRow(29.4803,-88.6381)280CALLPrintRow(-78.3251,-159.036)290PRINT300PRINT"Input in wider range"310PRINT" Bearing 1 Bearing 2 Difference"320CALLPrintRow(-70099.74233810938,29840.67437876723)330CALLPrintRow(-165313.6666297357,33693.9894517456)340CALLPrintRow(1174.8380510598456,-154146.66490124757)350CALLPrintRow(60175.77306795546,42213.07192354373)360END370REM380EXTERNALFUNCTIONGetDiff(B1,B2)390LETR=MOD(B2-B1,360.0)400IFR>=180.0THENLETR=R-360.0410LETGetDiff=R420ENDFUNCTION
Input in -180 to +180 range Bearing 1 Bearing 2 Difference 20.000000 45.000000 25.000000 -45.000000 45.000000 90.000000 -85.000000 90.000000 175.000000 -95.000000 90.000000 -175.000000 -45.000000 125.000000 170.000000 -45.000000 145.000000 -170.000000 -45.000000 125.000000 170.000000 -45.000000 145.000000 -170.000000 29.480300 -88.638100 -118.118400 -78.325100 -159.036000 -80.710900Input in wider range Bearing 1 Bearing 2 Difference -70099.742338 29840.674379 -139.583283-165313.666630 33693.989452 -72.343919 1174.838051 -154146.664901 -161.502952 60175.773068 42213.071924 37.298856
# Rosetta Code problem: http://rosettacode.org/wiki/Angle_difference_between_two_bearings# by Jjuanhdez, 06/2022print "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)printprint "Input in wider range:"call getDifference(-70099.74233810938, 29840.67437876723)call getDifference(-165313.6666297357, 33693.9894517456)call getDifference(1174.8380510598456, -154146.66490124757)endsubroutine getDifference(b1, b2)r = (b2 - b1) mod 360if r >= 180.0 then r -= 360.0print ljust(b1,16); ljust(b2,16); ljust(r,12)end subroutine
100cls110subgetdifference(b1,b2)120r=(b2-b1)mod360130ifr>=180thenr=r-360140printusing"#######.######";b1;150printusing" #######.######";b2;160printusing" #######.######";r170endsub180print"Input in -180 to +180 range:"190print" b1 b2 difference"200print" -------------------------------------------------"210getdifference(20,45)220getdifference(-45,45)230getdifference(-85,90)240getdifference(-95,90)250getdifference(-45,125)260getdifference(-45,145)270getdifference(-45,125)280getdifference(-45,145)290getdifference(29.4803,-88.6381)300getdifference(-78.3251,-159.036)310getdifference(-70099.742338,29840.674379)320getdifference(-165313.66663,33693.989452)330getdifference(1174.838051,-154146.664901)340print350print"Input in wider range:"360print" b1 b2 difference"370print" -------------------------------------------------"380getdifference(-70099.742338,29840.674379)390getdifference(-165313.66663,33693.989452)400getdifference(1174.838051,-154146.664901)410getdifference(60175.773068,42213.071924)
Input in -180 to +180 range: b1 b2 difference ------------------------------------------------- 20.000000 45.000000 25.000000 -45.000000 45.000000 90.000000 -85.000000 90.000000 175.000000 -95.000000 90.000000 -175.000000 -45.000000 125.000000 170.000000 -45.000000 145.000000 -170.000000 -45.000000 125.000000 170.000000 -45.000000 145.000000 -170.000000 29.480300 -88.638100 -118.000000 -78.325100 -159.036000 -80.000000 -70099.742338 29840.674379 -140.000000-165313.666630 33693.989452 -73.000000 1174.838051 -154146.664901 -161.000000Input in wider range: b1 b2 difference ------------------------------------------------- -70099.742338 29840.674379 -140.000000-165313.666630 33693.989452 -73.000000 1174.838051 -154146.664901 -161.000000 60175.773068 42213.071924 -322.000000
precision4defines1=0,s2=0dimb1[20,-45,-85,-95,-45,-45,29.4803,-78.3251]dimb2[45,45,90,90,125,145,-88.6381,-159.036]arraysizes1,b1arraysizes2,b2ifs1=s2thenfori=0tos1-1letr=(b2[i]-b1[i])%360ifr>=180thenletr=r-360endifprint"bearing 1: ",b1[i]," bearing 2: ",b2[i]," difference: ",rnextiendif
bearing 1: 20 bearing 2: 45 difference: 25bearing 1: -45 bearing 2: 45 difference: 90bearing 1: -85 bearing 2: 90 difference: 175bearing 1: -95 bearing 2: 90 difference: -175bearing 1: -45 bearing 2: 125 difference: 170bearing 1: -45 bearing 2: 145 difference: -170bearing 1: 29.4803 bearing 2: -88.6381 difference: -118bearing 1: -78.3251 bearing 2: -159.0360 difference: -80
' version 28-01-2019' compile with: fbc -s console#Include"string.bi"Functionfrmt(numAsDouble)AsStringDimAsStringtemp=Format(num,"#######.#############")DimAsIntegeri=Len(temp)-1Iftemp[i]=Asc(".")Thentemp[i]=32IfInStr(temp,".")=0ThenReturnRight(Space(10)+temp,9)+Space(13)EndIftemp=Space(10)+temp+Space(13)ReturnMid(temp,InStr(temp,".")-8,22)EndFunction' ------=< MAIN >=------DimAsDoubleb1,b2,bb1,bb2,diffPrintPrint" b1 b2 difference"Print" -----------------------------------------------------------"DoReadb1,b2Ifb1=0Andb2=0ThenExitDodiff=b2-b1diff=diff-Int(diff/360)*360Ifdiff>180Thendiff-=360Printfrmt(b1);frmt(b2);frmt(diff)LoopData20,45,-45,45,-85,90Data-95,90,-45,125,-45,145Data29.4803,-88.6381,-78.3251,-159.036Data-70099.74233810938,29840.67437876723Data-165313.6666297357,33693.9894517456Data1174.8380510598456,-154146.66490124757Data60175.77306795546,42213.07192354373' empty keyboard bufferWhileInKey<>"":WendPrint:Print"hit any key to end program"SleepEnd
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
100INPUTPROMPT"1. angle: ":A1110INPUTPROMPT"2. angle: ":A2120LETB=MOD(A2-A1,360)130IFB>180THENLETB=B-360140IFB<-180THENLETB=B+360150PRINT"Difference: ";B
Procedure.fgetDifference(b1.f,b2.f)r.f=Mod((b2-b1),360)Ifr>=180:r-360EndIfPrintN(StrF(b1)+#TAB$+StrF(b2)+#TAB$+StrF(r));EndProcedureIfOpenConsole()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:UntilInkey()<>""EndIf
SUBgetDifference(b1!,b2!)r!=(b2-b1)MOD360!IFr>=180!THENr=r-360!PRINTUSING"#######.###### #######.###### #######.######";b1;b2;rENDSUBPRINT" Bearing 1 Bearing 2 Difference"CALLgetDifference(20!,45!)CALLgetDifference(-45!,45!)CALLgetDifference(-85!,90!)CALLgetDifference(-95!,90!)CALLgetDifference(-45!,125!)CALLgetDifference(-45!,145!)CALLgetDifference(-45!,125!)CALLgetDifference(-45!,145!)CALLgetDifference(29.4803,-88.6381)CALLgetDifference(-78.3251,-159.036)CALLgetDifference(-70099.74233810938#,29840.67437876723#)CALLgetDifference(-165313.6666297357#,33693.9894517456#)CALLgetDifference(1174.838051059846#,-154146.6649012476#)
sub getDifference b1, b2 r = (b2 - b1) mod 360 if r >= 180 then r = r - 360 print rend subprint "Input in -180 to +180 range:"call getDifference 20, 45 call getDifference -45, 45 call getDifference -85, 90call getDifference -95, 90call getDifference -45, 125call getDifference -45, 145call getDifference -45, 125call getDifference -45, 145call getDifference 29.4803, -88.6381call getDifference -78.3251, -159.036print "Input in wider range:"call getDifference -70099.74233810938, 29840.67437876723call getDifference -165313.6666297357, 33693.9894517456call getDifference 1174.8380510598456, -154146.66490124757
SUBgetdifference(b1,b2)LETr=REMAINDER(b2-b1,360.0)IFr>=180.0THENLETr=r-360.0PRINTUSING"#######.###### #######.###### #######.######":b1,b2,rENDSUBPRINT" Bearing 1 Bearing 2 Difference"CALLgetdifference(20.0,45.0)CALLgetdifference(-45.0,45.0)CALLgetdifference(-85.0,90.0)CALLgetdifference(-95.0,90.0)CALLgetdifference(-45.0,125.0)CALLgetdifference(-45.0,145.0)CALLgetdifference(-45.0,125.0)CALLgetdifference(-45.0,145.0)CALLgetdifference(29.4803,-88.6381)CALLgetdifference(-78.3251,-159.036)CALLgetdifference(-70099.74233810938,29840.67437876723)CALLgetdifference(-165313.6666297357,33693.9894517456)CALLgetdifference(1174.8380510598456,-154146.66490124757)END
PrivateFunctiontx(aAsVariant)AsStringDimsAsStrings=CStr(Format(a,"0.######"))IfRight(s,1)=","Thens=Mid(s,1,Len(s)-1)&" "Elsei=InStr(1,s,",")s=s&String$(6-Len(s)+i," ")EndIftx=sEndFunctionPrivateSubtest(b1AsVariant,b2AsVariant)DimdiffAsVariantdiff=(b2-b1)-((b2-b1)\360)*360diff=diff-IIf(diff>180,360,0)diff=diff+IIf(diff<-180,360,0)Debug.PrintFormat(tx(b1),"@@@@@@@@@@@@@@@@");Format(tx(b2),"@@@@@@@@@@@@@@@@@");Format(tx(diff),"@@@@@@@@@@@@@@@@@")EndSubPublicSubangle_difference()Debug.Print" b1 b2 diff"Debug.Print"---------------- ---------------- ----------------"test20,45test-45,45test-85,90test-95,90test-45,125test-45,145test29.4803,-88.6381test-78.3251,-159.036test-70099.7423381094,29840.6743787672test-165313.666629736,33693.9894517456test1174.83805105985,-154146.664901248test60175.7730679555,42213.0719235437EndSub
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
ModuleModule1FunctionDelta_Bearing(b1AsDecimal,b2AsDecimal)AsDecimalDimdAsDecimal=0' Convert bearing to W.C.BWhileb1<0b1+=360EndWhileWhileb1>360b1-=360EndWhileWhileb2<0b2+=360EndWhileWhileb2>0b2-=360EndWhile' Calculate delta bearingd=(b2-b1)Mod360' Convert result to Q.BIfd>180Thend-=360ElseIfd<-180Thend+=360EndIfReturndEndFunctionSubMain()' Calculate standard test casesConsole.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 casesConsole.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))EndSubEndModule
2590175-175170-170-118.1184-80.7109-139.5832831234-72.3439185184-161.5029523078537.2988555882
//RosettaCodeproblem:http://rosettacode.org/wiki/Angle_difference_between_two_bearings//byJjuanhdez,06/2022print"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)endsubgetDifference(b1,b2)r=mod((b2-b1),360.0)ifr>=180.0r=r-360.0printrendsub
012pv12345678>&:v>859**%:459**1-`#v_>12g!:12p#v_\-:459**1-`#v_>.>>0`#^_8v>859**-^>859**-^^:+**95<>^
The labelled points are:1. Initialise write/not write and read input,2. Put in the range 0-360 if negative,3. Likewise if positive,4. Put in range -180 - 180,5. Check if write/not write step,6. If write find difference,7. Scale to -180 - 180,8. Write out and onto next pair.
Unfortunately, due to the lack of floating-point arithmetic in befunge, it is impossible to do the full challenge, however, given the integer truncations of these values it works.
Input:
20 45-45 45-85 90-95 90-45 125-45 14529 -88-78 -159-70099 29840-165313 336931174 -15414660175 42213
25 90 175 -175 170 -170 -117 -81 -141 -74 -160 38
Adiff←180-360|180+-tests←[20‿45,¯45‿45,¯85‿90,¯95‿90,¯45‿125,¯45‿14599‿279,29.4803‿¯88.6381,¯78.3251‿¯159.036¯70099.74233810938‿29840.67437876723¯165313.6666297357‿33693.98945174561174.8380510598456‿¯154146.6649012475760175.77306795546‿42213.07192354373]Round←⌊∘+⟜0.5⌾(1e3⊸×)Round∘∾⟜(Adiff´)˘tests
┌─╵ 20 45 25 ¯45 45 90 ¯85 90 175 ¯95 90 ¯175 ¯45 125 170 ¯45 145 ¯170 99 279 180 29.48 ¯88.638 ¯118.118 ¯78.325 ¯159.036 ¯80.711 ¯70099.742 29840.674 ¯139.583 ¯165313.667 33693.989 ¯72.344 1174.838 ¯154146.665 ¯161.503 60175.773 42213.072 37.299 ┘
This implementation either reads two bearings from the console or a file containing a list of bearings. Usage printed on incorrect invocation.
#include<stdlib.h>#include<stdio.h>#include<math.h>voidprocessFile(char*name){inti,records;doublediff,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);}intmain(intargC,char*argV[]){doublediff;if(argC<2)printf("Usage : %s <bearings separated by a space OR full file name which contains the bearing list>",argV[0]);elseif(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));}return0;}
Invocation and output for two bearings :
C:\rosettaCode>bearingDiff.exe 29.4803 -88.6381Difference 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 :
1220 45-45 45-85 90-95 90-45 125-45 14529.4803 -88.6381-78.3251 -159.036-70099.74233810938 29840.67437876723-165313.6666297357 33693.98945174561174.8380510598456 -154146.6649012475760175.77306795546 42213.07192354373
Invocation and output for above bearing list file :
C:\rosettaCode>bearingDiff.exe bearingList.txtDifference between b2(45.000000) and b1(20.000000) is 25.000000Difference between b2(45.000000) and b1(-45.000000) is 90.000000Difference between b2(90.000000) and b1(-85.000000) is 175.000000Difference between b2(90.000000) and b1(-95.000000) is -175.000000Difference between b2(125.000000) and b1(-45.000000) is 170.000000Difference between b2(145.000000) and b1(-45.000000) is -170.000000Difference between b2(-88.638100) and b1(29.480300) is -118.118400Difference between b2(-159.036000) and b1(-78.325100) is -80.710900Difference between b2(29840.674379) and b1(-70099.742338) is -139.583283Difference between b2(33693.989452) and b1(-165313.666630) is -72.343919Difference between b2(-154146.664901) and b1(1174.838051) is -161.502952Difference between b2(42213.071924) and b1(60175.773068) is 37.298856
usingSystem;namespaceAngle_difference_between_two_bearings{classProgram{publicstaticvoidMain(string[]args){Console.WriteLine();Console.WriteLine("Hello World!");Console.WriteLine();// Calculate standard test casesConsole.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 casesConsole.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);}staticdecimalDelta_Bearing(decimalb1,decimalb2){/* * Optimal solution *decimal d = 0;d = (b2-b1)%360;if(d>180)d -= 360;else if(d<-180)d += 360;return d; * * *///////decimald=0;// Convert bearing to W.C.Bif(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;elseif(d<-180)d+=360;returnd;//////}}}
Hello World!2590175-175170-170-118,1184-80,7109-139,58328312339-72,3439185187-161,502952307415637,29885558827Press any key to continue . . .
#include<cmath>#include<iostream>usingnamespacestd;doublegetDifference(doubleb1,doubleb2){doubler=fmod(b2-b1,360.0);if(r<-180.0)r+=360.0;if(r>=180.0)r-=360.0;returnr;}inlinevoidprintRow(doubleb1,doubleb2){cout<<getDifference(b1,b2)<<endl;}intmain(){cout<<"Input in -180 to +180 range"<<endl;printRow(20.0,45.0);printRow(-45.0,45.0);printRow(-85.0,90.0);printRow(-95.0,90.0);printRow(-45.0,125.0);printRow(-45.0,145.0);printRow(-45.0,125.0);printRow(-45.0,145.0);printRow(29.4803,-88.6381);printRow(-78.3251,-159.036);cout<<endl<<"Input in wider range"<<endl;printRow(-70099.74233810938,29840.67437876723);printRow(-165313.6666297357,33693.9894517456);printRow(1174.8380510598456,-154146.66490124757);printRow(60175.77306795546,42213.07192354373);return0;}
Input in -180 to +180 range2590175-175170-170170-170-118.118-80.7109Input in wider range-139.583-72.3439-161.50337.2989
(defnangle-difference[ab](let[r(mod(-ba)360)](if(>=r180)(-r360)r)))(angle-difference2045); 25(angle-difference-4545); 90(angle-difference-8590); 175(angle-difference-9590); -175(angle-difference-70099.7429840.67); -139.59
****************************************************************** * 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. ******************************************************************IDENTIFICATIONDIVISION.PROGRAM-ID.ANGLE-DIFFERENCE.ENVIRONMENTDIVISION.INPUT-OUTPUTSECTION.FILE-CONTROL.SELECTIN-FILEASSIGNTO'C:\Both\Rosetta\Angle_diff.txt'ORGANIZATIONISLINESEQUENTIAL.DATADIVISION.FILESECTION.FDIN-FILE.01IN-RECORD.05ALPHA-BEARING-1PIC X(20).05FILLERPIC X.05ALPHA-BEARING-2PIC X(20).WORKING-STORAGESECTION.01SWITCHES.05EOF-SWITCHPIC XVALUE'N'.01COUNTERS.05REC-CTRPIC 9(3)VALUE0.01WS-ALPHA-BEARING.05WS-AB-SIGNPIC X.88WS-AB-NEGATIVEVALUE"-".05WS-AB-INTEGER-PARTPIC X(6).05WS-AB-DEC-POINTPIC X.05WS-AB-DECIMAL-PARTPIC X(12).01WS-BEARING-1PIC S9(6)V9(12).01WS-BEARING-2PIC S9(6)V9(12).01WS-BEARINGPIC S9(6)V9(12).01FILLERREDEFINESWS-BEARING.05WSB-INTEGER-PARTPIC X(6).05WSB-DECIMAL-PARTPIC X9(12).77WS-RESULTPIC S9(6)V9(12).77WS-RESULT-POSPIC 9(6)V9(12).77WS-INTEGER-PARTPIC 9(6).77WS-DECIMAL-PARTPIC V9(12).77WS-RESULT-OUTPIC ------9.9999.PROCEDUREDIVISION.000-MAIN.PERFORM100-INITIALIZE.PERFORM200-PROCESS-RECORDUNTILEOF-SWITCH='Y'.PERFORM300-TERMINATE.STOPRUN.100-INITIALIZE.OPENINPUTIN-FILE.PERFORM150-READ-RECORD.150-READ-RECORD.READIN-FILEATENDMOVE'Y'TOEOF-SWITCHNOTATENDCOMPUTEREC-CTR=REC-CTR+1END-READ.200-PROCESS-RECORD.MOVEALPHA-BEARING-1TOWS-ALPHA-BEARING.PERFORM250-CONVERT-DATA.MOVEWS-BEARINGTOWS-BEARING-1.MOVEALPHA-BEARING-2TOWS-ALPHA-BEARING.PERFORM250-CONVERT-DATA.MOVEWS-BEARINGTOWS-BEARING-2.COMPUTEWS-RESULT=WS-BEARING-2-WS-BEARING-1.MOVEWS-RESULTTOWS-RESULT-POS.MOVEWS-RESULT-POSTOWS-INTEGER-PART.COMPUTEWS-DECIMAL-PART=WS-RESULT-POS-WS-INTEGER-PART.COMPUTEWS-INTEGER-PART=FUNCTIONMOD(WS-INTEGER-PART360).IFWS-RESULT>0COMPUTEWS-RESULT=WS-INTEGER-PART+WS-DECIMAL-PARTELSECOMPUTEWS-RESULT=(WS-INTEGER-PART+WS-DECIMAL-PART)*-1END-IF.IFWS-RESULT<-180COMPUTEWS-RESULT=WS-RESULT+360.IFWS-RESULT>180COMPUTEWS-RESULT=WS-RESULT-360.COMPUTEWS-RESULT-OUTROUNDED=WS-RESULT.DISPLAYREC-CTR' 'WS-RESULT-OUT.PERFORM150-READ-RECORD.250-CONVERT-DATA.MOVEWS-AB-INTEGER-PARTTOWSB-INTEGER-PART.MOVEWS-AB-DECIMAL-PARTTOWSB-DECIMAL-PART.IFWS-AB-NEGATIVESUBTRACTWS-BEARINGFROMZEROGIVINGWS-BEARINGEND-IF.300-TERMINATE.DISPLAY'RECORDS PROCESSED: 'REC-CTR.CLOSEIN-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 ******************************************************************
(defun angle-difference (b1 b2) (let ((diff (mod (- b2 b1) 360))) (if (< diff -180) (incf diff 360) (if (> diff 180) (decf diff 360) diff))))
CL-USER> (angle-difference 20 45)25CL-USER> (angle-difference -45 45)90CL-USER> (angle-difference -85 90)175CL-USER> (angle-difference -95 90)-175CL-USER> (angle-difference -70099.74 29840.67)-139.58594
importstd.stdio;doublegetDifference(doubleb1,doubleb2){doubler=(b2-b1)%360.0;if(r<-180.0){r+=360.0;}if(r>=180.0){r-=360.0;}returnr;}voidmain(){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));}
Input in -180 to +180 range2590175-175170-170170-170-118.118-80.7109Input in wider range-139.583-72.3439-161.50337.2989
See#Pascal.
func angdiff a b . r = (b - a) mod 360 if r < -180 r += 360 elif r >= 180 r -= 360 . return r.proc pd a b . print b & " " & a & " -> " & angdiff a b.pd 20 45pd -45 45pd -85 90pd -95 90pd -45 125pd -45 145pd 29.4803 -88.6381pd -78.3251 -159.036pd -70099.74233810938 29840.67437876723pd -165313.6666297357 33693.9894517456pd 1174.8380510598456 -154146.66490124757pd 60175.77306795546 42213.07192354373
45 20 -> 2545 -45 -> 9090 -85 -> 17590 -95 -> -175125 -45 -> 170145 -45 -> -170-88.64 29.48 -> -118.12-159.04 -78.33 -> -80.7129840.67 -70099.74 -> -139.5833693.99 -165313.67 -> -72.34-154146.66 1174.84 -> -161.5042213.07 60175.77 -> 37.30
The real number calculations are done using integer arithmetic to better handlerounding 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 resultswith the result of function call.
-module(bearings).%% API-export([angle_sub_degrees/2,test/0]).-define(RealAngleMultiplier,16#10000000000).-define(DegreesPerTurn,360).-define(Precision,9).%%%===================================================================%%% API%%%===================================================================%%--------------------------------------------------------------------%% @doc%% @spec%% @end%%--------------------------------------------------------------------%%angle_sub_degrees(B1,B2)whenis_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=ValueremTurnSize,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 2minimise_angle(Angle,Turn)whenAngle+(Turnbsr1)<0->Angle+Turn;minimise_angle(Angle,Turn)whenAngle-(Turnbsr1)>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.
Binding the names ANGLEBETWEENBEARINGS and BEARINGDELTA to the following lambda expressions in the Name Manager of the Excel WorkBook:
(SeeLAMBDA: The ultimate Excel worksheet function)
ANGLEBETWEENBEARINGS=LAMBDA(ab,DEGREES(BEARINGDELTA(RADIANS(ab))))BEARINGDELTA=LAMBDA(ab,LET(sinab,SIN(ab),cosab,COS(ab),ax,INDEX(sinab,1),bx,INDEX(sinab,2),ay,INDEX(cosab,1),by,INDEX(cosab,2),rem,"Sign * dot product",IF(0<((ay*bx)-(by*ax)),1,-1)*ACOS((ax*bx)+(ay*by))))
Using an Excel custom number format to display the degree symbol°
| 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 | |||
letdeltaBearing(b1:double)(b2:double)=letr=(b2-b1)%360.0;ifr>180.0thenr-360.0elifr<-180.0thenr+360.0elser[<EntryPoint>]letmain_=printfn"%A"(deltaBearing20.045.0)printfn"%A"(deltaBearing-45.045.0)printfn"%A"(deltaBearing-85.090.0)printfn"%A"(deltaBearing-95.090.0)printfn"%A"(deltaBearing-45.0125.0)printfn"%A"(deltaBearing-45.0145.0)printfn"%A"(deltaBearing29.4803-88.6381)printfn"%A"(deltaBearing-78.3251-159.036)printfn"%A"(deltaBearing-70099.7423381093829840.67437876723)printfn"%A"(deltaBearing-165313.666629735733693.9894517456)printfn"%A"(deltaBearing1174.8380510598456-154146.66490124757)printfn"%A"(deltaBearing60175.7730679554642213.07192354373)0// return an integer exit code
25.090.0175.0-175.0170.0-170.0-118.1184-80.7109-139.5832831-72.34391852-161.502952337.29885559
USING:combinatorsgeneralizationskernelmathprettyprint;IN:rosetta-code.bearings:delta-bearing(xy--z)swap-360mod{{[dup180>][360-]}{[dup-180<][360+]}[]}cond;:bearings-demo(--)20 45-45 45-85 90-95 90-45 125-45 14529.4803 -88.6381-78.3251 -159.036-70099.74233810938 29840.67437876723-165313.6666297357 33693.98945174561174.8380510598456 -154146.6649012475760175.77306795546 42213.07192354373[delta-bearing.]2 12mnapply;MAIN:bearings-demo
2590175-175170-170-118.1184-80.7109-139.5832831233856-72.34391851868713-161.502952307404537.29885558826936
Developed with Gforth 0.7.9_20211014 using floating point math.
:Angle-Difference-stack( b1 b2 - a +/-180)\ Algorithm with stack manipulation without branches ( s. Frotran Groovy)fswapf-\ Delta angle360efswapfoverfmod\ mod 360fover1.5ef*f+\ + 540foverfmod\ mod 360fswapf2/f-\ - 180;:Angle-Difference-const( b1 b2 - a +/-180)\ Algorithm without Branches ( s. Fotran Groovy)fswapf-360efmod540ef+360efmod180ef-;\ Test Word for requested tests:test-ad( b1 b2 -- )foverfoverAngle-Difference-stackf.Angle-Difference-constf.;
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.50295230740460175.77306795546e 42213.07192354373e test-ad 37.2988555882694 37.2988555882694
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 usingarctan instead ofarccos to recover angles would be safer. By using the four-quadrantarctan(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 justT = ATAN2D(Z1*CONJG(Z2)) and the whole calculation could be effected in one statement,T = ATAN2D(CIS(90 - B1)*CONJG(CIS(90 - B2))) And, sincecis(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.
SUBROUTINEBDIFF(B1,B2)!Difference B2 - B1, as bearings. All in degrees, not radians.REAL*8B1,B2!Maximum precision, for large-angle folding.COMPLEX*16CIS,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.10FORMAT(2(F14.4,"(",F9.6,",",F9.6,")"),F9.3)!Two lots, and a tail.END SUBROUTINEBDIFF!Having functions in degrees saves some bother.PROGRAMORIENTEDREAL*8B(24)!Just prepare a wad of values.DATAB/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,51174.8380510598456D0,-154146.66490124757D0,660175.77306795546D0,42213.07192354373D0/WRITE(6,1)("B",I,"x","y",I=1,2)!Or, one could just list them twice.1FORMAT(28X,"Bearing calculations, in degrees"//*2(A13,I1,"(",A9,",",A9,")"),A9)!Compare format 10, above.DOI=1,23,2!Step through the pairs.CALLBDIFF(B(I),B(I+1))END DO END
The output shows the stages:
Bearing calculations, in degrees B1( x, y) B2( x, y) 20.0000( 0.342020, 0.939693) 45.0000( 0.707107, 0.707107) 25.000 -45.0000(-0.707107, 0.707107) 45.0000( 0.707107, 0.707107) 90.000 -85.0000(-0.996195, 0.087156) 90.0000( 1.000000, 0.000000) 175.000 -95.0000(-0.996195,-0.087156) 90.0000( 1.000000, 0.000000) -175.000 -45.0000(-0.707107, 0.707107) 125.0000( 0.819152,-0.573576) 170.000 -45.0000(-0.707107, 0.707107) 145.0000( 0.573576,-0.819152) -170.000 29.4803( 0.492124, 0.870525) -88.6381(-0.999718, 0.023767) -118.118 -78.3251(-0.979312, 0.202358) -159.0360(-0.357781,-0.933805) -80.711 -70099.7423( 0.984016,-0.178078) 29840.6744(-0.633734, 0.773551) -139.584 -165313.6666(-0.959667, 0.281138) 33693.9895(-0.559023,-0.829152) -72.340 1174.8381( 0.996437,-0.084339) -154146.6649(-0.918252, 0.395996) -161.510 60175.7731( 0.826820, 0.562467) 42213.0719( 0.998565,-0.053561) 37.297
void local fn GetDifference( b1 as float, b2 as float ) float r = ( b2 - b1 ) mod 360.0 if r >= 180.0 then r = r - 360.0 printf @"%9.1f\u00B0 %10.1f\u00B0 = %7.1f\u00B0", b1, b2, rend fnprintf @"Input in -180 to +180 range:"printf @"-----------------------------------"printf @"%9s %12s %15s", "b1", "b2", "distance"printf @"-----------------------------------"fn GetDifference( 20.0, 45.0 )fn GetDifference( -45.0, 45.0 )fn GetDifference( -85.0, 90.0 )fn GetDifference( -95.0, 90.0 )fn GetDifference( -45.0, 125.0 )fn GetDifference( -45.0, 145.0 )fn GetDifference( -45.0, 125.0 )fn GetDifference( -45.0, 145.0 )fn GetDifference( 29.4803, -88.6381 )fn GetDifference( -78.3251, -159.036 )fn GetDifference( -70099.74233810938, 29840.67437876723 )fn GetDifference( -165313.6666297357, 33693.9894517456 )fn GetDifference( 1174.8380510598456, -154146.66490124757 )HandleEvents
----------------------------------- b1 b2 distance----------------------------------- 20.0° 45.0° = 25.0° -45.0° 45.0° = 90.0° -85.0° 90.0° = 175.0° -95.0° 90.0° = -175.0° -45.0° 125.0° = 170.0° -45.0° 145.0° = -170.0° -45.0° 125.0° = 170.0° -45.0° 145.0° = -170.0° 29.5° -88.6° = -118.1° -78.3° -159.0° = -80.7° -70099.7° 29840.7° = -139.6°-165313.7° 33694.0° = -72.3° 1174.8° -154146.7° = -161.5°
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.
packagemainimport"fmt"typebearingfloat64vartestCases=[]struct{b1,b2bearing}{{20,45},{-45,45},{-85,90},{-95,90},{-45,125},{-45,145},{29.4803,-88.6381},{-78.3251,-159.036},}funcmain(){for_,tc:=rangetestCases{fmt.Println(tc.b2.Sub(tc.b1))}}func(b2bearing)Sub(b1bearing)bearing{switchd:=b2-b1;{cased<-180:returnd+360cased>180:returnd-360default:returnd}}
2590175-175170-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.
packagemainimport("fmt""math")vartestCases=[]struct{b1,b2float64}{{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},}funcmain(){for_,tc:=rangetestCases{fmt.Println(angleDifference(tc.b2,tc.b1))}}funcangleDifference(b2,b1float64)float64{returnmath.Mod(math.Mod(b2-b1,360)+360+180,360)-180}
2590175-175170-170-118.11840000000001-80.71089999999998-139.58328312338563-72.34391851868713-161.5029523074044837.29885558826936
Solution A:
defangleDifferenceA(doubleb1,doubleb2){r=(b2-b1)%360.0(r>180.0?r-360.0:r<=-180.0?r+360.0:r)}
Solution B:
In the spirit of theFortran "Why branch when you can math?" solution, but without all the messy trigonometry.
defangleDifferenceB(doubleb1,doubleb2){((b2-b1)%360.0-540.0)%360.0+180.0}
NOTE: We could ADD 540 and SUBTRACT 180 instead (as did many others, notably360_Assembly,NewLISP,Racket, andREXX). The difference is that my choice normalizes "about face" to +180° while the other (At least inGroovy and otherC-derived languages) normalizes "about face" to -180°.
Test:
println" b1 b2 diff A diff B"[[b1:20,b2:45],[b1:-45,b2:45],[b1:-85,b2:90],[b1:-95,b2:90],[b1:-45,b2:125],[b1:-45,b2:145],[b1:29.4803,b2:-88.6381],[b1:-78.3251,b2:-159.036],[b1:-70099.74233810938,b2:29840.67437876723],[b1:-165313.6666297357,b2:33693.9894517456],[b1:1174.8380510598456,b2:-154146.66490124757],[b1:60175.77306795546,b2:42213.07192354373]].each{bearings->def(b1,b2)=bearings.values().collect{itasdouble}printf("%22.13f %22.13f %22.13f %22.13f\n",b1,b2,angleDifferenceA(b1,b2),angleDifferenceB(b1,b2))}
Output:
b1 b2 diff A diff B 20.0000000000000 45.0000000000000 25.0000000000000 25.0000000000000 -45.0000000000000 45.0000000000000 90.0000000000000 90.0000000000000 -85.0000000000000 90.0000000000000 175.0000000000000 175.0000000000000 -95.0000000000000 90.0000000000000 -175.0000000000000 -175.0000000000000 -45.0000000000000 125.0000000000000 170.0000000000000 170.0000000000000 -45.0000000000000 145.0000000000000 -170.0000000000000 -170.0000000000000 29.4803000000000 -88.6381000000000 -118.1184000000000 -118.1184000000000 -78.3251000000000 -159.0360000000000 -80.7109000000000 -80.7109000000000 -70099.7423381093800 29840.6743787672300 -139.5832831233856 -139.5832831233856 -165313.6666297357000 33693.9894517456000 -72.3439185186871 -72.3439185186871 1174.8380510598456 -154146.6649012475700 -161.5029523074045 -161.5029523074045 60175.7730679554600 42213.0719235437300 37.2988555882694 37.2988555882694
importControl.Monad(join)importData.Bifunctor(bimap)importText.Printf(printf)typeRadians=FloattypeDegrees=Float---------- ANGLE DIFFERENCE BETWEEN TWO BEARINGS ---------bearingDelta::(Radians,Radians)->RadiansbearingDelta(a,b)-- sign * dot-product=sign*acos((ax*bx)+(ay*by))where(ax,ay)=(sina,cosa)(bx,by)=(sinb,cosb)sign|((ay*bx)-(by*ax))>0=1|otherwise=-1angleBetweenDegrees::(Degrees,Degrees)->DegreesangleBetweenDegrees=degrees.bearingDelta.joinbimapradians--------------------------- 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->Degreesdegrees=(/pi).(180*)radians::Degrees->Radiansradians=(/180).(pi*)
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°
relativeBearing=:180-360|180+-tests=:_99&".;._2noundefine20 45-45 45-85 90-95 90-45 125-45 14529.4803 -88.6381-78.3251 -159.036-70099.74233810938 29840.67437876723-165313.6666297357 33693.98945174561174.8380510598456 -154146.6649012475760175.77306795546 42213.07192354373)
tests ,. relativeBearing/"1 tests 20 45 25 _45 45 90 _85 90 175 _95 90 _175 _45 125 170 _45 145 _170 29.4803 _88.6381 _118.118_78.3251 _159.036 _80.7109_70099.7 29840.7 _139.583 _165314 33694 _72.3439 1174.84 _154147 _161.503 60175.8 42213.1 37.2989
publicclassAngleDifference{publicstaticdoublegetDifference(doubleb1,doubleb2){doubler=(b2-b1)%360.0;if(r<-180.0)r+=360.0;if(r>=180.0)r-=360.0;returnr;}publicstaticvoidmain(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));}}
Input in -180 to +180 range25.090.0175.0-175.0170.0-170.0170.0-170.0-118.1184-80.7109Input in wider range-139.58328312338563-72.34391851868713-161.5029523074044837.29885558826936
This approach should be reliable but it is also very inefficient.
functionrelativeBearing(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.)returnMath.acos(dotp);return-Math.acos(dotp);}functiontest(){vardeg2rad=3.14159265/180.0;varrad2deg=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";}
Input in -180 to +180 range25.00000000000000490174.99999999999997-175.00000041135993170.00000000000003-170.00000041135996-118.1184-80.71089999999998Input in wider range-139.5833974814558-72.34414600076728-161.5027750112703337.2988761562732
(()=>{"use strict";// ------ ANGLE DIFFERENCE BETWEEN TWO BEARINGS ------// bearingDelta :: Radians -> Radians -> RadiansconstbearingDelta=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 ?constsign=((ay*bx)-(by*ax))>0?(+1):-1;// Sign * dot-product.returnsign*acos((ax*bx)+(ay*by));};// ---------------------- TEST -----------------------// main :: IO ()constmain=()=>[[20,45],[-45,45],[-85,90],[-95,90],[-45,125],[-45,145]].map(xy=>showMap(...xy)).join("\n");// ------------------- FORMATTING --------------------// showMap :: Degrees -> Degrees -> StringconstshowMap=(da,db)=>{constdelta=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 -> FloatconstradiansFromDegrees=n=>Pi*n/180.0;// degreesFromRadians :: Float -> FloatconstdegreesFromRadians=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 ---returnmain();})();
20° + 45° -> 25.00°-45° + 45° -> 90.00°-85° + 90° -> 175.0°-95° + 90° -> -175.0°-45° + 125° -> 170.0°-45° + 145° -> -170.0°
/* Angle difference between bearings, in Jsish */functionangleDifference(bearing1:number,bearing2:number):number{varangle=(bearing2-bearing1)%360;if(angle<-180)angle+=360;if(angle>=180)angle-=360;returnangle;}if(Interp.conf('unitTest')){vardataSet=[[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(vari=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!=*/
prompt$ jsish -u angleDifference.jsi[PASS] angleDifference.jsi
Works with gojq, the Go implementation of jq
Note that the `%` operator in jq produces integral results.
# Angles are in degrees; the result is rounded to 4 decimal places:def subtract($b1; $b2): 10000 as $scale | (($scale * ($b2 - $b1)) % (360 * $scale)) | round / $scale | if . < -180 then . + 360 elif . >= 180 then . - 360 else . end; def pairs: [ 20, 45], [-45, 45], [-85, 90], [-95, 90], [-45, 125], [-45, 145], [ 29.4803, -88.6381], [-78.3251, -159.036], [-70099.74233810938, 29840.67437876723], [-165313.6666297357, 33693.9894517456], [1174.8380510598456, -154146.66490124757], [60175.77306795546, 42213.07192354373] ;"Differences (to 4dp) between these bearings:",( pairs as [$p0, $p1] | subtract($p0; $p1) as $diff | (if $p0 < 0 then " " else " " end) as $offset | "\($offset)\($p0) and \($p1) -> \($diff)" )
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
usingPrintffunctionangdiff(a,b)r=(b-a)%360.0ifr≥180.0r-=360.0endreturnrendprintln("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))endprintln("\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
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.7Input 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
/ Angle difference between two angles/ angledif.kangdif:{[b1;b2];:[(r:(b2-b1)!360.0)<-180.0;r+:360.0;r>180.0;r-:360.0];:r}
The output of a session is given below:
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
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 bearing29.4803 -88.6381 bearing-78.3251 -159.036 bearing-70099.74233810938 29840.67437876723 bearing-165313.6666297357 33693.9894517456 bearing1174.8380510598456 -154146.66490124757 bearing60175.77306795546 42213.07192354373 bearingpstack" " input
(-25, -90, -175, 175, -170, 170, 118.118, 80.7109, 139.583, 72.3439, 161.503, -37.2989)
// version 1.1.2classAngle(d:Double){valvalue=when{din-180.0..180.0->dd>180.0->(d-180.0)%360.0-180.0else->(d+180.0)%360.0+180.0}operatorfunminus(other:Angle)=Angle(this.value-other.value)}funmain(args:Array<String>){valanglePairs=arrayOf(20.0to45.0,-45.0to45.0,-85.0to90.0,-95.0to90.0,-45.0to125.0,-45.0to145.0,29.4803to-88.6381,-78.3251to-159.036,-70099.74233810938to29840.67437876723,-165313.6666297357to33693.9894517456,1174.8380510598456to-154146.66490124757,60175.77306795546to42213.07192354373)println(" b1 b2 diff")valf="% 12.4f % 12.4f % 12.4f"for(apinanglePairs){valdiff=Angle(ap.second)-Angle(ap.first)println(f.format(ap.first,ap.second,diff.value))}}
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
Each bearing will be stored in an object that inherits methods to accomplish all parts of the task: accept a new number of degrees, automatically adjusting to the range [-180, 180]; construct new bearing objects; subtract another bearing from itself and return the difference; construct a list of new bearing objects given a list of arbitrary degree sizes; and format the number of degrees into a modest human-readable format. Bearings will be zero-initialized by default if no degree size is provided.
bearing={degrees=0}-- prototype objectfunctionbearing:assign(angle)angle=tonumber(angle)or0whileangle>180doangle=angle-360endwhileangle<-180doangle=angle+360endself.degrees=angleendfunctionbearing:new(size)localchild_object={}setmetatable(child_object,{__index=self})child_object:assign(size)returnchild_objectendfunctionbearing:subtract(other)localdifference=self.degrees-other.degreesreturnself:new(difference)endfunctionbearing:list(sizes)localbearings={}forindex,sizeinipairs(sizes)dotable.insert(bearings,self:new(size))endreturnbearingsendfunctionbearing:text()returnstring.format("%.4f deg",self.degrees)endfunctionmain()localsubtrahends=bearing:list{20,-45,-85,-95,-45,-45,29.4803,-78.3251,-70099.74233810938,-165313.6666297357,1174.8380510598456,60175.77306795546}localminuends=bearing:list{45,45,90,90,125,145,-88.6381,-159.036,29840.67437876723,33693.9894517456,-154146.66490124757,42213.07192354373}forindex=1,#minuendsdolocalb2,b1=minuends[index],subtrahends[index]localb3=b2:subtract(b1)localstatement=string.format("%s - %s = %s\n",b2:text(),b1:text(),b3:text())io.write(statement)endendmain()
45.0000 deg - 20.0000 deg = 25.0000 deg45.0000 deg - -45.0000 deg = 90.0000 deg90.0000 deg - -85.0000 deg = 175.0000 deg90.0000 deg - -95.0000 deg = -175.0000 deg125.0000 deg - -45.0000 deg = 170.0000 deg145.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 deg93.0719 deg - 55.7731 deg = 37.2989 deg
getDiff:=proc(b1,b2)localr:r:=frem(b2-b1,360):ifr>=180thenr:=r-360:fi:returnr:endproc: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)
2590175-175170-170-118.1184-80.7109-139.58328-72.3340-161.503037.29885
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]
2590175-175170-170-118.118-80.7109-139.583-72.3439-161.50337.2989
diff_bearing(b1,b2):=block(r:mod(b2-b1,360),ifr>180thenr-360elser)$test_bearings:[[20,45],[-45,45],[-85,90],[-95,90],[-45,125],[-45,145],[29.4803,-88.6381],[-78.3251,-159.036]]$big_bearings:[[-70099.74233810938,29840.67437876723],[-165313.6666297357,33693.9894517456],[1174.8380510598456,-154146.66490124757],[60175.77306795546,42213.07192354373]]$db_unary(list):=map(lambda([l],apply(diff_bearing,l)),list)$db_unary(test_bearings);db_unary(big_bearings);
[25,90,175,-175,170,-170,-118.11840000000001,-80.71089999999998][-139.58328312338563,-72.34391851868713,-161.50295230740448,37.29885558826936]
FROMTerminalIMPORT*;PROCEDUREWriteRealLn(value:REAL);VARstr:ARRAY[0..16]OFCHAR;BEGINRealToStr(value,str);WriteString(str);WriteLn;ENDWriteRealLn;PROCEDUREAngleDifference(b1,b2:REAL):REAL;VARr:REAL;BEGINr:=(b2-b1);WHILEr<-180.0DOr:=r+360.0;END;WHILEr>=180.0DOr:=r-360.0;END;RETURNr;ENDAngleDifference;BEGINWriteString('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;ENDBearings.
Taken from Racket solution
#!/usr/bin/envnewlisp(define(bearing-bearingheading)(sub(mod(add(mod(subbearingheading)360.0)540.0)360.0)180.0))(bearing-2045)(bearing--4545)(bearing--8590)(bearing--9590)(bearing--45125)(bearing--45145)(bearing-29.4803-88.6381)(bearing--78.3251-159.036)(bearing--70099.7423381093829840.67437876723)(bearing--165313.666629735733693.9894517456)(bearing-1174.8380510598456-154146.66490124757)(bearing-60175.7730679554642213.07192354373))
-25-90-175175-170170118.1183999999999580.71090000000004139.5832831233856372.34391851868713161.50295230740448-37.29885558826936
importmathimportstrutilsprocdelta(b1,b2:float):float=result=(b2-b1)mod360.0ifresult<-180.0:result+=360.0elifresult>=180.0:result-=360.0lettestVectors: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)]forvectorintestVectors:echovector.b1.formatFloat(ffDecimal,2).align(13)&vector.b2.formatFloat(ffDecimal,2).align(13)&delta(vector.b1,vector.b2).formatFloat(ffDecimal,2).align(13)
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
module mainimports native.io.output.sayfunct get_difference(b1:Float,b2:Float):Float=var r:Float=(b2-b1)%360.0doif r< -180.0 r=r+360.0doif r>=180.0 r=r-360.0yield rreturnsay("Input in -180 to +180 range")say(get_difference(20.0,45.0))say(get_difference(-45.0,45.0))say(get_difference(-85.0,90.0))say(get_difference(-95.0,90.0))say(get_difference(-45.0,125.0))say(get_difference(-45.0,145.0))say(get_difference(-45.0,125.0))say(get_difference(-45.0,145.0))say(get_difference(29.4803,-88.6381))say(get_difference(-78.3251,-159.036))say("Input in wider range")say(get_difference(-70099.74233810938,29840.67437876723))say(get_difference(-165313.6666297357,33693.9894517456))say(get_difference(1174.8380510598456,-154146.66490124757))say(get_difference(60175.77306795546,42213.07192354373))endInput in -180 to +180 range25.090.0175.0-175.0170.0-170.0170.0-170.0-118.1184-80.7109Input in wider range-139.58328312339-72.3439185187-161.502952307415637.29885558827
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; }}Input in -180 to +180 range2590175-175170-170170-170-118.118-80.7109Input in wider range-139.583-72.3439-161.50337.2989
letget_diffb1b2=letr=mod_float(b2-.b1)360.0inifr<-180.0thenr+.360.0elseifr>=180.0thenr-.360.0elserlet()=print_endline"Input in -180 to +180 range";Printf.printf" %g\n"(get_diff20.045.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_diff29.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_diff1174.8380510598456(-154146.66490124757));Printf.printf" %g\n"(get_diff60175.7730679554642213.07192354373);;;
Input in -180 to +180 range 25 90 175 -175 170 -170 170 -170 -118.118 -80.7109Input in wider range -139.583 -72.3439 -161.503 37.2989
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]])
%1 = [25, 90, 175, -175, 170, -170, -118.11840000000000000000000000000000000, -80.710900000000000000000000000000000000, -139.58328312339000000000000000000000023, -72.343918518700000000000000000000000733, -161.50295230741560000000000000000000000, 37.298855588269999999999999999999999909]
This program is meant to be saved in the same folder as a fileangles.txt containing the input. Each pair of angles to subtract appears on its own line in the input file.
ProgramBearings;{ Reads pairs of angles from a file and subtracts them }ConstfileName='angles.txt';Typedegrees=real;Varsubtrahend,minuend:degrees;angleFile:text;functionSimplify(angle:degrees):degrees;{ Returns an number in the range [-180.0, 180.0] }beginwhileangle>180.0doangle:=angle-360.0;whileangle<-180.0doangle:=angle+360.0;Simplify:=angleend;functionDifference(b1,b2:degrees):degrees;{ Subtracts b1 from b2 and returns a simplified result }beginDifference:=Simplify(b2-b1)end;procedureSubtract(b1,b2:degrees);{ Subtracts b1 from b2 and shows the whole equation onscreen }varb3:degrees;beginb3:=Difference(b1,b2);writeln(b2:20:11,' - ',b1:20:11,' = ',b3:20:11)end;Beginassign(angleFile,fileName);reset(angleFile);whilenoteof(angleFile)dobeginreadln(angleFile,subtrahend,minuend);Subtract(subtrahend,minuend)end;close(angleFile)End.
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.98945174561174.8380510598456 -154146.66490124757 60175.77306795546 42213.07192354373
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
programanglebearings(output);(* Angle difference between two bearings *)functionrmod(x1,x2:real):real;beginrmod:=x1-trunc(x1/x2)*x2;end;functiongetdiff(b1,b2:real):real;varr:real;beginr:=rmod((b2-b1),360.0);ifr>=180.0thenr:=r-360.0;ifr<-180.0thenr:=r+360.0;getdiff:=r;end;procedurewriterow(b1,b2:real);beginwriteln(b1:14,' ',b2:14,' ',getdiff(b1,b2):14);end;beginwriteln('Input in -180 to +180 range');writeln(' Bearing 1 Bearing 2 Difference');writerow(20.0,45.0);writerow(-45.0,45.0);writerow(-85.0,90.0);writerow(-95.0,90.0);writerow(-45.0,125.0);writerow(-45.0,145.0);writerow(-45.0,125.0);writerow(-45.0,145.0);writerow(29.4803,-88.6381);writerow(-78.3251,-159.036);writeln;writeln('Input in wider range');writeln(' Bearing 1 Bearing 2 Difference');writerow(-70099.74233810938,29840.67437876723);writerow(-165313.6666297357,33693.9894517456);writerow(1174.8380510598456,-154146.66490124757);writerow(60175.77306795546,42213.07192354373)end.
Input in -180 to +180 range Bearing 1 Bearing 2 Difference 2.0000000e+01 4.5000000e+01 2.5000000e+01-4.5000000e+01 4.5000000e+01 9.0000000e+01-8.5000000e+01 9.0000000e+01 1.7500000e+02-9.5000000e+01 9.0000000e+01 -1.7500000e+02-4.5000000e+01 1.2500000e+02 1.7000000e+02-4.5000000e+01 1.4500000e+02 -1.7000000e+02-4.5000000e+01 1.2500000e+02 1.7000000e+02-4.5000000e+01 1.4500000e+02 -1.7000000e+02 2.9480300e+01 -8.8638100e+01 -1.1811840e+02-7.8325100e+01 -1.5903600e+02 -8.0710900e+01Input in wider range Bearing 1 Bearing 2 Difference-7.0099742e+04 2.9840674e+04 -1.3958328e+02-1.6531367e+05 3.3693989e+04 -7.2343919e+01 1.1748381e+03 -1.5414666e+05 -1.6150295e+02 6.0175773e+04 4.2213072e+04 3.7298856e+01
functiondelta(b1,b2:real):real;beginresult:=(b2-b1)-Trunc((b2-b1)/360.0)*360.0;ifresult<-180.0thenresult+=360.0elseifresult>=180.0thenresult-=360.0end;beginvartestVectors:=|(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)|;foreachvarvectorintestVectorsdowriteln(vector[0]:10:2,vector[1]:12:2,delta(vector[0],vector[1]):10:2);end.
Perl's built-in modulo is integer-only, so import a suitable one from thePOSIX core module
usePOSIX'fmod';subangle{my($b1,$b2)=@_;my$b=fmod(($b2-$b1+720),360);$b-=360if$b>180;$b+=360if$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);}
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
functiontz(atoma)-- trim trailing zeroes and decimal pointstringres=sprintf("%16f",a)fori=length(res)to1by-1dointegerch=res[i]ifch='0'orch='.'thenres[i]=' 'endififch!='0'thenexitendifendforreturnresendfunctionproceduretest(atomb1,b2)atomdiff=mod(b2-b1,360)diff-=iff(diff>180?360:0)printf(1,"%s %s %s\n",{tz(b1),tz(b2),tz(diff)})endprocedureputs(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)
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
include ..\Utilitys.pmt( "16" 1 "16" 1 "16" ) var aldef difAngle /# b1 b2 -- diff #/ swap - 360 mod dup 180 > if 360 - endifenddefdef 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 test29.4803 -88.6381 test-78.3251 -159.036 test-70099.74233810938 29840.67437876723 test-165313.6666297357 33693.9894517456 test1174.8380510598456 -154146.66490124757 test60175.77306795546 42213.07192354373 test
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.3439185186871174.83805105984 -154146.66490124 -161.5029523074060175.7730679554 42213.0719235437 37.2988555882693=== Press any key to exit ===
<?php// Angle difference between two bearingsfunctionget_diff($b1,$b2){$r=($b2-$b1)-intdiv($b2-$b1,360)*360;if($r>180.0)$r-=360.0;if($r<-180.0)$r+=360.0;return$r;}functionecho_row($b1,$b2){echostr_pad(number_format($b1,6,".",""),14," ",STR_PAD_LEFT).' ';echostr_pad(number_format($b2,6,".",""),14," ",STR_PAD_LEFT).' ';echostr_pad(number_format(get_diff($b1,$b2),6),14," ",STR_PAD_LEFT);echo"\n";}echo"Input in -180 to +180 range\n";echo" Bearing 1 Bearing 2 Difference\n";echo_row(20.0,45.0);echo_row(-45.0,45.0);echo_row(-85.0,90.0);echo_row(-95.0,90.0);echo_row(-45.0,125.0);echo_row(-45.0,145.0);echo_row(-45.0,125.0);echo_row(-45.0,145.0);echo_row(29.4803,-88.6381);echo_row(-78.3251,-159.036);echo"\nInput in wider range\n";echo" Bearing 1 Bearing 2 Difference\n";echo_row(-70099.74233810938,29840.67437876723);echo_row(-165313.6666297357,33693.9894517456);echo_row(1174.8380510598456,-154146.66490124757);echo_row(60175.77306795546,42213.07192354373);?>
Input in -180 to +180 range Bearing 1 Bearing 2 Difference 20.000000 45.000000 25.000000 -45.000000 45.000000 90.000000 -85.000000 90.000000 175.000000 -95.000000 90.000000 -175.000000 -45.000000 125.000000 170.000000 -45.000000 145.000000 -170.000000 -45.000000 125.000000 170.000000 -45.000000 145.000000 -170.000000 29.480300 -88.638100 -118.118400 -78.325100 -159.036000 -80.710900Input in wider range Bearing 1 Bearing 2 Difference -70099.742338 29840.674379 -139.583283-165313.666630 33693.989452 -72.343919 1174.838051 -154146.664901 -161.502952 60175.773068 42213.071924 37.298856
require"math2"localfunctionsubtract(b1,b2)locald=(b2-b1)%360ifd<-180thend+=360endifd>=180thend-=360endreturnmath.toplaces(d,4)endlocalpairs={{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("Differences (to 4dp) between these bearings:")forpairsaspairdolocal[p1,p2]=pairlocaldiff=subtract(p1,p2)localoffset=p1<0?" ":" "print($"{offset}{p1} and {p2} -> {diff}")end
Differences (to 4dp) between these bearings: 20 and 45 -> 25.0 -45 and 45 -> 90.0 -85 and 90 -> 175.0 -95 and 90 -> -175.0 -45 and 125 -> 170.0 -45 and 145 -> -170.0 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
This implementation takes two user inputs withGet-AngleDiff or prints the examples withGet-Examples. There is also a full help file accessed by typingGet-Help Get-AngleDiff -full
<#.Synopsis Gets the difference between two angles between the values of -180 and 180. To see examples use "Get-Examples".DESCRIPTION This code uses the modulo operator, this is represented with the "%". The modulo operator returns the remainder after division, as displayed below 3 % 2 = 1 20 % 15 = 5 200 % 146 = 54.EXAMPLE PS C:\WINDOWS\system32> Get-AngleDiff cmdlet Get-AngleDiff at command pipeline position 1 Supply values for the following parameters: angle1: 45 angle2: -85 The difference between 45 and -85 is -130 PS C:\WINDOWS\system32>.EXAMPLE PS C:\WINDOWS\system32> Get-AngleDiff -angle1 50 -angle2 -65 The difference between 50 and -65 is -115 PS C:\WINDOWS\system32>.EXAMPLE PS C:\WINDOWS\system32> Get-AngleDiff -89 50 The difference between -89 and 50 is 139 PS C:\WINDOWS\system32>#>functionGet-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 rangeif($Difference-lt-180.0){$Difference+=360.0}elseif($Difference-gt360.0){$Difference-=360.0}#Writes the values given by the user and the resultWrite-Host"The difference between $angle1 and $angle2 is $Difference"}End{}}<#.Synopsis This is simply the outputs of the Get-AngleDiff Function in a function.EXAMPLEPS C:\WINDOWS\system32> Get-ExamplesInputs from the -180 to 180 rangeThe difference between 20 and 45 is 25The difference between -45 and 45 is 90The difference between -85 and 90 is 175The difference between -95 and 90 is 185The difference between -45 and 125 is 170The difference between -45 and 145 is 190The difference between -45 and 125 is 170The difference between -45 and 145 is 190The difference between 29.4803 and -88.6381 is -118.1184The difference between -78.3251 and -159.036 is -80.7109Inputs from a wider rangeThe difference between -70099.7423381094 and 29840.6743787672 is 220.416716876614The difference between -165313.666629736 and 33693.9894517456 is 287.656081481313The difference between 1174.83805105985 and -154146.664901248 is -161.502952307404The difference between 60175.7730679555 and 42213.0719235437 is 37.2988555882694PS C:\WINDOWS\system32>#>functionGet-Examples{#blank write-host is used for a blank line to make the output look a lil cleanerWrite-HostWrite-Host"Inputs from the -180 to 180 range"Get-AngleDiff20.045.0Get-AngleDiff-45.045.0Get-AngleDiff-85.090.0Get-AngleDiff-95.090.0Get-AngleDiff-45.0125.0Get-AngleDiff-45.0145.0Get-AngleDiff-45.0125.0Get-AngleDiff-45.0145.0Get-AngleDiff29.4803-88.6381Get-AngleDiff-78.3251-159.036Write-HostWrite-Host"Inputs from a wider range"Get-AngleDiff-70099.7423381093829840.67437876723Get-AngleDiff-165313.666629735733693.9894517456Get-AngleDiff1174.8380510598456-154146.66490124757Get-AngleDiff60175.7730679554642213.07192354373}
Results of user inputs
using -45 and 98 withGet-AngleDiff:
PSC:\WINDOWS\system32>Get-AngleDiff-4598Thedifferencebetween-45and98is143
Results ofGet-Examples
PS C:\WINDOWS\system32> Get-ExamplesInputs from the -180 to 180 rangeThe difference between 20 and 45 is 25The difference between -45 and 45 is 90The difference between -85 and 90 is 175The difference between -95 and 90 is 185The difference between -45 and 125 is 170The difference between -45 and 145 is 190The difference between -45 and 125 is 170The difference between -45 and 145 is 190The difference between 29.4803 and -88.6381 is -118.1184The difference between -78.3251 and -159.036 is -80.7109Inputs from a wider rangeThe difference between -70099.7423381094 and 29840.6743787672 is 220.416716876614The difference between -165313.666629736 and 33693.9894517456 is 287.656081481313The difference between 1174.83805105985 and -154146.664901248 is -161.502952307404The difference between 60175.7730679555 and 42213.0719235437 is 37.2988555882694
In "traditional" algorithmic style.
# Angle difference between two bearingsfunctionGet-Diff([double]$B1,[double]$B2){$r=($B2-$B1)%360.0if($r-lt-180.0){$r+=360.0}if($r-ge180.0){$r-=360.0}return[double]$r}functionWrite-Row([double]$B1,[double]$B2){[string]$out="$($B1.ToString('#######.000000').PadLeft(14,' '))"$out+="$($B2.ToString('#######.000000').PadLeft(14,' '))"$out+="$((Get-Diff$B1$B2).ToString('#######.000000').PadLeft(14,' '))"Write-Output$out}Write-Output"Input in -180 to +180 range"Write-Output" Bearing 1 Bearing 2 Difference"Write-Row20.045.0Write-Row-45.045.0Write-Row-85.090.0Write-Row-95.090.0Write-Row-45.0125.0Write-Row-45.0145.0Write-Row-45.0125.0Write-Row-45.0145.0Write-Row29.4803-88.6381Write-Row-78.3251-159.036Write-Output""Write-Output"Input in wider range"Write-Output" Bearing 1 Bearing 2 Difference"Write-Row-70099.7423381093829840.67437876723Write-Row-165313.666629735733693.9894517456Write-Row1174.8380510598456-154146.66490124757Write-Row60175.7730679554642213.07192354373
Format of numbers (decimal comma or dot) depends on a culture settings.
Input in -180 to +180 range Bearing 1 Bearing 2 Difference 20,000000 45,000000 25,000000 -45,000000 45,000000 90,000000 -85,000000 90,000000 175,000000 -95,000000 90,000000 -175,000000 -45,000000 125,000000 170,000000 -45,000000 145,000000 -170,000000 -45,000000 125,000000 170,000000 -45,000000 145,000000 -170,000000 29,480300 -88,638100 -118,118400 -78,325100 -159,036000 -80,710900Input in wider range Bearing 1 Bearing 2 Difference -70099,742338 29840,674379 -139,583283-165313,666630 33693,989452 -72,343919 1174,838051 -154146,664901 -161,502952 60175,773068 42213,071924 37,298856
from__future__importprint_functiondefgetDifference(b1,b2):r=(b2-b1)%360.0# Python modulus has same sign as divisor, which is positive here,# so no need to consider negative caseifr>=180.0:r-=360.0returnrif__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))
Input in -180 to +180 range25.090.0175.0-175.0170.0-170.0170.0-170.0-118.11840000000001-80.71089999999998Input in wider range-139.58328312338563-72.34391851868713-161.5029523074044837.29885558826936
Or, generalising a little by deriving the degrees from a (Radians -> Radians) function, and formatting the output in columns:
'''Difference between two bearings'''frommathimport(acos,cos,pi,sin)# bearingDelta :: Radians -> Radians -> RadiansdefbearingDelta(ar):'''Difference between two bearings, expressed in radians.'''defgo(br):[(ax,ay),(bx,by)]=[(sin(x),cos(x))forxin[ar,br]]# cross-product > 0 ?sign=+1if0<((ay*bx)-(by*ax))else-1# sign * dot-productreturnsign*acos((ax*bx)+(ay*by))returnlambdabr:go(br)# TEST ----------------------------------------------------# main :: IO ()defmain():'''Test and display'''# showMap :: Degrees -> Degrees -> StringdefshowMap(da,db):returnunwords(str(x).rjust(n)forn,xin[(22,str(da)+' +'),(24,str(db)+' -> '),(7,round(degrees(bearingDelta(radians(da))(radians(db))),2))])print(__doc__+':')print(unlines(showMap(a,b)fora,bin[(20,45),(-45,45),(-85,90),(-95,90),(-45,125),(-45,145),(-70099.74233810938,29840.67437876723),(-165313.6666297357,33693.9894517456),(1174.8380510598456,-154146.66490124757),(60175.77306795546,42213.07192354373)]))# GENERIC ----------------------------------------------# radians :: Float x => Degrees x -> Radians xdefradians(x):'''Radians derived from degrees.'''returnpi*x/180# degrees :: Float x => Radians x -> Degrees xdefdegrees(x):'''Degrees derived from radians.'''return180*x/pi# unlines :: [String] -> Stringdefunlines(xs):'''A single newline-delimited string derived from a list of strings.'''return'\n'.join(xs)# unwords :: [String] -> Stringdefunwords(xs):'''A space-separated string derived from a list of words.'''return' '.join(xs)if__name__=='__main__':main()
Difference between two bearings: 20 + 45 -> 25.0 -45 + 45 -> 90.0 -85 + 90 -> 175.0 -95 + 90 -> -175.0 -45 + 125 -> 170.0 -45 + 145 -> -170.0 -70099.74233810938 + 29840.67437876723 -> -139.58 -165313.6666297357 + 33693.9894517456 -> -72.34 1174.8380510598456 + -154146.66490124757 -> -161.5 60175.77306795546 + 42213.07192354373 -> 37.3
Hopefully a lot simpler, elegant and efficient by avoiding conditional statement and trigonometric functions
The table output use print formatting only available from python 3. Tested with 3.6.
"""Difference between two bearings"""defdelta_bearing(b1,b2):return((b2-b1+540)%360)-180dataSet=[[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ΔindataSet:print('|{: > 19}|{: > 19}|{: > 9.4f}|'.format(Δ[0],Δ[1],delta_bearing(Δ[0],Δ[1])))
.------- 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|
Using the Quackery big number rational arithmetic librarybigrat.qky.
[ $ "bigrat.qky" loadfile ] now! [ v- -v proper rot 360 mod unrot improper 180 1 2over v< iff [ 360 1 v- ] done 2dup -180 1 v< if [ 360 1 v+ ] ] is angledelta ( n/d n/d --> n/d ) ' [ [ $ "20" $ "45" ] [ $ "-45" $ "45" ] [ $ "85" $ "90" ] [ $ "-95" $ "90" ] [ $ "-45" $ "125" ] [ $ "45" $ "145" ] [ $ "29.4803" $ "-88.6361" ] [ $ "-78.3251" $ "-159.0360" ] [ $ "-70099.74233810938" $ "29840.67437876723" ] [ $ "-165313.6666297357" $ "33693.9894517456" ] [ $ "1174.8380510598456" $ "-154146.66490124757" ] [ $ "60175.773067955546" $ "42213.07192354373" ] ] witheach [ do dip [ $->v drop ] $->v drop angledelta 20 point$ echo$ cr ]
25905-175170100-118.1164-80.7109-139.58328312339-72.3439185187-161.502952307415637.298855588184
diff_bearing<-function(b1,b2){r<-(b2-b1)%%360ifelse(r>180,r-360,r)}test_bearings<-list(c(20,45),c(-45,45),c(-85,90),c(-95,90),c(-45,125),c(-45,145),c(29.4803,-88.6381),c(-78.3251,-159.036))test_bigbearings<-list(c(-70099.74233810938,29840.67437876723),c(-165313.6666297357,33693.9894517456),c(1174.8380510598456,-154146.66490124757),c(60175.77306795546,42213.07192354373))db_unary<-function(v)do.call(diff_bearing,as.list(v))sapply(test_bearings,db_unary)sapply(test_bigbearings,db_unary)
[1] 25.0000 90.0000 175.0000 -175.0000 170.0000 -170.0000 -118.1184 -80.7109[1] -139.58328 -72.34392 -161.50295 37.29886
see my comments in discussion regards bearing-heading or vice versa
#langracket(define(%ab)(-a(*b(truncate(/ab)))))(define(bearing-bearingheading)(-(%(+(%(-bearingheading)360)540)360)180))(module+main(bearing-2045)(bearing--4545)(bearing--8590)(bearing--9590)(bearing--45125)(bearing--45145)(bearing-29.4803-88.6381)(bearing--78.3251-159.036)(bearing--70099.7423381093829840.67437876723)(bearing--165313.666629735733693.9894517456)(bearing-1174.8380510598456-154146.66490124757)(bearing-60175.7730679554642213.07192354373))(module+test(requirerackunit)(check-equal?(%7.510)7.5)(check-equal?(%17.510)7.5)(check-equal?(%-7.510)-7.5)(check-equal?(%-17.510)-7.5))
-25-90-175175-170170118.1183999999999580.71090000000004139.5832831233856372.34391851868713161.50295230740448-37.29885558826936
(formerly Perl 6)
subinfix:<∠> (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 }
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
anglediff:func[b1b2/localr][r:mod(b2- b1)360eitherr>=180[r-360][r]]b1:180b2:-180test-list:[[2045][-4545][-8590][-9590][-45125][-45145][29.4803-88.6381][-78.3251-159.036]]foreachtest-casetest-list[b1:test-case/1b2:test-case/2print["b1 : "b1" b2 : "b2"angle diff b2 - b1 : "(anglediffb1 b2)]]
Some extra coding was added for a better visual presentation; the angles were centered, the answers were aligned.
/*REXX pgm calculates difference between two angles (in degrees), normalizes the result.*/numericdigits25/*use enough dec. digits for angles*/callshow20,45/*display angular difference (deg).*/callshow-45,45/* " " " " */callshow-85,90/* " " " " */callshow-95,90/* " " " " */callshow-45,125/* " " " " */callshow45,145/* " " " " */callshow29.4803,-88.6361/* " " " " */callshow-78.3251,-159.036/* " " " " */callshow-70099.74233810938,29840.67437876723/* " " " " */callshow-165313.6666297357,33693.9894517456/* " " " " */callshow1174.8380510598456,-154146.66490124757/* " " " " */callshow60175.773067955546,42213.07192354373/* " " " " */exit/*stick a fork in it, we're done. *//*──────────────────────────────────────────────────────────────────────────────────────*/show:parsearga,b;d=digits();$='º'/*obtain the 2 angles (are in degrees).*/x=format(((((b-a)//360)+540)//360)-180,4,d)/*compute and format. */ifpos(.,x)\==0thenx=strip(strip(x,'T',0),"T",.)/*strip trailing chaff.*/saycenter(a||$,d)'─'center(b||$,d)" ────► "x||$return/* [↑] display the angular difference.*/
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º
# Project : Angle difference between two bearingsdecimals(4)see "Input in -180 to +180 range:" + nlsee getDifference(20.0, 45.0) + nlsee getDifference(-45.0, 45.0) + nlsee getDifference(-85.0, 90.0) + nlsee getDifference(-95.0, 90.0) + nlsee getDifference(-45.0, 125.0) + nlsee getDifference(-45.0, 145.0) + nlsee getDifference(-45.0, 125.0) + nlsee getDifference(-45.0, 145.0) + nlsee getDifference(29.4803, -88.6381) + nlsee getDifference(-78.3251, -159.036) + nl func getDifference(b1, b2) r = (b2 - b1) % 360.0 if r >= 180.0 r = r - 360.0 end return r
Output:
Input in -180 to +180 range:2590175-175170-170170-170-118.1184-80.7109
≪ SWAP - 360 MODIF DUP 180 >THEN 360 -END ≫ 'BDIFF' STO
20 45 BDIFF-45 45 BDIFF-85 90 BDIFF-95 90 BDIFF-45 125 BDIFF-45 145 BDIFF29.4803 -88.6381 BDIFF-78.3251 -159.036 BDIFF
8: 257: 906 1755: -1754: 1703: -1702: -118.11841: -80.7109
defgetDifference(b1,b2)r=(b2-b1)%360.0# Ruby modulus has same sign as divisor, which is positive here,# so no need to consider negative caseifr>=180.0r-=360.0endreturnrendif__FILE__==$PROGRAM_NAMEputs"Input in -180 to +180 range"putsgetDifference(20.0,45.0)putsgetDifference(-45.0,45.0)putsgetDifference(-85.0,90.0)putsgetDifference(-95.0,90.0)putsgetDifference(-45.0,125.0)putsgetDifference(-45.0,145.0)putsgetDifference(-45.0,125.0)putsgetDifference(-45.0,145.0)putsgetDifference(29.4803,-88.6381)putsgetDifference(-78.3251,-159.036)puts"Input in wider range"putsgetDifference(-70099.74233810938,29840.67437876723)putsgetDifference(-165313.6666297357,33693.9894517456)putsgetDifference(1174.8380510598456,-154146.66490124757)putsgetDifference(60175.77306795546,42213.07192354373)end
Input in -180 to +180 range25.090.0175.0-175.0170.0-170.0170.0-170.0-118.11840000000001-80.71089999999998Input in wider range-139.58328312338563-72.34391851868713-161.5029523074044837.29885558826936
/// Calculate difference between two bearings, in -180 to 180 degrees rangepubfnangle_difference(bearing1:f64,bearing2:f64)->f64{letdiff=(bearing2-bearing1)%360.0;ifdiff<-180.0{360.0+diff}elseifdiff>180.0{-360.0+diff}else{diff}}#[cfg(test)]modtests{usesuper::*;#[test]fntest_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-cmpfnapprox_eq(f1:f64,f2:f64){assert!((f2-f1).abs()<0.0001,"{} != {}",f1,f2)}}
Best seen running in your browser either byScalaFiddle (ES aka JavaScript, non JVM) orScastie (remote JVM).
objectAngleDifferenceextendsApp{privatedefgetDifference(b1:Double,b2:Double)={valr=(b2-b1)%360.0if(r<-180.0)r+360.0elseif(r>=180.0)r-360.0elser}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))}
R6RS standard.
#!r6rs(import(rnrsbase(6))(rnrsiosimple(6)))(define(bearing-differencebearing-2bearing-1)(-(mod(+(mod(-bearing-2bearing-1)360)540)360)180))(define(bearing-difference-test)(definetest-cases'((2045)(-4545)(-8590)(-9590)(-45125)(-45145)(29.4803-88.6381)(-78.3251-159.036)(-70099.7423381093829840.67437876723)(-165313.666629735733693.9894517456)(1174.8380510598456-154146.66490124757)(60175.7730679554642213.07192354373)))(for-each(lambda(argument-list)(display(applybearing-differenceargument-list))(newline))test-cases))
> (bearing-difference-test)-25-90-175175-170170118.1183999999999580.71090000000004139.5832831233856372.34391851868713161.50295230740448-37.29885558826936
The libraryfloat.s7i supports theoperatormod,which can be used to solve this task easily.
$ include "seed7_05.s7i"; include "float.s7i";const func float: getDifference (in float: b1, in float: b2) is func result var float: difference is 0.0; begin difference := (b2 - b1) mod 360.0; if difference > 180.0 then difference -:= 360.0; end if; end func;const proc: main is func begin writeln("Input in -180 to +180 range"); writeln(getDifference(20.0, 45.0)); writeln(getDifference(-45.0, 45.0)); writeln(getDifference(-85.0, 90.0)); writeln(getDifference(-95.0, 90.0)); writeln(getDifference(-45.0, 125.0)); writeln(getDifference(-45.0, 145.0)); writeln(getDifference(-45.0, 125.0)); writeln(getDifference(-45.0, 145.0)); writeln(getDifference(29.4803, -88.6381)); writeln(getDifference(-78.3251, -159.036)); writeln("Input in wider range"); writeln(getDifference(-70099.74233810938, 29840.67437876723)); writeln(getDifference(-165313.6666297357, 33693.9894517456)); writeln(getDifference(1174.8380510598456, -154146.66490124757)); writeln(getDifference(60175.77306795546, 42213.07192354373)); end func;Input in -180 to +180 range25.090.0175.0-175.0170.0-170.0170.0-170.0-118.1184-80.7109Input in wider range-139.583283123386-72.3439185186871-161.50295230740437.2988555882694
funcbearingAngleDiff(b1,b2){(varb=((b2-b1+720)%360))>180?(b-360):b}printf("%25s %25s %25s\n","B1","B2","Difference")printf("%25s %25s %25s\n","-"*20,"-"*20,"-"*20)forb1,b2in([20,45-45,45-85,90-95,90-45,125-45,14529.4803,-88.6381-78.3251,-159.036-70099.74233810938,29840.67437876723-165313.6666297357,33693.98945174561174.8380510598456,-154146.6649012475760175.77306795546,42213.07192354373].slices(2)){printf("%25s %25s %25s\n",b1,b2,bearingAngleDiff(b1,b2))}
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
funcangleDifference(a1:Double,a2:Double)->Double{letdiff=(a2-a1).truncatingRemainder(dividingBy:360)ifdiff<-180.0{return360.0+diff}elseifdiff>180.0{return-360.0+diff}else{returndiff}}lettestCases=[(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))
[25.0, 90.0, 175.0, -175.0, 170.0, -170.0, -118.1184, -80.7109, -139.58328312338563, -72.34391851868713, -161.50295230740448, 37.29885558826936]
procangleDiff{b1b2}{setangle[::tcl::mathfunc::fmod[expr($b2-$b1)]360]if{$angle<-180.0}{setangle[expr$angle+360.0]}if{$angle>=180.0}{setangle[expr$angle-360.0]}return$angle}puts"Input in -180 to +180 range"puts[angleDiff20.045.0]puts[angleDiff-45.045.0]puts[angleDiff-85.090.0]puts[angleDiff-95.090.0]puts[angleDiff-45.0125.0]puts[angleDiff-45.0145.0]puts[angleDiff-45.0125.0]puts[angleDiff-45.0145.0]puts[angleDiff29.4803-88.6381]puts[angleDiff-78.3251-159.036]puts"Input in wider range"puts[angleDiff-70099.7423381093829840.67437876723]puts[angleDiff-165313.666629735733693.9894517456]puts[angleDiff1174.8380510598456-154146.66490124757]puts[angleDiff60175.7730679554642213.07192354373]
Input in -180 to +180 range25.090.0175.0-175.0170.0-170.0170.0-170.0-118.1184-80.7109Input in wider range-139.58328312338563-72.34391851868713-161.5029523074044837.29885558826936
Truncated inputs to 4 d.p. and outputs to 3 d.p. as we're not flying cruise missiles here.
Wrap ← ◌◌⍢(⊙⟜+|<⊙⋅∘)⊙◌⊢⟜(⍢(⊙⟜-|>⊙⋅∘)⊣)⟜/-Diff ← Wrap [¯180 180]/-[20_45 ¯45_45 ¯85_90 ¯95_90 ¯45_125 ¯45_145 29.4803_¯88.6381 ¯78.3251_¯159.036]≡(⁅₃Diff)[¯70099.7423_29840.6744 ¯165313.6666_33693.9895 1174.8381_¯154146.6649 60175.7731_42213.0719]≡(⁅₃Diff)
[25 90 175 ¯175 170 ¯170 ¯118.118 ¯80.711][¯139.583 ¯72.344 ¯161.503 37.299]
import mathtype 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}25.25.9090175.175.-175.-175.170170-170-170-118.1184-118.11840000000001-80.7109-80.71089999999998
varsubtract=Fn.new{|b1,b2|vard=(b2-b1)%360if(d<-180)d=d+360if(d>=180)d=d-360return(d*10000).round/10000// to 4dp}varpairs=[[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(pairinpairs){varp0=pair[0]varp1=pair[1]vardiff=subtract.call(p0,p1)varoffset=(p0<0)?" ":" "System.print("%(offset)%(p0) and%(p1) ->%(diff)")}
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
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());}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°
Pairs of bearing angles are input from the console or from a file(terminated with Ctrl+C) redirected on the command line.
real B1, B2, Ang;[Text(0, " Bearing 1 Bearing 2 Difference");loop [B1:= RlIn(1); B2:= RlIn(1); Ang:= B2 - B1; while Ang > 180. do Ang:= Ang - 360.; while Ang < -180. do Ang:= Ang + 360.; CrLf(0); RlOut(0, B1); ChOut(0, 9); RlOut(0, B2); ChOut(0, 9); RlOut(0, Ang); ];]
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.5029560175.77307 42213.07192 37.29886
fcn bearingAngleDiff(b1,b2){ // -->Float, b1,b2 can be int or float ( (b:=(0.0 + b2 - b1 + 720)%360) > 180 ) and b - 360 or b;}T( 20,45, -45,45, -85,90, -95,90, -45,125, -45,145 ).pump(Console.println,Void.Read, fcn(b1,b2){ "%.1f\UB0; + %.1f\UB0; = %.1f\UB0;" .fmt(b1,b2,bearingAngleDiff(b1,b2)) });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