//Input variables (Assumptions: massless pivot, no energy loss)
bob_mass=10;
g=-9.81;
L=2;
theta0=-%pi/6;
v0=0;
t0=0;

//No. of steps
steps=300;

//Setting deltaT or duration (comment either of the lines below)
//deltaT=0.1; t_max=t0+deltaT*steps;
t_max=5; deltaT=(t_max-t0)/steps;

if t_max<=t0 then
    error("Check duration (t0 and t_f), number of steps and deltaT.");
end

//Initial position
not_a_pendulum=%F;
t=zeros(1,steps); t(1)=t0;                      //time
theta=zeros(1,steps); theta(1)=theta0;          //angle
F=zeros(1,steps); F(1)=bob_mass*g*sin(theta0);  //force
A=zeros(1,steps); A(1)=F(1)/bob_mass;           //acceleration
V=zeros(1,steps); V(1)=v0;                      //linear speed
W=zeros(1,steps); W(1)=v0/L;                    //angular speed

for i=2:steps
    t(i)=t(i-1)+deltaT;
    V(i)=A(i-1)*deltaT+V(i-1);
    W(i)=V(i)/L;
    theta(i)=theta(i-1)+W(i)*deltaT;
    F(i)=bob_mass*g*sin(theta(i));
    A(i)=F(i)/bob_mass;
    if (abs(theta(i))>=%pi | (abs(theta(i))==0 & V(i)==0)) & ~not_a_pendulum  then
        disp("Initial conditions do not describe a pendulum.");
        not_a_pendulum = %T;
    end
end
clear i

//Ploting the pendulum
bob_r=0.08*L;
bob_shape=bob_r*exp(%i.*linspace(0,360,20)/180*%pi);

bob_pos=zeros(20,steps);
rod_pos=zeros(1,steps);
for i=1:steps
    rod_pos(i)=L*exp(%i*(-%pi/2+theta(i)));
    bob_pos(:,i)=bob_shape'+rod_pos(i);
end
clear i

scf(0); clf(); xname("Simple gravity pendulum");
plot2d(real([0 rod_pos(1)]),imag([0 rod_pos(1)]));
axes=gca();
axes.isoview="on";
axes.children(1).children.mark_style=3;
axes.children(1).children.mark_size=1;
axes.children(1).children.thickness=3;

plot2d(real(bob_pos(:,1)),imag(bob_pos(:,1)));
axes=gca();
axes.children(1).children.fill_mode="on";
axes.children(1).children.foreground=2;
axes.children(1).children.background=2;

if max(imag(bob_pos))>0 then
    axes.data_bounds=[-L-bob_r,-L-1.01*bob_r;L+bob_r,max(imag(bob_pos))];
else
    axes.data_bounds=[-L-bob_r,-L-1.01*bob_r;L+bob_r,bob_r];
end

//Animating the plot
disp("Duration: "+string(max(t)+deltaT-t0)+"s.");
sleep(850);
for i=2:steps
    axes.children(1).children.data=[real(bob_pos(:,i)), imag(bob_pos(:,i))];
    axes.children(2).children.data=[0, 0; real(rod_pos(i)), imag(rod_pos(i))];
    sleep(deltaT*1000)
end
clear i


import <Utilities/Sequence.sl>;
import <Utilities/Conversion.sl>;
import <Utilities/Math.sl>;

//region Types

Point ::= (x: int(0), y: int(0));
Color ::= (red: int(0), green: int(0), blue: int(0));
Image ::= (kind: char(1), iColor: Color(0), vert1: Point(0), vert2: Point(0), vert3: Point(0), center: Point(0),
           radius: int(0), height: int(0), width: int(0), message: char(1), source: char(1));
Click ::= (clicked: bool(0), clPoint: Point(0));
Input ::= (iClick: Click(0), keys: char(1));

//endregion

//region Helpers======================================================================
//region Constructor-Functions-------------------------------------------------
point(a(0), b(0)) := (x: a, y: b);
color(r(0), g(0), b(0)) := (red: r, green: g, blue: b);
segment(e1(0), e2(0), c(0)) := (kind: "segment", vert1: e1, vert2: e2, iColor: c);
disc(ce(0), rad(0), c(0)) := (kind: "disc", center: ce, radius: rad, iColor: c);
//endregion----------------------------------------------------------------------

//region Colors----------------------------------------------------------------
dBlack := color(0, 0, 0);
dYellow := color(255, 255, 0);
//endregion----------------------------------------------------------------------
//endregion=============================================================================

//=================Easel=Functions=============================================

State ::= (angle: float(0), angleVelocity: float(0), angleAccel: float(0));

initialState := (angle: pi/2, angleVelocity: 0.0, angleAccel: 0.0);

dt := 0.3;
length := 450;

anchor := point(500, 750);

newState(I(0), S(0)) :=
    let
        newAngle := S.angle + newAngleVelocity * dt;
        newAngleVelocity := S.angleVelocity + newAngleAccel * dt;
        newAngleAccel := -9.81 / length * sin(S.angle);
    in
    (angle: newAngle, angleVelocity: newAngleVelocity, angleAccel: newAngleAccel);

sounds(I(0), S(0)) := ["ding"] when I.iClick.clicked else [];

images(S(0)) :=
    let
        pendulum := pendulumLocation(S.angle);
    in
        [segment(anchor, pendulum, dBlack),
         disc(pendulum, 30, dYellow),
         disc(anchor, 5, dBlack)];

pendulumLocation(angle) :=
    let
        x := anchor.x + round(sin(angle) * length);
        y := anchor.y - round(cos(angle) * length);
    in
        point(x, y);

//=============End=Easel=Functions=============================================


require('Tk')

var root = %s<MainWindow>.new('-title' => 'Pendulum Animation')
var canvas = root.Canvas('-width' => 320, '-height' => 200)

canvas.createLine(  0,  25, 320,  25, '-tags' => <plate>,     '-width' => 2, '-fill' => :grey50)
canvas.createOval(155,  20, 165,  30, '-tags' => <pivot outline>,            '-fill' => :grey50)
canvas.createLine(  1,   1,    1,  1, '-tags' => <rod width>, '-width' => 3, '-fill' => :black)
canvas.createOval(  1,   1,    2,  2, '-tags' => <bob outline>,              '-fill' => :yellow)

canvas.raise(:pivot)
canvas.pack('-fill' => :both, '-expand' => 1)
var(θ = 45, Δθ = 0, length = 150, homeX = 160, homeY = 25)

func show_pendulum() {
    var angle = θ.deg2rad
    var x = (homeX + length*sin(angle))
    var y = (homeY + length*cos(angle))
    canvas.coords(:rod, homeX,  homeY,  x,      y)
    canvas.coords(:bob, x - 15, y - 15, x + 15, y + 15)
}

func recompute_angle() {
    var scaling = 3000/(length**2)

    # first estimate
    var firstΔΔθ = (-sin(θ.deg2rad) * scaling)
    var midΔθ    = (Δθ + firstΔΔθ)
    var midθ     = ((Δθ + midΔθ)/2 + θ)

    # second estimate
    var midΔΔθ = (-sin(midθ.deg2rad) * scaling)
    midΔθ      = ((firstΔΔθ + midΔΔθ)/2 + Δθ)
    midθ       = ((Δθ + midΔθ)/2 + θ)

    # again, first
    midΔΔθ     = (-sin(midθ.deg2rad) * scaling)
    var lastΔθ = (midΔθ + midΔΔθ)
    var lastθ  = ((midΔθ + lastΔθ)/2 + midθ)

    # again, second
    var lastΔΔθ = (-sin(lastθ.deg2rad) * scaling)
    lastΔθ      = ((midΔΔθ + lastΔΔθ)/2 + midΔθ)
    lastθ       = ((midΔθ + lastΔθ)/2 + midθ)

    # Now put the values back in our globals
    Δθ = lastΔθ
    θ  = lastθ
}

func animate(Ref id) {
    recompute_angle()
    show_pendulum()
    *id = root.after(15 => { animate(id) })
}

show_pendulum()
var after_id = root.after(500 => { animate(\after_id) })

canvas.bind('<Destroy>' => { after_id.cancel })
%S<Tk>.MainLoop()


'Pendulum
'By Dutchman
' --- constants
g=9.81 ' accelleration of gravity
l=1 ' length of pendulum
GET SCREEN SIZE sw,sh
pivotx=sw/2
pivoty=150
' --- initialise graphics
GRAPHICS
DRAW COLOR 1,0,0
FILL COLOR 0,0,1
DRAW SIZE 2
' --- initialise pendulum
theta=1 ' initial displacement in radians
speed=0
' --- loop
DO
  bobx=pivotx+100*l*SIN(theta)
  boby=pivoty-100*l*COS(theta)
  GOSUB Plot
  PAUSE 0.01
  accel=g*SIN(theta)/l/100
  speed=speed+accel
  theta=theta+speed
UNTIL 0
END
' --- subroutine
Plot:
REFRESH OFF
GRAPHICS CLEAR 1,1,0.5
DRAW LINE pivotx,pivoty TO bobx,boby
FILL CIRCLE bobx,boby SIZE 10
REFRESH ON
RETURN


package require Tcl 8.5
package require Tk

# Make the graphical entities
pack [canvas .c -width 320 -height 200] -fill both -expand 1
.c create line 0 25 320 25 -width 2 -fill grey50 -tags plate
.c create line 1 1 1 1 -tags rod -width 3 -fill black
.c create oval 1 1 2 2 -tags bob -fill yellow -outline black
.c create oval 155 20 165 30 -fill grey50 -outline {} -tags pivot

# Set some vars
set points {}
set Theta   45.0
set dTheta   0.0
set pi       3.1415926535897933
set length 150
set homeX  160

# How to respond to a changing in size of the window
proc resized {width} {
    global homeX
    .c coords plate 0 25 $width 25
    set homeX [expr {$width / 2}]
    .c coords pivot [expr {$homeX-5}] 20 [expr {$homeX+5}] 30
    showPendulum
}

# How to actually arrange the pendulum, mapping the model to the display
proc showPendulum {} {
    global Theta dTheta pi length homeX
    set angle [expr {$Theta * $pi/180}]
    set x [expr {$homeX + $length*sin($angle)}]
    set y [expr {25 + $length*cos($angle)}]
    .c coords rod $homeX 25 $x $y
    .c coords bob [expr {$x-15}] [expr {$y-15}] [expr {$x+15}] [expr {$y+15}]
}

# The dynamic part of the display
proc recomputeAngle {} {
    global Theta dTheta pi length
    set scaling [expr {3000.0/$length**2}]

    # first estimate
    set firstDDTheta [expr {-sin($Theta * $pi/180)*$scaling}]
    set midDTheta [expr {$dTheta + $firstDDTheta}]
    set midTheta [expr {$Theta + ($dTheta + $midDTheta)/2}]
    # second estimate
    set midDDTheta [expr {-sin($midTheta * $pi/180)*$scaling}]
    set midDTheta [expr {$dTheta + ($firstDDTheta + $midDDTheta)/2}]
    set midTheta [expr {$Theta + ($dTheta + $midDTheta)/2}]
    # Now we do a double-estimate approach for getting the final value
    # first estimate
    set midDDTheta [expr {-sin($midTheta * $pi/180)*$scaling}]
    set lastDTheta [expr {$midDTheta + $midDDTheta}]
    set lastTheta [expr {$midTheta + ($midDTheta + $lastDTheta)/2}]
    # second estimate
    set lastDDTheta [expr {-sin($lastTheta * $pi/180)*$scaling}]
    set lastDTheta [expr {$midDTheta + ($midDDTheta + $lastDDTheta)/2}]
    set lastTheta [expr {$midTheta + ($midDTheta + $lastDTheta)/2}]
    # Now put the values back in our globals
    set dTheta $lastDTheta
    set Theta $lastTheta
}

# Run the animation by updating the physical model then the display
proc animate {} {
    global animation

    recomputeAngle
    showPendulum

    # Reschedule
    set animation [after 15 animate]
}
set animation [after 500 animate]; # Extra initial delay is visually pleasing

# Callback to handle resizing of the canvas
bind .c <Configure> {resized %w}
# Callback to stop the animation cleanly when the GUI goes away
bind .c <Destroy> {after cancel $animation}


import "graphics" for Canvas, Color
import "dome" for Window
import "math" for Math
import "./dynamic" for Tuple

var Element = Tuple.create("Element", ["x", "y"])
var Dt = 0.1
var Angle = Num.pi / 2
var AngleVelocity = 0

class Pendulum {
    construct new(length) {
        Window.title = "Pendulum"
        _w = 2 * length + 50
        _h = length / 2 * 3
        Window.resize(_w, _h)
        Canvas.resize(_w, _h)
        _length = length
        _anchor = Element.new((_w/2).floor, (_h/4).floor)
        _fore = Color.black
    }

    init() {
        drawPendulum()
    }

    drawPendulum() {
        Canvas.cls(Color.white)
        var ball = Element.new((_anchor.x + Math.sin(Angle) * _length).truncate,
                               (_anchor.y + Math.cos(Angle) * _length).truncate)
        Canvas.line(_anchor.x, _anchor.y, ball.x, ball.y, _fore, 2)
        Canvas.circlefill(_anchor.x - 3, _anchor.y - 4, 7, Color.lightgray)
        Canvas.circle(_anchor.x - 3, _anchor.y - 4, 7, _fore)
        Canvas.circlefill(ball.x - 7, ball.y - 7, 14, Color.yellow)
        Canvas.circle(ball.x - 7, ball.y - 7, 14, _fore)
    }

    update() {
        AngleVelocity = AngleVelocity - 9.81 / _length * Math.sin(Angle) * Dt
        Angle = Angle + AngleVelocity * Dt
    }

    draw(alpha) {
        drawPendulum()
    }
}

var Game = Pendulum.new(200)


include c:\cxpl\codes;          \intrinsic 'code' declarations

proc    Ball(X0, Y0, R, C);     \Draw a filled circle
int     X0, Y0, R, C;           \center coordinates, radius, color
int     X, Y;
for Y:= -R to R do
    for X:= -R to R do
        if X*X + Y*Y <= R*R then Point(X+X0, Y+Y0, C);

def     L  = 2.0,               \pendulum arm length (meters)
        G  = 9.81,              \acceleration due to gravity (meters/second^2)
        Pi = 3.14,
        DT = 1.0/72.0;          \delta time = screen refresh rate (seconds)
def     X0=640/2, Y0=480/2;     \anchor point = center coordinate
real    S, V, A, T;             \arc length, velocity, acceleration, theta angle
int     X, Y;                   \ball coordinates

[SetVid($101);                  \set 640x480x8 graphic display mode
T:= Pi*0.75;  V:= 0.0;          \starting angle and velocity
S:= T*L;
repeat  A:= -G*Sin(T);
        V:= V + A*DT;
        S:= S + V*DT;
        T:= S/L;
        X:= X0 + fix(L*100.0*Sin(T));   \100 scales to fit screen
        Y:= Y0 + fix(L*100.0*Cos(T));
        Move(X0, Y0); Line(X, Y, 7);    \draw pendulum
        Ball(X, Y, 10, $E\yellow\);
        while port($3DA) & $08 do [];   \wait for vertical retrace to go away
        repeat until port($3DA) & $08;  \wait for vertical retrace signal
        Move(X0, Y0); Line(X, Y, 0);    \erase pendulum
        Ball(X, Y, 10, 0\black\);
until   KeyHit;                         \keystroke terminates program
SetVid(3);                              \restore normal text screen
]


clear screen
open window 400, 300
window origin "cc"

rodLen = 160
gravity = 2
damp = .989
TWO_PI = pi * 2
angle = 90 * 0.01745329251 // convert degree to radian

repeat
    acceleration = -gravity / rodLen * sin(angle)
    angle = angle + velocity : if angle > TWO_PI angle = 0
    velocity = velocity + acceleration
    velocity = velocity * damp
    posX = sin(angle) * rodLen
    posY = cos(angle) * rodLen - 70
    clear window
    text -50, -100, "Press 'q' to quit"
    color 250, 0, 250
    fill circle 0, -70, 4
    line 0, -70, posX, posY
    color 250, 100, 20
    fill circle posX, posY, 10
until(lower$(inkey$(0.02)) = "q")

exit


10 OVER 1: CLS
20 LET theta=1
30 LET g=9.81
40 LET l=0.5
50 LET speed=0
100 LET pivotx=120
110 LET pivoty=140
120 LET bobx=pivotx+l*100*SIN (theta)
130 LET boby=pivoty+l*100*COS (theta)
140 GO SUB 1000: PAUSE 1: GO SUB 1000
190 LET accel=g*SIN (theta)/l/100
200 LET speed=speed+accel/100
210 LET theta=theta+speed
220 GO TO 100
1000 PLOT pivotx,pivoty: DRAW bobx-pivotx,boby-pivoty
1010 CIRCLE bobx,boby,3
1020 RETURN


*        Angle difference between two bearings - 06/06/2018
ANGLEDBB CSECT
         USING  ANGLEDBB,R13       base register
         B      72(R15)            skip savearea
         DC     17F'0'             savearea
         SAVE   (14,12)            save previous context
         ST     R13,4(R15)         link backward
         ST     R15,8(R13)         link forward
         LR     R13,R15            set addressability
         LA     R10,T-4            @t
         LA     R6,1               i=1
       DO WHILE=(C,R6,LE,N)        do i=1 to n
         LA     R10,4(R10)           next @t
         L      R7,0(R10)            a=t(i,1)
         LA     R10,4(R10)           next @t
         L      R8,0(R10)            b=t(i,2)
         LR     R4,R8                b
         SR     R4,R7                b-a
         SRDA   R4,32                ~
         D      R4,=F'3600000'       /360
         A      R4,=F'5400000'       +540
         SRDA   R4,32                ~
         D      R4,=F'3600000'       /360
         S      R4,=F'1800000'       x=((((b-a)//360)+540)//360)-180
         XDECO  R7,XDEC              edit a
         MVC    PG(8),XDEC           output a
         MVC    PG+9(4),XDEC+8       output a decimals
         XDECO  R8,XDEC              edit b
         MVC    PG+14(8),XDEC        output b
         MVC    PG+23(4),XDEC+8      output b decimals
         XDECO  R4,XDEC              edit x
         MVC    PG+28(8),XDEC        output x
         MVC    PG+37(4),XDEC+8      output x decimals
         XPRNT  PG,L'PG              print
         LA     R6,1(R6)             i++
       ENDDO    ,                  enddo i
         L      R13,4(0,R13)       restore previous savearea pointer
         RETURN (14,12),RC=0       restore registers from calling sav
N        DC     F'8'               number of pairs
T        DC     F'200000',F'450000',F'-450000',F'450000'
         DC     F'-850000',F'900000',F'-950000',F'900000'
         DC     F'-450000',F'1250000',F'450000',F'1450000'
         DC     F'294803',F'-886361',F'-783251',F'-1590360'
PG       DC     CL80'12345678.1234 12345678.1234 12345678.1234'
XDEC     DS     CL12               temp
         YREGS
         END    ANGLEDBB


/* ARM assembly AARCH64 Raspberry PI 3B */
/*  program diffAngle64.s   */

/************************************/
/* Constantes                       */
/************************************/
.include "../includeConstantesARM64.inc"

/*********************************/
/* Initialized data              */
/*********************************/
.data
szCarriageReturn:   .asciz "\n"
szMessResult:       .asciz "Difference between @ and @ = @ \n"

.align 8
fB1:            .double 0F20.0
fB2:            .double 0F45.0
fB3:            .double 0F-45.0
fB4:            .double 0F-85.0
fB5:            .double 90.0
fB6:            .double -95.0
fB7:            .double 125.0
fB8:            .double 145.0
fB9:            .double 0F29.4803
fB10:           .double 0F-88.6381
fB11:           .double 0F-78.3251
fB12:           .double 0F-159.036
fB13:           .double 0F-70099.74233810938
fB14:           .double 0F29840.67437876723

/*********************************/
/* UnInitialized data            */
/*********************************/
.bss
sZoneConv:           .skip 24
/*********************************/
/*  code section                 */
/*********************************/
.text
.global main
main:
    ldr x0,qAdrfB1
    ldr x1,qAdrfB2
    bl testComputeAngle
    //b 100f
    ldr x0,qAdrfB3
    ldr x1,qAdrfB2
    bl testComputeAngle

    ldr x0,qAdrfB4
    ldr x1,qAdrfB5
    bl testComputeAngle

    ldr x0,qAdrfB6
    ldr x1,qAdrfB5
    bl testComputeAngle

    ldr x0,qAdrfB3
    ldr x1,qAdrfB7
    bl testComputeAngle

    ldr x0,qAdrfB3
    ldr x1,qAdrfB8
    bl testComputeAngle

    ldr x0,qAdrfB9
    ldr x1,qAdrfB10
    bl testComputeAngle

    ldr x0,qAdrfB11
    ldr x1,qAdrfB12
    bl testComputeAngle

    ldr x0,qAdrfB13
    ldr x1,qAdrfB14
    bl testComputeAngle

100:                            // standard end of the program
    mov x0, #0                  // return code
    mov x8,EXIT
    svc #0                      // perform the system call
qAdrszCarriageReturn:    .quad szCarriageReturn
qAdrsZoneConv:           .quad sZoneConv
qAdrfB1:                .quad fB1
qAdrfB2:                .quad fB2
qAdrfB3:                .quad fB3
qAdrfB4:                .quad fB4
qAdrfB5:                .quad fB5
qAdrfB6:                .quad fB6
qAdrfB7:                .quad fB7
qAdrfB8:                .quad fB8
qAdrfB9:                .quad fB9
qAdrfB10:               .quad fB10
qAdrfB11:               .quad fB11
qAdrfB12:               .quad fB12
qAdrfB13:               .quad fB13
qAdrfB14:               .quad fB14
/******************************************************************/
/*     compute difference and display result                      */
/******************************************************************/
/* s0 contains bearing 1  */
/* s1 contains bearing 2  */
testComputeAngle:
    stp x1,lr,[sp,-16]!          // save  registers
    stp x2,x3,[sp,-16]!          // save  registers
    ldr d0,[x0]
    fmov d2,d0
    ldr d1,[x1]
    bl computeDiffAngle
    fmov d3,d0
    fmov d0,d2
    ldr x0,qAdrsZoneConv
    bl convertirFloat
    ldr x0,qAdrszMessResult
    ldr x1,qAdrsZoneConv
    bl strInsertAtCharInc
    mov x3,x0
    fmov d0,d1
    ldr x0,qAdrsZoneConv
    bl convertirFloat
    mov x0,x3
    ldr x1,qAdrsZoneConv
    bl strInsertAtCharInc
    mov x3,x0
    fmov d0,d3
    ldr x0,qAdrsZoneConv
    bl convertirFloat
    mov x0,x3
    ldr x1,qAdrsZoneConv
    bl strInsertAtCharInc
    bl affichageMess

100:
    ldp x2,x3,[sp],16        // restaur  registers
    ldp x1,lr,[sp],16        // restaur  registers
    ret
qAdrszMessResult:      .quad szMessResult
/******************************************************************/
/*     compute difference of two bearing                                  */
/******************************************************************/
/* d0 contains bearing 1  */
/* d1 contains bearing 2  */
computeDiffAngle:
    stp x1,lr,[sp,-16]!        // save  registers
    stp x2,x3,[sp,-16]!        // save  registers
    stp x4,x5,[sp,-16]!        // save  registers
    stp d1,d2,[sp,-16]!        // save  registres
    stp d3,d4,[sp,-16]!        // save  registres
    mov x1,#360
    mov x4,#0                  // top positive/negative
    fcvtzs d4,d0               // conversion.integer
    scvtf d2,d4                // conversion float
    fsub d2,d0,d2              // partie décimale
    fmov x0,d4                 // partie entière
    cmp x0,#0                  // negative ?
    bge 1f
    neg x0,x0                  // yes -> inversion
    mov x4,#1
1:
    udiv x2,x0,x1              // divide by 360
    msub x3,x2,x1,x0
    cmp x4,#0                  // value negative ?
    neg x5,x3
    csel x3,x5,x3,ne           // inversion remainder
    fmov d3,x3
    scvtf d3,d3                // and conversion float
    fadd d0,d3,d2              // add decimal part

    mov x4,#0                  // bearing 2
    fcvtzs d4,d1               // conversion integer
    scvtf d2,d4                // conversion float
    fsub d2,d1,d2              // partie décimale
    fmov x0,d4
    cmp x0,#0
    bge 2f
    neg x0,x0
    mov x4,#1
2:
    udiv x2,x0,x1              // divide by 360
    msub x3,x2,x1,x0
    cmp x4,#0
    neg x5,x3
    csel x3,x5,x3,ne           // inversion remainder
    fmov d3,x3
    scvtf d3,d3                // conversion float
    fadd d1,d3,d2

    fsub d0,d1,d0              // calculate the difference between the 2 values

    mov x0,180
    fmov d3,x0
    scvtf d3,d3                // conversion float 180
    fmov d4,x1                 // 360
    scvtf d4,d4                // conversion float 360
    fcmp d0,#0.0               // difference is negative ?
    blt 2f
                               // difference is positive
    fcmp d0,d4                 // difference > 360
    ble 3f
    fsub  d0,d0,d4             // yes -> difference - 360
3:
    fcmp d0,d3                 // compare difference and 180
    ble 100f
    fsub d0,d4,d0              // > 180 calculate 360 - difference
    fneg d0,d0                 // and negate
    b 100f

2:                            // différence is négative
    fneg d2,d4                // -360
    fcmp d0,d2                // compare différence et - 360
    ble 3f
    fsub  d0,d0,d4            // sub 360 to différence
3:
    fneg d3,d3                // -180
    fcmp d0,d3                // compare difference and -180
    bge 100f
    fadd d0,d4,d0             // calculate 360 + différence

100:
    ldp d3,d4,[sp],16         // restaur  registers
    ldp d1,d2,[sp],16         // restaur  registers
    ldp x4,x5,[sp],16         // restaur  registers
    ldp x2,x3,[sp],16         // restaur  registers
    ldp x1,lr,[sp],16         // restaur  registers
    ret

/******************************************************************/
/*     Conversion Float                                            */
/******************************************************************/
/* d0 contains Float */
/* x0 contains address conversion area  mini 20 charactèrs */
/* x0 return result length */
/* see https://blog.benoitblanchon.fr/lightweight-float-to-string/ */
convertirFloat:
    stp x1,lr,[sp,-16]!       // save  registres
    stp x2,x3,[sp,-16]!       // save  registres
    stp x4,x5,[sp,-16]!       // save  registres
    stp x6,x7,[sp,-16]!       // save  registres
    stp x8,x9,[sp,-16]!       // save  registres
    stp d1,d2,[sp,-16]!       // save  registres
    mov x6,x0                 // save area address
    fmov x0,d0
    mov x8,#0                 // result length
    mov x3,#'+'
    strb w3,[x6]              // signe + forcing
    mov x2,x0
    tbz x2,63,1f
    mov x2,1
    lsl x2,x2,63
    bic x0,x0,x2
    mov x3,#'-'               // sign -
    strb w3,[x6]
1:
    adds x8,x8,#1             // next position
    cmp x0,#0                 // case 0 positive or negative
    bne 2f
    mov x3,#'0'
    strb w3,[x6,x8]           // store character 0
    adds x8,x8,#1
    strb wzr,[x6,x8]          // store 0 final
    mov x0,x8                 // return length
    b 100f
2:
    ldr x2,iMaskExposant
    mov x1,x0
    and x1,x1,x2              // exposant
    cmp x1,x2
    bne 4f
    tbz x0,51,3f              // test bit 51 to zéro
    mov x2,#'N'               // case Nan. store byte  no possible store integer
    strb w2,[x6]              // area no aligned
    mov x2,#'a'
    strb w2,[x6,#1]
    mov x2,#'n'
    strb w2,[x6,#2]
    mov x2,#0                  // 0 final
    strb w2,[x6,#3]
    mov x0,#3
    b 100f
3:                             // case infini positive or négative
    mov x2,#'I'
    strb w2,[x6,x8]
    adds x8,x8,#1
    mov x2,#'n'
    strb w2,[x6,x8]
    adds x8,x8,#1
    mov x2,#'f'
    strb w2,[x6,x8]
    adds x8,x8,#1
    mov x2,#0
    strb w2,[x6,x8]
    mov x0,x8
    b 100f
4:
    bl normaliserFloat
    mov x5,x0                // save exposant
    fcvtzu d2,d0
    fmov x0,d2               // part integer
    scvtf d1,d2              // conversion float
    fsub d1,d0,d1            // extraction part fractional
    ldr d2,dConst1
    fmul d1,d2,d1            // to crop it in full
    fcvtzu d1,d1             // convertion integer
    fmov x4,d1               // fract value
                             // conversion part integer to x0
    mov x2,x6                // save address begin area
    adds x6,x6,x8
    mov x1,x6
    bl conversion10
    add x6,x6,x0
    mov x3,#','
    strb w3,[x6]
    adds x6,x6,#1

    mov x0,x4                // conversion part fractionnaire
    mov x1,x6
    bl conversion10SP
    add x6,x6,x0
    sub x6,x6,#1
                             //  remove trailing zeros
5:
    ldrb w0,[x6]
    cmp w0,#'0'
    bne 6f
    sub x6,x6,#1
    b 5b
6:
    cmp w0,#','
    bne 7f
    sub x6,x6,#1
7:
    cmp x5,#0                  // if exposant = 0 no display
    bne 8f
    add x6,x6,#1
    b 10f
8:
    add x6,x6,#1
    mov x3,#'E'
    strb w3,[x6]
    add x6,x6,#1
    mov x0,x5                  // conversion exposant
    mov x3,x0
    tbz x3,63,9f               // exposant negative ?
    neg x0,x0
    mov x3,#'-'
    strb w3,[x6]
    adds x6,x6,#1
9:
    mov x1,x6
    bl conversion10
    add x6,x6,x0
10:
    strb wzr,[x6]              // store 0 final
    adds x6,x6,#1
    mov x0,x6
    subs x0,x0,x2              // retour de la longueur de la zone
    subs x0,x0,#1              // sans le 0 final

100:
    ldp d1,d2,[sp],16          // restaur  registres
    ldp x8,x9,[sp],16          // restaur  registres
    ldp x6,x7,[sp],16          // restaur  registres
    ldp x4,x5,[sp],16          // restaur  registres
    ldp x2,x3,[sp],16          // restaur  registres
    ldp x1,lr,[sp],16          // restaur registres
    ret

iMaskExposant:            .quad 0x7FF<<52
dConst1:                  .double 0f1E17

/***************************************************/
/*   normaliser float                              */
/***************************************************/
/* x0 contain float value (always positive value and <> Nan) */
/* d0 return new value */
/* x0 return exposant */
normaliserFloat:
    stp x1,lr,[sp,-16]!       // save  registers
    fmov d0,x0                // value float
    mov x0,#0                 // exposant
    ldr d1,dConstE7           // no normalisation for value  < 1E7
    fcmp d0,d1
    blo 10f                   // if d0 < dConstE7

    ldr d1,dConstE256
    fcmp d0,d1
    blo 1f
    fdiv d0,d0,d1
    adds x0,x0,#256
1:

    ldr d1,dConstE128
    fcmp d0,d1
    blo 1f
    fdiv d0,d0,d1
    adds x0,x0,#128
1:
    ldr d1,dConstE64
    fcmp d0,d1
    blo 1f
    fdiv d0,d0,d1
    adds x0,x0,#64
1:
    ldr d1,dConstE32
    fcmp d0,d1
    blo 1f
    fdiv d0,d0,d1
    adds x0,x0,#32
1:
    ldr d1,dConstE16
    fcmp d0,d1
    blo 2f
    fdiv d0,d0,d1
    adds x0,x0,#16
2:
    ldr d1,dConstE8
    fcmp d0,d1
    blo 3f
    fdiv d0,d0,d1
    adds x0,x0,#8
3:
    ldr d1,dConstE4
    fcmp d0,d1
    blo 4f
    fdiv d0,d0,d1
    adds x0,x0,#4
4:
    ldr d1,dConstE2
    fcmp d0,d1
    blo 5f
    fdiv d0,d0,d1
    adds x0,x0,#2
5:
    ldr d1,dConstE1
    fcmp d0,d1
    blo 10f
    fdiv d0,d0,d1
    adds x0,x0,#1

10:
    ldr d1,dConstME5        // pas de normalisation pour les valeurs > 1E-5
    fcmp d0,d1
    bhi 100f                 // fin

    ldr d1,dConstME255
    fcmp d0,d1
    bhi 11f
    ldr d1,dConstE256

    fmul d0,d0,d1
    subs x0,x0,#256
11:

    ldr d1,dConstME127
    fcmp d0,d1
    bhi 11f
    ldr d1,dConstE128

    fmul d0,d0,d1
    subs x0,x0,#128
11:

    ldr d1,dConstME63
    fcmp d0,d1
    bhi 11f
    ldr d1,dConstE64

    fmul d0,d0,d1
    subs x0,x0,#64
11:

    ldr d1,dConstME31
    fcmp d0,d1
    bhi 11f
    ldr d1,dConstE32

    fmul d0,d0,d1
    subs x0,x0,#32
11:
    ldr d1,dConstME15
    fcmp d0,d1
    bhi 12f
    ldr d1,dConstE16
    fmul d0,d0,d1
    subs x0,x0,#16
12:
    ldr d1,dConstME7
    fcmp d0,d1
    bhi 13f
    ldr d1,dConstE8
    fmul d0,d0,d1
    subs x0,x0,#8
13:
    ldr d1,dConstME3
    fcmp d0,d1
    bhi 14f
    ldr d1,dConstE4
    fmul d0,d0,d1
    subs x0,x0,#4
14:
    ldr d1,dConstME1
    fcmp d0,d1
    bhi 15f
    ldr d1,dConstE2
    fmul d0,d0,d1
    subs x0,x0,#2
15:
    ldr d1,dConstE0
    fcmp d0,d1
    bhi 100f
    ldr d1,dConstE1
    fmul d0,d0,d1
    subs x0,x0,#1

100:                       // fin standard de la fonction
    ldp x1,lr,[sp],16           // restaur registres
    ret
.align 2
dConstE7:             .double 0f1E7
dConstE256:           .double 0f1E256
dConstE128:           .double 0f1E128
dConstE64:            .double 0f1E64
dConstE32:            .double 0f1E32
dConstE16:            .double 0f1E16
dConstE8:             .double 0f1E8
dConstE4:             .double 0f1E4
dConstE2:             .double 0f1E2
dConstE1:             .double 0f1E1
dConstME5:            .double 0f1E-5
dConstME255:          .double 0f1E-255
dConstME127:          .double 0f1E-127
dConstME63:           .double 0f1E-63
dConstME31:           .double 0f1E-31
dConstME15:           .double 0f1E-15
dConstME7:            .double 0f1E-7
dConstME3:            .double 0f1E-3
dConstME1:            .double 0f1E-1
dConstE0:             .double 0f1E0

/******************************************************************/
/*     Décimal Conversion                                         */
/******************************************************************/
/* x0 contain value et x1 address conversion area   */
conversion10SP:
    stp x1,lr,[sp,-16]!         // save  registers
    stp x2,x3,[sp,-16]!         // save  registers
    stp x4,x5,[sp,-16]!         // save  registers
    mov x5,x1
    mov x4,#16
    mov x2,x0
    mov x1,#10                  // décimal conversion
1:                              // conversion loop
    mov x0,x2                   // copy begin number or quotient
    udiv x2,x0,x1               // division by 10
    msub x3,x1,x2,x0            // compute remainder
    add x3,x3,#48               // compute digit
    strb w3,[x5,x4]             // store byte address area (x5) + offset (x4)
    subs x4,x4,#1               // position precedente
    bge 1b
    strb wzr,[x5,16]            // 0 final
100:
    ldp x4,x5,[sp],16           // restaur  registers
    ldp x2,x3,[sp],16           // restaur  registers
    ldp x1,lr,[sp],16           // restaur registers
    ret
/***************************************************/
/*      ROUTINES INCLUDE                           */
/***************************************************/
.include "../includeARM64.inc"


INCLUDE "H6:REALMATH.ACT"

INT FUNC AngleI(INT a1,a2)
  INT r

  r=a2-a1
  WHILE r>180 DO r==-360 OD
  WHILE r<-180 DO r==+360 OD
RETURN (r)

PROC TestI(INT a1,a2)
  INT r

  r=AngleI(a1,a2)
  PrintF("%I .. %I = %I%E",a1,a2,r)
RETURN

PROC AngleR(REAL POINTER r1,r2,r)
  REAL tmp,r180,rm180,r360

  ValR("180",r180)
  ValR("-180",rm180)
  ValR("360",r360)

  RealSub(r2,r1,r)
  WHILE RealGreaterOrEqual(r,r180)
  DO
    RealSub(r,r360,tmp) RealAssign(tmp,r)
  OD
  WHILE RealGreaterOrEqual(rm180,r)
  DO
    RealAdd(r,r360,tmp) RealAssign(tmp,r)
  OD
RETURN

PROC TestR(CHAR ARRAY s1,s2)
  REAL r1,r2,r

  ValR(s1,r1) ValR(s2,r2)
  AngleR(r1,r2,r)
  PrintR(r1) Print(" .. ") PrintR(r2)
  Print(" = ") PrintRE(r)
RETURN

PROC Main()
  Put(125) PutE() ;clear screen
  TestI(20,45)
  TestI(-45,45)
  TestI(-85,90)
  TestI(-95,90)
  TestI(-45,125)
  TestI(-45,145)
  TestR("29.4803","-88.6381")
  TestR("-78.3251","-159.036")
  TestR("-70099.74233810938","29840.67437876723")
  TestR("-165313.6666297357","33693.9894517456")
  TestR("1174.8380510598456","-154146.66490124757")
  TestR("60175.77306795546","42213.07192354373")
RETURN


/* ARM assembly Raspberry PI or android with termux */
/*  program diffAngle.s   */

 /* REMARK 1 : this program use routines in a include file
   see task Include a file language arm assembly
   for the routine affichageMess conversion10
   see at end of this program the instruction include */
/* for constantes see task include a file in arm assembly */
/************************************/
/* Constantes                       */
/************************************/
.include "../constantes.inc"

/*********************************/
/* Initialized data              */
/*********************************/
.data
szCarriageReturn:   .asciz "\n"
szMessResult:       .asciz "Difference between @ and @ = @ \n"

.align 4
fB1:            .float 20.0
fB2:            .float 45.0
fB3:            .float -45.0
fB4:            .float -85.0
fB5:            .float 90.0
fB6:            .float -95.0
fB7:            .float 125.0
fB8:            .float 145.0
fB9:            .float 29.4803
fB10:           .float -88.6381
fB11:           .float -78.3251
fB12:           .float -159.036
fB13:           .float -70099.74233810938
fB14:           .float 29840.67437876723

/*********************************/
/* UnInitialized data            */
/*********************************/
.bss
sZoneConv:           .skip 24
/*********************************/
/*  code section                 */
/*********************************/
.text
.global main
main:
    ldr r0,iAdrfB1
    ldr r1,iAdrfB2
    bl testComputeAngle

    ldr r0,iAdrfB3
    ldr r1,iAdrfB2
    bl testComputeAngle

    ldr r0,iAdrfB4
    ldr r1,iAdrfB5
    bl testComputeAngle

    ldr r0,iAdrfB6
    ldr r1,iAdrfB5
    bl testComputeAngle

    ldr r0,iAdrfB3
    ldr r1,iAdrfB7
    bl testComputeAngle

    ldr r0,iAdrfB3
    ldr r1,iAdrfB8
    bl testComputeAngle

    ldr r0,iAdrfB9
    ldr r1,iAdrfB10
    bl testComputeAngle

    ldr r0,iAdrfB11
    ldr r1,iAdrfB12
    bl testComputeAngle

    ldr r0,iAdrfB13
    ldr r1,iAdrfB14
    bl testComputeAngle

100:                            @ standard end of the program
    mov r0, #0                  @ return code
    mov r7, #EXIT               @ request to exit program
    svc #0                      @ perform the system call
iAdrszCarriageReturn:    .int szCarriageReturn
iAdrsZoneConv:           .int sZoneConv
iAdrfB1:                .int fB1
iAdrfB2:                .int fB2
iAdrfB3:                .int fB3
iAdrfB4:                .int fB4
iAdrfB5:                .int fB5
iAdrfB6:                .int fB6
iAdrfB7:                .int fB7
iAdrfB8:                .int fB8
iAdrfB9:                .int fB9
iAdrfB10:               .int fB10
iAdrfB11:               .int fB11
iAdrfB12:               .int fB12
iAdrfB13:               .int fB13
iAdrfB14:               .int fB14
/******************************************************************/
/*     compute difference and display result                      */
/******************************************************************/
/* s0 contains bearing 1  */
/* s1 contains bearing 2  */
testComputeAngle:
    push {r1-r3,lr}           @ save  registers
    vldr.f32 s0,[r0]
    vmov s2,s0
    vldr.f32 s1,[r1]
    bl computeDiffAngle
    vmov s3,s0
    vmov s0,s2
    ldr r0,iAdrsZoneConv
    bl convertirFloat
    ldr r0,iAdrszMessResult
    ldr r1,iAdrsZoneConv
    bl strInsertAtCharInc
    mov r3,r0
    vmov s0,s1
    ldr r0,iAdrsZoneConv
    bl convertirFloat
    mov r0,r3
    ldr r1,iAdrsZoneConv
    bl strInsertAtCharInc
    mov r3,r0
    vmov s0,s3
    ldr r0,iAdrsZoneConv
    bl convertirFloat
    mov r0,r3
    ldr r1,iAdrsZoneConv
    bl strInsertAtCharInc
    bl affichageMess

100:
    pop {r1-r3,pc}             @ restaur registers
iAdrszMessResult:      .int szMessResult
/******************************************************************/
/*     compute difference of two bearing                                  */
/******************************************************************/
/* s0 contains bearing 1  */
/* s1 contains bearing 2  */
computeDiffAngle:
    push {r1-r4,lr}           @ save  registers
    vpush {s1-s4}
    mov r1,#360
    mov r4,#0                 @ top positive/negative
    vcvt.s32.f32  s4,s0       @ conversion integer
    vcvt.f32.s32  s2,s4       @ conversion float
    vsub.f32 s2,s0,s2         @ partie décimale
    vmov r0,s4                @ partie entière
    cmp r0,#0                 @ negative ?
    neglt r0,r0               @ yes -> inversion
    movlt r4,#1
    bl division               @ divide by 360 (r0 dividende r1 divisor r2 quotient r3 remainder)
    cmp r4,#0                 @ value negative ?
    negne r3,r3               @ inversion remainder
    vmov s3,r3
    vcvt.f32.s32  s3,s3       @ and conversion float
    vadd.f32 s0,s3,s2         @ add decimal part

    mov r4,#0                 @ bearing 2
    vcvt.s32.f32  s4,s1       @ conversion integer
    vcvt.f32.s32  s2,s4       @ conversion float
    vsub.f32 s2,s1,s2         @ partie décimale
    vmov r0,s4
    cmp r0,#0
    neglt r0,r0
    movlt r4,#1
    bl division               @ divide by 360
    cmp r4,#0
    negne r3,r3               @ negate remainder
    vmov s3,r3
    vcvt.f32.s32  s3,s3       @ conversion float
    vadd.f32 s1,s3,s2

    vsub.f32 s0,s1,s0         @ calculate the difference between the 2 values

    mov r0,#180
    vmov s3,r0
    vcvt.f32.s32  s3,s3       @ conversion float 180
    vmov s4,r1                @ 360
    vcvt.f32.s32  s4,s4       @ conversion float 360

    vcmp.f32 s0,#0.0          @ difference is negative ?
    vmrs APSR_nzcv, FPSCR     @ flags transfert (do not forget this instruction !!!)
    blt 2f
                              @ difference is positive
    vcmp.f32 s0,s4            @ difference > 360
    vmrs APSR_nzcv, FPSCR     @ flags transfert (do not forget this instruction !!!)
    vsubgt.f32  s0,s4         @ yes -> difference - 360
    vcmp.f32 s0,s3            @ compare difference and 180
    vmrs APSR_nzcv, FPSCR     @ flags transfert (do not forget this instruction !!!)
    vsubgt.f32 s0,s4,s0       @ > 180 calculate 360 - difference
    vneggt.f32 s0,s0          @ and negate
    b 100f

2:                            @ différence is négative
    vneg.f32 s2,s4            @ -360
    vcmp.f32 s0,s2            @ compare différence et - 360
    vmrs APSR_nzcv, FPSCR     @ flags transfert (do not forget this instruction !!!)
    vsubgt.f32  s0,s4         @ sub 360 to différence

    vneg.f32 s3,s3            @ -180
    vcmp.f32 s0,s3            @ compare difference and -180
    vmrs APSR_nzcv, FPSCR     @ flags transfert (do not forget this instruction !!!)
    vaddlt.f32 s0,s4,s0       @ calculate 360 + différence

100:
    vpop {s1-s4}
    pop {r1-r4,pc}             @ restaur registers

/******************************************************************/
/*     Conversion Float                                            */
/******************************************************************/
/* s0  contains Float */
/* r0 contains address conversion area  mini 20 charactèrs*/
/* r0 return result length */
convertirFloat:
    push {r1-r7,lr}
    vpush {s0-s2}
    mov r6,r0                 @ save area address
    vmov r0,s0
    movs r7,#0                @ result length
    movs r3,#'+'
    strb r3,[r6]              @ sign + forcing
    mov r2,r0
    lsls r2,#1                @ extraction bit 31
    bcc 1f                    @ positive ?
    lsrs r0,r2,#1             @ raz sign if negative
    movs r3,#'-'              @ sign -
    strb r3,[r6]
1:
    adds r7,#1                @ next position
    cmp r0,#0                 @ case of positive or negative 0
    bne 2f
    movs r3,#'0'
    strb r3,[r6,r7]           @ store character 0
    adds r7,#1                @ next position
    movs r3,#0
    strb r3,[r6,r7]           @ store  0 final
    mov r0,r7                 @ return length
    b 100f                    @ and end
2:
    ldr r2,iMaskExposant
    mov r1,r0
    ands r1,r2                @ exposant = 255 ?
    cmp r1,r2
    bne 4f
    lsls r0,#10               @ bit 22 à 0 ?
    bcc 3f                    @ yes
    movs r2,#'N'              @ case of Nan. store byte, if not possible store int
    strb r2,[r6]              @ area no aligned
    movs r2,#'a'
    strb r2,[r6,#1]
    movs r2,#'n'
    strb r2,[r6,#2]
    movs r2,#0                @ 0 final
    strb r2,[r6,#3]
    movs r0,#3                @ return length 3
    b 100f
3:                            @ case infini positive or négative
    movs r2,#'I'
    strb r2,[r6,r7]
    adds r7,#1
    movs r2,#'n'
    strb r2,[r6,r7]
    adds r7,#1
    movs r2,#'f'
    strb r2,[r6,r7]
    adds r7,#1
    movs r2,#0
    strb r2,[r6,r7]
    mov r0,r7
    b 100f
4:
    bl normaliserFloat
    mov r5,r0                @ save exposant
    VCVT.U32.f32  s2,s0      @ integer value of  integer part
    vmov r0,s2               @ integer part
    VCVT.F32.U32  s1,s2      @ conversion float
    vsub.f32 s1,s0,s1        @ extraction fract part
    vldr s2,iConst1
    vmul.f32 s1,s2,s1        @ to crop it in full

    VCVT.U32.f32  s1,s1      @ integer conversion
    vmov r4,s1               @ fract value
                             @ integer conversion in  r0
    mov r2,r6                @ save address area begin
    adds r6,r7
    mov r1,r6
    bl conversion10
    add r6,r0
    movs r3,#','
    strb r3,[r6]
    adds r6,#1

    mov r0,r4                @ conversion fractional part
    mov r1,r6
    bl conversion10SP        @ spécial routine with conservation begin 0
    add r6,r0
    subs r6,#1
                             @ remove trailing zeros
5:
    ldrb r0,[r6]
    cmp r0,#'0'
    bne 6f
    subs r6,#1
    b 5b
6:
    cmp r0,#','
    bne 7f
    subs r6,#1
7:
    adds r6,#1
    movs r3,#'E'
    strb r3,[r6]
    adds r6,#1
    mov r0,r5                  @ conversion exposant
    mov r3,r0
    lsls r3,#1
    bcc 4f
    rsbs r0,r0,#0
    movs r3,#'-'
    strb r3,[r6]
    adds r6,#1
4:
    mov r1,r6
    bl conversion10
    add r6,r0

    movs r3,#0
    strb r3,[r6]
    adds r6,#1
    mov r0,r6
    subs r0,r2                 @ return length result
    subs r0,#1                 @ - 0 final

100:
    vpop {s0-s2}
    pop {r1-r7,pc}
iMaskExposant:            .int 0xFF<<23
iConst1:                  .float 0f1E9

/***************************************************/
/*   normaliser float                              */
/***************************************************/
/* r0 contain float value (always positive value and <> Nan) */
/* s0 return new value  */
/* r0 return exposant */
normaliserFloat:
    push {lr}               @ save  registre
    vmov s0,r0              @ value float
    movs r0,#0              @ exposant
    vldr s1,iConstE7        @ no normalisation for value < 1E7
    vcmp.f32 s0,s1
    vmrs APSR_nzcv,FPSCR
    blo 10f                 @ if s0  < iConstE7

    vldr s1,iConstE32
    vcmp.f32 s0,s1
    vmrs APSR_nzcv,FPSCR
    blo 1f
    vldr s1,iConstE32
    vdiv.f32 s0,s0,s1
    adds r0,#32
1:
    vldr s1,iConstE16
    vcmp.f32 s0,s1
    vmrs APSR_nzcv,FPSCR
    blo 2f
    vldr s1,iConstE16
    vdiv.f32 s0,s0,s1
    adds r0,#16
2:
    vldr s1,iConstE8
    vcmp.f32 s0,s1
    vmrs APSR_nzcv,FPSCR
    blo 3f
    vldr s1,iConstE8
    vdiv.f32 s0,s0,s1
    adds r0,#8
3:
    vldr s1,iConstE4
    vcmp.f32 s0,s1
    vmrs APSR_nzcv,FPSCR
    blo 4f
    vldr s1,iConstE4
    vdiv.f32 s0,s0,s1
    adds r0,#4
4:
    vldr s1,iConstE2
    vcmp.f32 s0,s1
    vmrs APSR_nzcv,FPSCR
    blo 5f
    vldr s1,iConstE2
    vdiv.f32 s0,s0,s1
    adds r0,#2
5:
    vldr s1,iConstE1
    vcmp.f32 s0,s1
    vmrs APSR_nzcv,FPSCR
    blo 10f
    vldr s1,iConstE1
    vdiv.f32 s0,s0,s1
    adds r0,#1

10:
    vldr s1,iConstME5        @ pas de normalisation pour les valeurs > 1E-5
    vcmp.f32 s0,s1
    vmrs APSR_nzcv,FPSCR
    bhi 100f
    vldr s1,iConstME31
    vcmp.f32 s0,s1
    vmrs APSR_nzcv,FPSCR
    bhi 11f
    vldr s1,iConstE32

    vmul.f32 s0,s0,s1
    subs r0,#32
11:
    vldr s1,iConstME15
    vcmp.f32 s0,s1
    vmrs APSR_nzcv,FPSCR
    bhi 12f
    vldr s1,iConstE16
    vmul.f32 s0,s0,s1
    subs r0,#16
12:
    vldr s1,iConstME7
    vcmp.f32 s0,s1
    vmrs APSR_nzcv,FPSCR
    bhi 13f
    vldr s1,iConstE8
    vmul.f32 s0,s0,s1
    subs r0,#8
13:
    vldr s1,iConstME3
    vcmp.f32 s0,s1
    vmrs APSR_nzcv,FPSCR
    bhi 14f
    vldr s1,iConstE4
    vmul.f32 s0,s0,s1
    subs r0,#4
14:
    vldr s1,iConstME1
    vcmp.f32 s0,s1
    vmrs APSR_nzcv,FPSCR
    bhi 15f
    vldr s1,iConstE2
    vmul.f32 s0,s0,s1
    subs r0,#2
15:
    vldr s1,iConstE0
    vcmp.f32 s0,s1
    vmrs APSR_nzcv,FPSCR
    bhi 100f
    vldr s1,iConstE1
    vmul.f32 s0,s0,s1
    subs r0,#1

100:                       @ fin standard de la fonction
    pop {pc}               @ restaur des registres
.align 2
iConstE7:             .float 0f1E7
iConstE32:            .float 0f1E32
iConstE16:            .float 0f1E16
iConstE8:             .float 0f1E8
iConstE4:             .float 0f1E4
iConstE2:             .float 0f1E2
iConstE1:             .float 0f1E1
iConstME5:            .float 0f1E-5
iConstME31:           .float 0f1E-31
iConstME15:           .float 0f1E-15
iConstME7:            .float 0f1E-7
iConstME3:            .float 0f1E-3
iConstME1:            .float 0f1E-1
iConstE0:             .float 0f1E0
/******************************************************************/
/*     Décimal Conversion                                         */
/******************************************************************/
/* r0 contain value et r1 address conversion area   */
conversion10SP:
    push {r1-r6,lr}            @ save  registers
    mov r5,r1
    mov r4,#8
    mov r2,r0
    mov r1,#10                 @ conversion decimale
1:                             @ begin loop
    mov r0,r2                  @ copy number or quotients
    bl division                @ r0 dividende r1 divisor r2 quotient r3 remainder
    add r3,#48                 @ compute digit
    strb r3,[r5,r4]            @ store byte area address (r5) + offset (r4)
    subs r4,r4,#1              @ position précedente
    bge 1b                     @ and loop if not < zero
    mov r0,#8
    mov r3,#0
    strb r3,[r5,r0]            @ store 0 final
100:
    pop {r1-r6,pc}             @ restaur registers
/***************************************************/
/*      ROUTINES INCLUDE                           */
/***************************************************/
.include "../affichage.inc"


getDifference: function [b1, b2][
    r: (b2 - b1) % 360.0

    if r >= 180.0 ->
        r: r - 360.0

    return r
]

print "Input in -180 to +180 range"
print getDifference 20.0 45.0
print getDifference neg 45.0 45.0
print getDifference neg 85.0 90.0
print getDifference neg 95.0 90.0
print getDifference neg 45.0 125.0
print getDifference neg 45.0 145.0
print getDifference neg 45.0 125.0
print getDifference neg 45.0 145.0
print getDifference 29.4803 neg 88.6381
print getDifference neg 78.3251 neg 159.036

print ""
print "Input in wider range"
print getDifference neg 70099.74233810938 29840.67437876723
print getDifference neg 165313.6666297357 33693.9894517456
print getDifference 1174.8380510598456 neg 154146.66490124757
print getDifference 60175.77306795546 42213.07192354373


# Rosetta Code problem: http://rosettacode.org/wiki/Angle_difference_between_two_bearings
# by Jjuanhdez, 06/2022

print "Input in -180 to +180 range:"
call getDifference(20.0, 45.0)
call getDifference(-45.0, 45.0)
call getDifference(-85.0, 90.0)
call getDifference(-95.0, 90.0)
call getDifference(-45.0, 125.0)
call getDifference(-45.0, 145.0)
call getDifference(-45.0, 125.0)
call getDifference(-45.0, 145.0)
call getDifference(29.4803, -88.6381)
call getDifference(-78.3251, -159.036)
print
print "Input in wider range:"
call getDifference(-70099.74233810938, 29840.67437876723)
call getDifference(-165313.6666297357, 33693.9894517456)
call getDifference(1174.8380510598456, -154146.66490124757)
end

subroutine getDifference(b1, b2)
	r = (b2 - b1) mod 360
	if r >= 180.0 then r -= 360.0
	print ljust(b1,16); ljust(b2,16); ljust(r,12)
end subroutine


#include<stdlib.h>
#include<stdio.h>
#include<math.h>

void processFile(char* name){

	int i,records;
	double diff,b1,b2;
	FILE* fp = fopen(name,"r");

	fscanf(fp,"%d\n",&records);

	for(i=0;i<records;i++){
		fscanf(fp,"%lf%lf",&b1,&b2);

		diff = fmod(b2-b1,360.0);
		printf("\nDifference between b2(%lf) and b1(%lf) is %lf",b2,b1,(diff<-180)?diff+360:((diff>=180)?diff-360:diff));
	}

	fclose(fp);
}

int main(int argC,char* argV[])
{
	double diff;

	if(argC < 2)
		printf("Usage : %s <bearings separated by a space OR full file name which contains the bearing list>",argV[0]);
	else if(argC == 2)
		processFile(argV[1]);
	else{
		diff = fmod(atof(argV[2])-atof(argV[1]),360.0);
		printf("Difference between b2(%s) and b1(%s) is %lf",argV[2],argV[1],(diff<-180)?diff+360:((diff>=180)?diff-360:diff));
	}

	return 0;
}


using System;

namespace Angle_difference_between_two_bearings
{
	class Program
	{
		public static void Main(string[] args)
		{
			Console.WriteLine();
			Console.WriteLine("Hello World!");
			Console.WriteLine();

			// Calculate standard test cases
			Console.WriteLine(Delta_Bearing( 20M,45));
			Console.WriteLine(Delta_Bearing(-45M,45M));
			Console.WriteLine(Delta_Bearing(-85M,90M));
			Console.WriteLine(Delta_Bearing(-95M,90M));
			Console.WriteLine(Delta_Bearing(-45M,125M));
			Console.WriteLine(Delta_Bearing(-45M,145M));
			Console.WriteLine(Delta_Bearing( 29.4803M,-88.6381M));
			Console.WriteLine(Delta_Bearing(-78.3251M, -159.036M));

			// Calculate optional test cases
			Console.WriteLine(Delta_Bearing(-70099.74233810938M,   29840.67437876723M));
			Console.WriteLine(Delta_Bearing(-165313.6666297357M,   33693.9894517456M));
			Console.WriteLine(Delta_Bearing( 1174.8380510598456M, -154146.66490124757M));
			Console.WriteLine(Delta_Bearing( 60175.77306795546M,   42213.07192354373M));

			Console.WriteLine();
			Console.Write("Press any key to continue . . . ");
			Console.ReadKey(true);
		}

		static decimal Delta_Bearing(decimal b1, decimal b2)
		{
			/*
			 * Optimal solution
			 *
			decimal d = 0;

			d = (b2-b1)%360;

			if(d>180)
				d -= 360;
			else if(d<-180)
				d += 360;

			return d;
			 *
			 *
			 */

			//
			//
			//
			decimal d = 0;

			// Convert bearing to W.C.B
			if(b1<0)
				b1 += 360;
			if(b2<0)
				b2 += 360;

			///Calculate delta bearing
			//and
			//Convert result value to Q.B.
			d = (b2 - b1)%360;

			if(d>180)
				d -= 360;
			else if(d<-180)
				d += 360;

			return d;

			//
			//
			//
		}
	}
}


#include <cmath>
#include <iostream>
using namespace std;

double getDifference(double b1, double b2) {
	double r = fmod(b2 - b1, 360.0);
	if (r < -180.0)
		r += 360.0;
	if (r >= 180.0)
		r -= 360.0;
	return r;
}

int main()
{
	cout << "Input in -180 to +180 range" << endl;
	cout << getDifference(20.0, 45.0) << endl;
	cout << getDifference(-45.0, 45.0) << endl;
	cout << getDifference(-85.0, 90.0) << endl;
	cout << getDifference(-95.0, 90.0) << endl;
	cout << getDifference(-45.0, 125.0) << endl;
	cout << getDifference(-45.0, 145.0) << endl;
	cout << getDifference(-45.0, 125.0) << endl;
	cout << getDifference(-45.0, 145.0) << endl;
	cout << getDifference(29.4803, -88.6381) << endl;
	cout << getDifference(-78.3251, -159.036) << endl;

	cout << "Input in wider range" << endl;
	cout << getDifference(-70099.74233810938, 29840.67437876723) << endl;
	cout << getDifference(-165313.6666297357, 33693.9894517456) << endl;
	cout << getDifference(1174.8380510598456, -154146.66490124757) << endl;
	cout << getDifference(60175.77306795546, 42213.07192354373) << endl;

	return 0;
}


(defn angle-difference [a b]
  (let [r (mod (- b a) 360)]
    (if (>= r 180)
      (- r 360)
      r)))

(angle-difference 20 45)  ; 25
(angle-difference -45 45) ; 90
(angle-difference -85 90) ; 175
(angle-difference -95 90) ; -175
(angle-difference -70099.74 29840.67) ; -139.59


      ******************************************************************
      * COBOL solution to Angle difference challange
      * The program was run on OpenCobolIDE
      * I chose to read the input data from a .txt file that I
      *    created on my PC rather than to hard code it into the
      *    program or enter it as the program was executing.
      ******************************************************************
       IDENTIFICATION DIVISION.
       PROGRAM-ID. ANGLE-DIFFERENCE.

       ENVIRONMENT DIVISION.
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.

           SELECT IN-FILE ASSIGN TO 'C:\Both\Rosetta\Angle_diff.txt'
               ORGANIZATION IS LINE SEQUENTIAL.

       DATA DIVISION.

       FILE SECTION.
       FD IN-FILE.
       01 IN-RECORD.
           05  ALPHA-BEARING-1          PIC X(20).
           05  FILLER                   PIC X.
           05  ALPHA-BEARING-2          PIC X(20).

       WORKING-STORAGE SECTION.
       01  SWITCHES.
           05 EOF-SWITCH                PIC X VALUE 'N'.

       01 COUNTERS.
           05 REC-CTR                   PIC 9(3) VALUE 0.

       01  WS-ALPHA-BEARING.
           05  WS-AB-SIGN               PIC X.
               88  WS-AB-NEGATIVE       VALUE "-".
           05  WS-AB-INTEGER-PART       PIC X(6).
           05  WS-AB-DEC-POINT          PIC X.
           05  WS-AB-DECIMAL-PART       PIC X(12).

       01  WS-BEARING-1                 PIC S9(6)V9(12).
       01  WS-BEARING-2                 PIC S9(6)V9(12).

       01  WS-BEARING                   PIC S9(6)V9(12).
       01  FILLER REDEFINES WS-BEARING.
           05  WSB-INTEGER-PART         PIC X(6).
           05  WSB-DECIMAL-PART         PIC X9(12).

       77  WS-RESULT                    PIC S9(6)V9(12).
       77  WS-RESULT-POS                PIC 9(6)V9(12).
       77  WS-INTEGER-PART              PIC 9(6).
       77  WS-DECIMAL-PART              PIC V9(12).
       77  WS-RESULT-OUT                PIC ------9.9999.

       PROCEDURE DIVISION.
       000-MAIN.
           PERFORM 100-INITIALIZE.
           PERFORM 200-PROCESS-RECORD
               UNTIL EOF-SWITCH = 'Y'.
           PERFORM 300-TERMINATE.
           STOP RUN.

       100-INITIALIZE.
           OPEN INPUT IN-FILE.
           PERFORM 150-READ-RECORD.

       150-READ-RECORD.
           READ IN-FILE
               AT END
                   MOVE 'Y' TO EOF-SWITCH
               NOT AT END
                   COMPUTE REC-CTR = REC-CTR + 1
               END-READ.

       200-PROCESS-RECORD.
           MOVE ALPHA-BEARING-1 TO WS-ALPHA-BEARING.
           PERFORM 250-CONVERT-DATA.
           MOVE WS-BEARING TO WS-BEARING-1.

           MOVE ALPHA-BEARING-2 TO WS-ALPHA-BEARING.
           PERFORM 250-CONVERT-DATA.
           MOVE WS-BEARING TO WS-BEARING-2.

           COMPUTE WS-RESULT = WS-BEARING-2 - WS-BEARING-1.
           MOVE WS-RESULT TO WS-RESULT-POS.
           MOVE WS-RESULT-POS TO WS-INTEGER-PART.
           COMPUTE WS-DECIMAL-PART = WS-RESULT-POS - WS-INTEGER-PART.
           COMPUTE WS-INTEGER-PART = FUNCTION MOD(WS-INTEGER-PART 360).
           IF WS-RESULT > 0
               COMPUTE WS-RESULT = WS-INTEGER-PART + WS-DECIMAL-PART
           ELSE
               COMPUTE WS-RESULT =
                   (WS-INTEGER-PART + WS-DECIMAL-PART) * -1
           END-IF.

           IF WS-RESULT < -180
               COMPUTE WS-RESULT = WS-RESULT + 360.
           IF WS-RESULT > 180
               COMPUTE WS-RESULT = WS-RESULT - 360.
           COMPUTE WS-RESULT-OUT ROUNDED = WS-RESULT.

           DISPLAY REC-CTR ' ' WS-RESULT-OUT.

           PERFORM 150-READ-RECORD.

       250-CONVERT-DATA.
           MOVE WS-AB-INTEGER-PART      TO WSB-INTEGER-PART.
           MOVE WS-AB-DECIMAL-PART      TO WSB-DECIMAL-PART.
           IF WS-AB-NEGATIVE
               SUBTRACT WS-BEARING      FROM ZERO
                 GIVING                 WS-BEARING
           END-IF.

       300-TERMINATE.
           DISPLAY 'RECORDS PROCESSED: ' REC-CTR.
           CLOSE IN-FILE.

      ******************************************************************
      *    INPUT FILE ('Angle_diff.txt' stored on my PC at:
      *            'C:\Both\Rosetta\Angle_diff.txt'
      ******************************************************************
      *     +000020.000000000000 +000045.000000000000
      *     -000045.000000000000 +000045.000000000000
      *     -000085.000000000000 +000090.000000000000
      *     -000095.000000000000 +000090.000000000000
      *     -000045.000000000000 +000125.000000000000
      *     -000045.000000000000 +000145.000000000000
      *     +000029.480300000000 -000088.638100000000
      *     -000078.325100000000 -000159.036000000000
      *     -070099.742338109380 +029840.674378767230
      *     -165313.666629735700 +033693.989451745600
      *     +001174.838051059846 -154146.664901247570
      *     +060175.773067955460 +042213.071923543730
      ******************************************************************
      *    OUTPUT:
      ******************************************************************
      *     001      25.0000
      *     002      90.0000
      *     003     175.0000
      *     004    -175.0000
      *     005     170.0000
      *     006    -170.0000
      *     007    -118.1184
      *     008     -80.7109
      *     009    -139.5833
      *     010     -72.3439
      *     011    -161.5030
      *     012      37.2989
      ******************************************************************


(defun angle-difference (b1 b2)
	   (let ((diff (mod (- b2 b1) 360)))
	     (if (< diff -180)
		 (incf diff 360)
		 (if (> diff 180)
		     (decf diff 360)
		     diff))))


-module(bearings).

%% API
-export([angle_sub_degrees/2,test/0]).

-define(RealAngleMultiplier,16#10000000000).
-define(DegreesPerTurn,360).
-define(Precision,9).
%%%===================================================================
%%% API
%%%===================================================================

%%--------------------------------------------------------------------
%% @doc
%% @spec
%% @end
%%--------------------------------------------------------------------
%%
angle_sub_degrees(B1,B2) when is_integer(B1), is_integer(B2) ->
    angle_sub(B2-B1,?DegreesPerTurn);
angle_sub_degrees(B1,B2) ->
    NewB1 = trunc(B1*?RealAngleMultiplier),
    NewB2 = trunc(B2*?RealAngleMultiplier),
    round(angle_sub(NewB2 - NewB1,
	      ?DegreesPerTurn*?RealAngleMultiplier)
	/?RealAngleMultiplier,?Precision).

%%%===================================================================
%%% Internal functions
%%%===================================================================

%% delta normalises the angle difference.  Consider a turn from 350 degrees
%% to 20 degrees.  Subtraction results in 330 degress.  This is equivalent of
%% a turn in the other direction of 30 degrees, thus 330 degrees is equal
%% to -30 degrees.

angle_sub(Value,TurnSize) ->
    NormalisedValue = Value rem TurnSize,
    minimise_angle(NormalisedValue,TurnSize).

% X rem Turn result in 0..Turn for X > 0 and -Turn..0 for X < 0
% specification requires -Turn/2 < X < Turn/2.  This is achieved
% by adding or removing a turn as required.
% bsr 1 divides an integer by 2
minimise_angle(Angle,Turn) when Angle + (Turn bsr 1) < 0 ->
    Angle+Turn;
minimise_angle(Angle,Turn) when Angle - (Turn bsr 1) > 0 ->
    Angle-Turn;
minimise_angle(Angle,_) ->
    Angle.

round(Number,Precision) ->
    P = math:pow(10,Precision),
    round(Number*P)/P.

test() ->
    25 = angle_sub_degrees(20,45),
    90 = angle_sub_degrees(-45,45),
    175 = angle_sub_degrees(-85,90),
    -175 = angle_sub_degrees(-95,90),
    170 = angle_sub_degrees(-45,125),
    -170 = angle_sub_degrees(-45,145),
    -118.1184 = angle_sub_degrees( 29.4803,-88.6381),
    -139.583283124=angle_sub_degrees(-70099.742338109,29840.674378767),
    -72.343918514=angle_sub_degrees( -165313.66662974,33693.989451746),
    -161.50295231=angle_sub_degrees(  1174.8380510598,-154146.66490125),
    37.298855589=angle_sub_degrees(  60175.773067955,42213.071923544),

    passed.


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


: Angle-Difference-stack ( b1 b2 - a +/-180)
\ Algorithm  with stack manipulation without branches ( s. Frotran Groovy)
     fswap f-                   \ Delta angle
     360e fswap fover fmod      \ mod 360
     fover 1.5e f* f+           \ +   540
     fover fmod                 \ mod 360
     fswap f2/  f-              \ -   180
;
: Angle-Difference-const  ( b1 b2 - a +/-180)
\ Algorithm  without  Branches ( s. Fotran Groovy)
     fswap f-
     360e  fmod
     540e  f+
     360e fmod
     180e  f-
;

\  Test Word  for  requested tests
: test-ad    ( b1 b2 -- )
   fover fover
   Angle-Difference-stack  f.
   Angle-Difference-const  f.
;


      SUBROUTINE BDIFF (B1,B2)	!Difference B2 - B1, as bearings. All in degrees, not radians.
       REAL*8 B1,B2	!Maximum precision, for large-angle folding.
       COMPLEX*16 CIS,Z1,Z2,Z	!Scratchpads.
       CIS(T) = CMPLX(COSD(T),SIND(T))	!Convert an angle into a unit vector.
        Z1 = CIS(90 - B1)	!Bearings run clockwise from north (y) around to east (x).
        Z2 = CIS(90 - B2)	!Mathematics runs counterclockwise from x (east).
        Z = Z1*CONJG(Z2)	!(Z1x,Z1y)(Z2x,-Z2y) = (Z1x.Z2x + Z1y.Z2y, Z1y.Z2x - Z1x.Z2y)
        T = ATAN2D(AIMAG(Z),REAL(Z))	!Madly, arctan(x,y) is ATAN(Y,X)!
        WRITE (6,10) B1,Z1,B2,Z2,T	!Two sets of numbers, and a result.
   10   FORMAT (2(F14.4,"(",F9.6,",",F9.6,")"),F9.3)	!Two lots, and a tail.
      END SUBROUTINE BDIFF	!Having functions in degrees saves some bother.

      PROGRAM ORIENTED
      REAL*8 B(24)	!Just prepare a wad of values.
      DATA B/20D0,45D0, -45D0,45D0, -85D0,90D0, -95D0,90D0,	!As specified.
     1      -45D0,125D0, -45D0,145D0, 29.4803D0,-88.6381D0,
     2      -78.3251D0,              -159.036D0,
     3   -70099.74233810938D0,      29840.67437876723D0,
     4  -165313.6666297357D0,       33693.9894517456D0,
     5     1174.8380510598456D0,  -154146.66490124757D0,
     6    60175.77306795546D0,      42213.07192354373D0/

      WRITE (6,1) ("B",I,"x","y", I = 1,2)	!Or, one could just list them twice.
    1 FORMAT (28X,"Bearing calculations, in degrees"//
     * 2(A13,I1,"(",A9,",",A9,")"),A9)	!Compare format 10, above.

      DO I = 1,23,2	!Step through the pairs.
        CALL BDIFF(B(I),B(I + 1))
      END DO

      END


' version 28-01-2019
' compile with: fbc -s console

#Include "string.bi"

Function frmt(num As Double) As String

    Dim As String temp = Format(num, "#######.#############")
    Dim As Integer i = Len(temp) -1

    If temp[i] = Asc(".") Then temp[i] = 32
    If InStr(temp, ".") = 0 Then
        Return Right(Space(10) + temp, 9) + Space(13)
    End If
    temp = Space(10) + temp + Space(13)
    Return Mid(temp, InStr(temp, ".") -8, 22)

End Function

' ------=< MAIN >=------

Dim As Double b1, b2, bb1, bb2, diff

Print
Print "      b1                    b2                    difference"
Print " -----------------------------------------------------------"

Do
    Read b1, b2
    If b1 = 0 And b2 = 0 Then Exit Do
    diff = b2 - b1
    diff = diff - Int(diff / 360) * 360
    If diff > 180 Then diff -= 360
    Print frmt(b1); frmt(b2); frmt(diff)
Loop

Data   20,45,   -45,45,   -85,90
Data  -95,90,   -45,125,   -45,145
Data  29.4803,-88.6381,  -78.3251,-159.036
Data  -70099.74233810938,     29840.67437876723
Data -165313.6666297357,      33693.9894517456
Data    1174.8380510598456, -154146.66490124757
Data   60175.77306795546,     42213.07192354373

' empty keyboard buffer
While InKey <> "" : Wend
Print : Print "hit any key to end program"
Sleep
End


package main

import "fmt"

type bearing float64

var testCases = []struct{ b1, b2 bearing }{
    {20, 45},
    {-45, 45},
    {-85, 90},
    {-95, 90},
    {-45, 125},
    {-45, 145},
    {29.4803, -88.6381},
    {-78.3251, -159.036},
}

func main() {
    for _, tc := range testCases {
        fmt.Println(tc.b2.Sub(tc.b1))
    }
}

func (b2 bearing) Sub(b1 bearing) bearing {
    switch d := b2 - b1; {
    case d < -180:
        return d + 360
    case d > 180:
        return d - 360
    default:
        return d
    }
}


import Control.Monad (join)
import Data.Bifunctor (bimap)
import Text.Printf (printf)

type Radians = Float

type Degrees = Float

---------- ANGLE DIFFERENCE BETWEEN TWO BEARINGS ---------

bearingDelta :: (Radians, Radians) -> Radians
bearingDelta (a, b) -- sign * dot-product
  =
  sign * acos ((ax * bx) + (ay * by))
  where
    (ax, ay) = (sin a, cos a)
    (bx, by) = (sin b, cos b)
    sign
      | ((ay * bx) - (by * ax)) > 0 = 1
      | otherwise = -1

angleBetweenDegrees :: (Degrees, Degrees) -> Degrees
angleBetweenDegrees =
  degrees
    . bearingDelta
    . join bimap radians

--------------------------- TEST -------------------------
main :: IO ()
main =
  putStrLn . unlines $
    fmap
      ( uncurry (printf "%6.2f° - %6.2f°  ->  %7.2f°")
          <*> angleBetweenDegrees
      )
      [ (20.0, 45.0),
        (-45.0, 45.0),
        (-85.0, 90.0),
        (-95.0, 90.0),
        (-45.0, 125.0),
        (-45.0, 145.0)
      ]

------------------------- GENERIC ------------------------

degrees :: Radians -> Degrees
degrees = (/ pi) . (180 *)

radians :: Degrees -> Radians
radians = (/ 180) . (pi *)


100 INPUT PROMPT "1. angle: ":A1
110 INPUT PROMPT "2. angle: ":A2
120 LET B=MOD(A2-A1,360)
130 IF B>180 THEN LET B=B-360
140 IF B<-180 THEN LET B=B+360
150 PRINT "Difference: ";B


public class AngleDifference {

    public static double getDifference(double b1, double b2) {
        double r = (b2 - b1) % 360.0;
        if (r < -180.0)
            r += 360.0;
        if (r >= 180.0)
            r -= 360.0;
        return r;
    }

    public static void main(String[] args) {
        System.out.println("Input in -180 to +180 range");
        System.out.println(getDifference(20.0, 45.0));
        System.out.println(getDifference(-45.0, 45.0));
        System.out.println(getDifference(-85.0, 90.0));
        System.out.println(getDifference(-95.0, 90.0));
        System.out.println(getDifference(-45.0, 125.0));
        System.out.println(getDifference(-45.0, 145.0));
        System.out.println(getDifference(-45.0, 125.0));
        System.out.println(getDifference(-45.0, 145.0));
        System.out.println(getDifference(29.4803, -88.6381));
        System.out.println(getDifference(-78.3251, -159.036));

        System.out.println("Input in wider range");
        System.out.println(getDifference(-70099.74233810938, 29840.67437876723));
        System.out.println(getDifference(-165313.6666297357, 33693.9894517456));
        System.out.println(getDifference(1174.8380510598456, -154146.66490124757));
        System.out.println(getDifference(60175.77306795546, 42213.07192354373));
    }
}


function relativeBearing(b1Rad, b2Rad)
{
	b1y = Math.cos(b1Rad);
	b1x = Math.sin(b1Rad);
	b2y = Math.cos(b2Rad);
	b2x = Math.sin(b2Rad);
	crossp = b1y * b2x - b2y * b1x;
	dotp = b1x * b2x + b1y * b2y;
	if(crossp > 0.)
		return Math.acos(dotp);
	return -Math.acos(dotp);
}

function test()
{
	var deg2rad = 3.14159265/180.0;
	var rad2deg = 180.0/3.14159265;
	return "Input in -180 to +180 range\n"
		+relativeBearing(20.0*deg2rad, 45.0*deg2rad)*rad2deg+"\n"
		+relativeBearing(-45.0*deg2rad, 45.0*deg2rad)*rad2deg+"\n"
		+relativeBearing(-85.0*deg2rad, 90.0*deg2rad)*rad2deg+"\n"
		+relativeBearing(-95.0*deg2rad, 90.0*deg2rad)*rad2deg+"\n"
		+relativeBearing(-45.0*deg2rad, 125.0*deg2rad)*rad2deg+"\n"
		+relativeBearing(-45.0*deg2rad, 145.0*deg2rad)*rad2deg+"\n"

		+relativeBearing(29.4803*deg2rad, -88.6381*deg2rad)*rad2deg+"\n"
		+relativeBearing(-78.3251*deg2rad, -159.036*deg2rad)*rad2deg+"\n"

		+ "Input in wider range\n"
		+relativeBearing(-70099.74233810938*deg2rad, 29840.67437876723*deg2rad)*rad2deg+"\n"
		+relativeBearing(-165313.6666297357*deg2rad, 33693.9894517456*deg2rad)*rad2deg+"\n"
		+relativeBearing(1174.8380510598456*deg2rad, -154146.66490124757*deg2rad)*rad2deg+"\n"
		+relativeBearing(60175.77306795546*deg2rad, 42213.07192354373*deg2rad)*rad2deg+"\n";

}


bearing = {degrees = 0} -- prototype object

function bearing:assign(angle)
	angle = tonumber(angle) or 0
	while angle > 180 do
		angle = angle - 360
	end
	while angle < -180 do
		angle = angle + 360
	end
	self.degrees = angle
end

function bearing:new(size)
	local child_object = {}
	setmetatable(child_object, {__index = self})
	child_object:assign(size)
	return child_object
end

function bearing:subtract(other)
	local difference = self.degrees - other.degrees
	return self:new(difference)
end

function bearing:list(sizes)
	local bearings = {}
	for index, size in ipairs(sizes) do
		table.insert(bearings, self:new(size))
	end
	return bearings
end

function bearing:text()
	return string.format("%.4f deg", self.degrees)
end

function main()
	local subtrahends = bearing:list{
		20, -45, -85, -95, -45, -45, 29.4803, -78.3251,
		-70099.74233810938, -165313.6666297357,
		1174.8380510598456, 60175.77306795546
	}
	local minuends = bearing:list{
		45, 45, 90, 90, 125, 145, -88.6381, -159.036,
		29840.67437876723, 33693.9894517456,
		-154146.66490124757, 42213.07192354373
	}
	for index = 1, #minuends do
		local b2, b1 = minuends[index], subtrahends[index]
		local b3 = b2:subtract(b1)
		local statement = string.format(
			"%s - %s = %s\n",
			b2:text(), b1:text(), b3:text()
		)
		io.write(statement)
	end
end

main()


FROM Terminal IMPORT *;

PROCEDURE WriteRealLn(value : REAL);
VAR str : ARRAY[0..16] OF CHAR;
BEGIN
    RealToStr(value, str);
    WriteString(str);
    WriteLn;
END WriteRealLn;

PROCEDURE AngleDifference(b1, b2 : REAL) : REAL;
VAR r : REAL;
BEGIN
    r := (b2 - b1);
    WHILE r < -180.0 DO
        r := r + 360.0;
    END;
    WHILE r >= 180.0 DO
        r := r - 360.0;
    END;
    RETURN r;
END AngleDifference;

BEGIN
    WriteString('Input in -180 to +180 range');
    WriteLn;
    WriteRealLn(AngleDifference(20.0, 45.0));
    WriteRealLn(AngleDifference(-45.0, 45.0));
    WriteRealLn(AngleDifference(-85.0, 90.0));
    WriteRealLn(AngleDifference(-95.0, 90.0));
    WriteRealLn(AngleDifference(-45.0, 125.0));
    WriteRealLn(AngleDifference(-45.0, 145.0));
    WriteRealLn(AngleDifference(29.4803, -88.6381));
    WriteRealLn(AngleDifference(-78.3251, -159.036));

    WriteString('Input in wider range');
    WriteLn;
    WriteRealLn(AngleDifference(-70099.74233810938, 29840.67437876723));
    WriteRealLn(AngleDifference(-165313.6666297357, 33693.9894517456));
    WriteRealLn(AngleDifference(1174.8380510598456, -154146.66490124757));
    WriteRealLn(AngleDifference(60175.77306795546, 42213.07192354373));

    ReadChar;
END Bearings.


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


Program Bearings;
{ Reads pairs of angles from a file and subtracts them }

Const
  fileName = 'angles.txt';

Type
  degrees = real;

Var
  subtrahend, minuend: degrees;
  angleFile: text;

function Simplify(angle: degrees): degrees;
{ Returns an number in the range [-180.0, 180.0] }
  begin
    while angle > 180.0 do
      angle := angle - 360.0;
    while angle < -180.0 do
      angle := angle + 360.0;
    Simplify := angle
  end;

function Difference(b1, b2: degrees): degrees;
{ Subtracts b1 from b2 and returns a simplified result }
  begin
    Difference := Simplify(b2 - b1)
  end;

procedure Subtract(b1, b2: degrees);
{ Subtracts b1 from b2 and shows the whole equation onscreen }
  var
    b3: degrees;
  begin
    b3 := Difference(b1, b2);
    writeln(b2:20:11, '   - ', b1:20:11, '   = ', b3:20:11)
  end;

Begin
  assign(angleFile, fileName);
  reset(angleFile);
  while not eof(angleFile) do
    begin
      readln(angleFile, subtrahend, minuend);
      Subtract(subtrahend, minuend)
    end;
  close(angleFile)
End.


<#
.Synopsis
   Gets the difference between two angles between the values of -180 and 180.
   To see examples use "Get-Examples"
.DESCRIPTION
   This code uses the modulo operator, this is represented with the "%".
   The  modulo operator returns the remainder after division, as displayed below
   3 % 2 = 1
   20 % 15 = 5
   200 % 146 = 54

.EXAMPLE
    PS C:\WINDOWS\system32> Get-AngleDiff
    cmdlet Get-AngleDiff at command pipeline position 1
    Supply values for the following parameters:
    angle1: 45
    angle2: -85

    The difference between 45 and -85 is -130

    PS C:\WINDOWS\system32>

.EXAMPLE
    PS C:\WINDOWS\system32> Get-AngleDiff -angle1 50 -angle2 -65

    The difference between 50 and -65 is -115

    PS C:\WINDOWS\system32>

.EXAMPLE
    PS C:\WINDOWS\system32> Get-AngleDiff -89 50

    The difference between -89 and 50 is 139

    PS C:\WINDOWS\system32>

#>
function Get-AngleDiff
{
    [CmdletBinding()]

    Param
    (
        # Angle one input, must be a number
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true)][double]$angle1,

        # Angle two input, must be a number
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true)][double]$angle2
                   )

    Begin
    {
    #This is the equation to calculate the difference
    [double]$Difference = ($angle2 - $angle1) % 360.0
    }

    Process
    {
    #If/IfElse/Else block to return results within the requested range
    if ($Difference -lt -180.0)
        {$Difference += 360.0
        }

    elseif ($Difference -gt 360.0)
        {$Difference -= 360.0
        }

    #Writes the values given by the user and the result
    Write-Host "The difference between $angle1 and $angle2 is $Difference"
    }

    End
    {
    }

}

<#
.Synopsis
   This is simply the outputs of the Get-AngleDiff Function in a function
.EXAMPLE
PS C:\WINDOWS\system32> Get-Examples

Inputs from the -180 to 180 range
The difference between 20 and 45 is 25
The difference between -45 and 45 is 90
The difference between -85 and 90 is 175
The difference between -95 and 90 is 185
The difference between -45 and 125 is 170
The difference between -45 and 145 is 190
The difference between -45 and 125 is 170
The difference between -45 and 145 is 190
The difference between 29.4803 and -88.6381 is -118.1184
The difference between -78.3251 and -159.036 is -80.7109

Inputs from a wider range
The difference between -70099.7423381094 and 29840.6743787672 is 220.416716876614
The difference between -165313.666629736 and 33693.9894517456 is 287.656081481313
The difference between 1174.83805105985 and -154146.664901248 is -161.502952307404
The difference between 60175.7730679555 and 42213.0719235437 is 37.2988555882694

PS C:\WINDOWS\system32>
#>

function Get-Examples
{
    #blank write-host is used for a blank line to make the output look a lil cleaner
    Write-Host
    Write-Host "Inputs from the -180 to 180 range"

    Get-AngleDiff 20.0 45.0
    Get-AngleDiff -45.0 45.0
    Get-AngleDiff -85.0 90.0
    Get-AngleDiff -95.0 90.0
    Get-AngleDiff -45.0 125.0
    Get-AngleDiff -45.0 145.0
    Get-AngleDiff -45.0 125.0
    Get-AngleDiff -45.0 145.0
    Get-AngleDiff 29.4803 -88.6381
    Get-AngleDiff -78.3251 -159.036

    Write-Host
    Write-Host "Inputs from a wider range"

    Get-AngleDiff -70099.74233810938 29840.67437876723
    Get-AngleDiff -165313.6666297357 33693.9894517456
    Get-AngleDiff 1174.8380510598456 -154146.66490124757
    Get-AngleDiff 60175.77306795546 42213.07192354373

}


from __future__ import print_function

def getDifference(b1, b2):
	r = (b2 - b1) % 360.0
	# Python modulus has same sign as divisor, which is positive here,
	# so no need to consider negative case
	if r >= 180.0:
		r -= 360.0
	return r

if __name__ == "__main__":
	print ("Input in -180 to +180 range")
	print (getDifference(20.0, 45.0))
	print (getDifference(-45.0, 45.0))
	print (getDifference(-85.0, 90.0))
	print (getDifference(-95.0, 90.0))
	print (getDifference(-45.0, 125.0))
	print (getDifference(-45.0, 145.0))
	print (getDifference(-45.0, 125.0))
	print (getDifference(-45.0, 145.0))
	print (getDifference(29.4803, -88.6381))
	print (getDifference(-78.3251, -159.036))

	print ("Input in wider range")
	print (getDifference(-70099.74233810938, 29840.67437876723))
	print (getDifference(-165313.6666297357, 33693.9894517456))
	print (getDifference(1174.8380510598456, -154146.66490124757))
	print (getDifference(60175.77306795546, 42213.07192354373))


/*REXX pgm calculates difference between two angles (in degrees), normalizes the result.*/
numeric digits 25                                    /*use enough dec. digits for angles*/
call show      20,                    45             /*display angular difference (deg).*/
call show     -45,                    45             /*   "       "        "        "   */
call show     -85,                    90             /*   "       "        "        "   */
call show     -95,                    90             /*   "       "        "        "   */
call show     -45,                   125             /*   "       "        "        "   */
call show      45,                   145             /*   "       "        "        "   */
call show      29.4803,              -88.6361        /*   "       "        "        "   */
call show     -78.3251,             -159.036         /*   "       "        "        "   */
call show  -70099.74233810938,     29840.67437876723 /*   "       "        "        "   */
call show -165313.6666297357,      33693.9894517456  /*   "       "        "        "   */
call show    1174.8380510598456, -154146.66490124757 /*   "       "        "        "   */
call show   60175.773067955546,    42213.07192354373 /*   "       "        "        "   */
exit                                                 /*stick a fork in it,  we're done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
show: parse arg a,b;    d=digits();     $='º'    /*obtain the 2 angles (are in degrees).*/
      x=format( ( ( ((b-a) // 360) + 540) // 360) - 180, 4, d)   /*compute and format.  */
      if pos(., x)\==0  then x=strip( strip(x, 'T', 0), "T", .)  /*strip trailing chaff.*/
      say center(a || $, d)      '─'      center(b || $, d)       " ────► "      x || $
      return                                     /* [↑]  display the angular difference.*/


# Project : Angle difference between two bearings

decimals(4)
see "Input in -180 to +180 range:" + nl
see getDifference(20.0, 45.0) + nl
see getDifference(-45.0, 45.0) + nl
see getDifference(-85.0, 90.0) + nl
see getDifference(-95.0, 90.0) + nl
see getDifference(-45.0, 125.0) + nl
see getDifference(-45.0, 145.0) + nl
see getDifference(-45.0, 125.0) + nl
see getDifference(-45.0, 145.0) + nl
see getDifference(29.4803, -88.6381) + nl
see getDifference(-78.3251, -159.036) + nl

func getDifference(b1, b2)
     r = (b2 - b1) % 360.0
     if r >= 180.0
        r = r - 360.0
     end
     return r


def getDifference(b1, b2)
	r = (b2 - b1) % 360.0
	# Ruby modulus has same sign as divisor, which is positive here,
	# so no need to consider negative case
	if r >= 180.0
		r -= 360.0
	end
	return r
end

if __FILE__ == $PROGRAM_NAME
	puts "Input in -180 to +180 range"
	puts getDifference(20.0, 45.0)
	puts getDifference(-45.0, 45.0)
	puts getDifference(-85.0, 90.0)
	puts getDifference(-95.0, 90.0)
	puts getDifference(-45.0, 125.0)
	puts getDifference(-45.0, 145.0)
	puts getDifference(-45.0, 125.0)
	puts getDifference(-45.0, 145.0)
	puts getDifference(29.4803, -88.6381)
	puts getDifference(-78.3251, -159.036)

	puts "Input in wider range"
	puts getDifference(-70099.74233810938, 29840.67437876723)
	puts getDifference(-165313.6666297357, 33693.9894517456)
	puts getDifference(1174.8380510598456, -154146.66490124757)
	puts getDifference(60175.77306795546, 42213.07192354373)
end


sub getDifference b1, b2
    r = (b2 - b1) mod 360
    if r >= 180 then r = r - 360
    print r
end sub

print "Input in -180 to +180 range:"
call getDifference  20, 45
call getDifference -45, 45
call getDifference -85, 90
call getDifference -95, 90
call getDifference -45, 125
call getDifference -45, 145
call getDifference -45, 125
call getDifference -45, 145
call getDifference  29.4803, -88.6381
call getDifference -78.3251, -159.036
print "Input in wider range:"
call getDifference -70099.74233810938, 29840.67437876723
call getDifference -165313.6666297357, 33693.9894517456
call getDifference 1174.8380510598456, -154146.66490124757


object AngleDifference extends App {
  private def getDifference(b1: Double, b2: Double) = {
    val r = (b2 - b1) % 360.0
    if (r < -180.0) r + 360.0 else if (r >= 180.0) r - 360.0 else r
  }

  println("Input in -180 to +180 range")
  println(getDifference(20.0, 45.0))
  println(getDifference(-45.0, 45.0))
  println(getDifference(-85.0, 90.0))
  println(getDifference(-95.0, 90.0))
  println(getDifference(-45.0, 125.0))
  println(getDifference(-45.0, 145.0))
  println(getDifference(-45.0, 125.0))
  println(getDifference(-45.0, 145.0))
  println(getDifference(29.4803, -88.6381))
  println(getDifference(-78.3251, -159.036))

  println("Input in wider range")
  println(getDifference(-70099.74233810938, 29840.67437876723))
  println(getDifference(-165313.6666297357, 33693.9894517456))
  println(getDifference(1174.8380510598456, -154146.66490124757))
  println(getDifference(60175.77306795546, 42213.07192354373))

}


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


Module Module1

    Function Delta_Bearing(b1 As Decimal, b2 As Decimal) As Decimal
        Dim d As Decimal = 0

        ' Convert bearing to W.C.B
        While b1 < 0
            b1 += 360
        End While
        While b1 > 360
            b1 -= 360
        End While

        While b2 < 0
            b2 += 360
        End While
        While b2 > 0
            b2 -= 360
        End While

        ' Calculate delta bearing
        d = (b2 - b1) Mod 360
        ' Convert result to Q.B
        If d > 180 Then
            d -= 360
        ElseIf d < -180 Then
            d += 360
        End If

        Return d
    End Function

    Sub Main()
        ' Calculate standard test cases
        Console.WriteLine(Delta_Bearing(20, 45))
        Console.WriteLine(Delta_Bearing(-45, 45))
        Console.WriteLine(Delta_Bearing(-85, 90))
        Console.WriteLine(Delta_Bearing(-95, 90))
        Console.WriteLine(Delta_Bearing(-45, 125))
        Console.WriteLine(Delta_Bearing(-45, 145))
        Console.WriteLine(Delta_Bearing(29.4803, -88.6381))
        Console.WriteLine(Delta_Bearing(-78.3251, -159.036))

        ' Calculate optional test cases
        Console.WriteLine(Delta_Bearing(-70099.742338109383, 29840.674378767231))
        Console.WriteLine(Delta_Bearing(-165313.6666297357, 33693.9894517456))
        Console.WriteLine(Delta_Bearing(1174.8380510598456, -154146.66490124757))
        Console.WriteLine(Delta_Bearing(60175.773067955459, 42213.071923543728))
    End Sub

End Module


import math
type Bearing = f64

const test_cases = [
    [Bearing(20), 45],
    [Bearing(-45), 45],
    [Bearing(-85), 90],
    [Bearing(-95), 90],
    [Bearing(-45), 125],
    [Bearing(-45), 145],
    [Bearing(29.4803), -88.6381],
    [Bearing(-78.3251), -159.036],
]

fn main() {
    for tc in test_cases {
        println(tc[1].sub(tc[0]))
        println(angle_difference(tc[1],tc[0]))
    }
}

fn (b2 Bearing) sub(b1 Bearing) Bearing {
    d := b2 - b1
    match true {
        d < -180 {
            return d + 360
        }
        d > 180 {
            return d - 360
        }
        else {
            return d
        }
    }
}
fn angle_difference(b2 Bearing, b1 Bearing) Bearing {
    return math.mod(math.mod(b2-b1, 360)+360+180, 360) - 180
}


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


// Rosetta Code problem: http://rosettacode.org/wiki/Angle_difference_between_two_bearings
// by Jjuanhdez, 06/2022

print "Input in -180 to +180 range:"
getDifference(20.0, 45.0)
getDifference(-45.0, 45.0)
getDifference(-85.0, 90.0)
getDifference(-95.0, 90.0)
getDifference(-45.0, 125.0)
getDifference(-45.0, 145.0)
getDifference(-45.0, 125.0)
getDifference(-45.0, 145.0)
getDifference(29.4803, -88.6381)
getDifference(-78.3251, -159.036)
print "\nInput in wider range:"
getDifference(-70099.74233810938, 29840.67437876723)
getDifference(-165313.6666297357, 33693.9894517456)
getDifference(1174.8380510598456, -154146.66490124757)
end

sub getDifference(b1, b2)
    r = mod((b2 - b1), 360.0)
    if r >= 180.0  r = r - 360.0
    print r
end sub


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


F isqrt(BigInt =x)
   BigInt q = 1
   BigInt r = 0
   BigInt t
   L q <= x
      q *= 4
   L q > 1
      q I/= 4
      t = x - r - q
      r I/= 2
      I t >= 0
         x = t
         r += q
   R r

F dump(=digs, show)
   V gb = 1
   digs++
   V dg = digs + gb
   BigInt t1 = 1
   BigInt t2 = 9
   BigInt t3 = 1
   BigInt te
   BigInt su = 0
   V t = BigInt(10) ^ (I dg <= 60 {0} E dg - 60)
   BigInt d = -1
   BigInt _fn_ = 1

   V n = 0
   L n < dg
      I n > 0
         t3 *= BigInt(n) ^ 6
      te = t1 * t2 I/ t3
      V z = dg - 1 - n * 6
      I z > 0
         te *= BigInt(10) ^ z
      E
         te I/= BigInt(10) ^ -z
      I show & n < 10
         print(‘#2 #62’.format(n, te * 32 I/ 3 I/ t))
      su += te

      I te < 10
         I show
            digs--
            print("\n#. iterations required for #. digits after the decimal point.\n".format(n, digs))
         L.break

      L(j) n * 6 + 1 .. n * 6 + 6
         t1 *= j
      d += 2
      t2 += 126 + 532 * d

      n++

   V s = String(isqrt(BigInt(10) ^ (dg * 2 + 3) I/ su I/ 32 * 3 * BigInt(10) ^ (dg + 5)))
   R s[0]‘.’s[1 .+ digs]

print(dump(70, 1B))


/* ARM assembly AARCH64 Raspberry PI 3B */
/*  program calculPi64.s   */
/* this program use gmp library */
/* link with gcc option -lgmp */

/*******************************************/
/* Constantes file                         */
/*******************************************/
/* for this file see task include a file in language AArch64 assembly*/
.include "../includeConstantesARM64.inc"

.equ MAXI,      10
.equ SIZEBIG,   100

/*********************************/
/* Initialized data              */
/*********************************/
.data
szMessDebutPgm:     .asciz "Program 64 bits start. \n"
szMessPi:           .asciz "\nPI = \n"
szCarriageReturn:   .asciz "\n"

szFormat:           .asciz " %Zd\n"
szFormatFloat:      .asciz " %.*Ff\n"
/*********************************/
/* UnInitialized data            */
/*********************************/
.bss
Result1:                    .skip SIZEBIG
Result2:                    .skip SIZEBIG
Result3:                    .skip SIZEBIG
Result4:                    .skip SIZEBIG
fIntex5:                    .skip SIZEBIG
fIntex6:                    .skip SIZEBIG
fIntex7:                    .skip SIZEBIG
fSum:                       .skip SIZEBIG
fSum1:                      .skip SIZEBIG
sBuffer:                    .skip SIZEBIG
fEpsilon:                   .skip SIZEBIG
fPrec:                      .skip SIZEBIG
fPI:                        .skip SIZEBIG
fTEN:                       .skip SIZEBIG
fONE:                       .skip SIZEBIG
/*********************************/
/*  code section                 */
/*********************************/
.text
.global main
main:                             // entry of program
    ldr x0,qAdrszMessDebutPgm
    bl affichageMess
    mov x20,#0                     // loop indice
1:
    mov x0,x20
    bl computeAlmkvist            // compute
    mov x1,x0
    ldr x0,qAdrszFormat           // print big integer
    bl __gmp_printf

    add x20,x20,#1
    cmp x20,#MAXI
    blt 1b                        // and loop

    mov x0,#560                   // float précision in bits
    bl __gmpf_set_default_prec

    mov x19,#0                     // compute indice
    ldr x0,qAdrfSum               // init to zéro
    bl __gmpf_init
    ldr x0,qAdrfSum1              // init to zéro
    bl __gmpf_init

    ldr x0,qAdrfONE               // result address
    mov x1,#1                     // init à 1
    bl __gmpf_init_set_ui

    ldr x0,qAdrfIntex5            // init to zéro
    bl __gmpf_init
    ldr x0,qAdrfIntex6            // init to zéro
    bl __gmpf_init
    ldr x0,qAdrfIntex7            // init to zéro
    bl __gmpf_init
    ldr x0,qAdrfEpsilon           // init to zéro
    bl __gmpf_init
    ldr x0,qAdrfPrec              // init to zéro
    bl __gmpf_init
    ldr x0,qAdrfPI                // init to zéro
    bl __gmpf_init
    ldr x0,qAdrfTEN
    mov x1,#10                    // init to 10
    bl __gmpf_init_set_ui

    ldr x0,qAdrfIntex6            // compute 10 pow 70
    ldr x1,qAdrfTEN
    mov x2,#70
    bl __gmpf_pow_ui

    ldr x0,qAdrfEpsilon           // divide 1 by 10 pow 70
    ldr x1,qAdrfONE               // dividende
    ldr x2,qAdrfIntex6            // divisor
    bl __gmpf_div

2:                                // PI compute loop
    mov x0,x19
    bl computeAlmkvist
    mov x20,x0
    mov x1,#6
    mul x2,x1,x19
    add x6,x2,#3                  // compute 6n + 3

    ldr x0,qAdrfIntex6            // compute 10 pow (6n+3)
    ldr x1,qAdrfTEN
    mov x2,x6
    bl __gmpf_pow_ui

    ldr x0,qAdrfIntex7             // compute 1 / 10 pow (6n+3)
    ldr x1,qAdrfONE                // dividende
    ldr x2,qAdrfIntex6             // divisor
    bl __gmpf_div

    ldr x0,qAdrfIntex6             // result big float
    mov x1,x20                     // big integer Almkvist
    bl __gmpf_set_z                // conversion in big float

    ldr x0,qAdrfIntex5             // result Almkvist * 1 / 10 pow (6n+3)
    ldr x1,qAdrfIntex7             // operator 1
    ldr x2,qAdrfIntex6             // operator 2
    bl __gmpf_mul

    ldr x0,qAdrfSum1               // terms addition
    ldr x1,qAdrfSum
    ldr x2,qAdrfIntex5
    bl __gmpf_add

    ldr x0,qAdrfSum                // copy terms
    ldr x1,qAdrfSum1
    bl __gmpf_set

    ldr x0,qAdrfIntex7             // compute 1 / sum
    ldr x1,qAdrfONE                // dividende
    ldr x2,qAdrfSum                // divisor
    bl __gmpf_div

    ldr x0,qAdrfPI                 // compute square root (1 / sum )
    ldr x1,qAdrfIntex7
    bl __gmpf_sqrt

    ldr x0,qAdrfIntex6             // compute variation PI
    ldr x1,qAdrfPrec
    ldr x2,qAdrfPI
    bl __gmpf_sub

    ldr x0,qAdrfIntex6             // absolue value
    ldr x1,qAdrfIntex5
    bl __gmpf_abs

    add x19,x19,#1                   // increment indice

    ldr x0,qAdrfPrec               // copy PI -> prévious
    ldr x1,qAdrfPI
    bl __gmpf_set

    ldr x0,qAdrfIntex6             // compare gap and epsilon
    ldr x1,qAdrfEpsilon
    bl __gmpf_cmp
    cmp w0,#0                      // !!! cmp return result on 32 bits
    bgt 2b                         // if gap is highter -> loop

    ldr x0,qAdrszMessPi            // title display
    bl affichageMess

    ldr x2,qAdrfPI                 // PI display
    ldr x0,qAdrszFormatFloat
    mov x1,#70
    bl __gmp_printf

100:                              // standard end of the program
    mov x0, #0                    // return code
    mov x8, #EXIT                 // request to exit program
    svc #0                        // perform the system call
qAdrszMessDebutPgm:          .quad szMessDebutPgm
qAdrszCarriageReturn:        .quad szCarriageReturn
qAdrfIntex5:                 .quad fIntex5
qAdrfIntex6:                 .quad fIntex6
qAdrfIntex7:                 .quad fIntex7
qAdrfSum:                    .quad fSum
qAdrfSum1:                   .quad fSum1
qAdrszFormatFloat:           .quad szFormatFloat
qAdrszMessPi:                .quad szMessPi
qAdrfEpsilon:                .quad fEpsilon
qAdrfPrec:                   .quad fPrec
qAdrfPI:                     .quad fPI
qAdrfTEN:                    .quad fTEN
qAdrfONE:                    .quad fONE
/***************************************************/
/*   compute  almkvist_giullera formula             */
/***************************************************/
/* x0 contains the number            */
computeAlmkvist:
    stp x19,lr,[sp,-16]!           // save  registers
    mov x19,x0
    mov x1,#6
    mul x0,x1,x0
    ldr x1,qAdrResult1            // result address
    bl computeFactorielle         // compute (n*6)!
    mov x1,#532
    mul x2,x19,x19
    mul x2,x1,x2
    mov x1,#126
    mul x3,x19,x1
    add x2,x2,x3
    add x2,x2,#9
    lsl x2,x2,#5                   // * 32

    ldr x0,qAdrResult2             // result
    ldr x1,qAdrResult1             // operator
    bl __gmpz_mul_ui

    mov x0,x19
    ldr x1,qAdrResult1
    bl computeFactorielle

    ldr x0,qAdrResult3
    bl __gmpz_init                 // init to 0

    ldr x0,qAdrResult3             // result
    ldr x1,qAdrResult1             // operator
    mov x2,#6
    bl __gmpz_pow_ui

    ldr x0,qAdrResult1             // result
    ldr x1,qAdrResult3             // operator
    mov x2,#3
    bl __gmpz_mul_ui

    ldr x0,qAdrResult3             // result
    ldr x1,qAdrResult2             // operator
    ldr x2,qAdrResult1             // operator
    bl __gmpz_cdiv_q

    ldr x0,qAdrResult3             // return result address
100:
    ldp x19,lr,[sp],16              // restaur  2 registers
    ret                            // return to address lr x30
qAdrszFormat:         .quad szFormat
qAdrResult1:          .quad Result1
qAdrResult2:          .quad Result2
qAdrResult3:          .quad Result3
/***************************************************/
/*   compute  factorielle N                        */
/***************************************************/
/* x0 contains the number            */
/* x1 contains big number result address */
computeFactorielle:
    stp x19,lr,[sp,-16]!           // save  registers
    stp x20,x21,[sp,-16]!           // save  registers
    mov x19,x0                     // save N
    mov x20,x1                     // save result address
    mov x0,x1                     // result address
    mov x1,#1                     // init to 1
    bl __gmpz_init_set_ui
    ldr x0,qAdrResult4
    bl __gmpz_init                // init to 0
    mov x21,#1
1:                                // loop
    ldr x0,qAdrResult4            // result
    mov x1,x20                     // operator 1
    mov x2,x21                     // operator 2
    bl __gmpz_mul_ui
    mov x0,x20                     // copy result4 -> result
    ldr x1,qAdrResult4
    bl __gmpz_set
    add x21,x21,#1                  // increment indice
    cmp x21,x19                     // N ?
    ble 1b                        // no -> loop

    ldr  x0,qAdrResult4
    ldp x20,x21,[sp],16              // restaur  2 registers
    ldp x19,lr,[sp],16              // restaur  2 registers
    ret                            // return to address lr x30
qAdrResult4:          .quad Result4
/********************************************************/
/*        File Include fonctions                        */
/********************************************************/
/* for this file see task include a file in language AArch64 assembly */
.include "../includeARM64.inc"