Elite on the BBC Micro and NES

# Version analysis of ARCTAN

This code appears in the following versions (click to see it in the source code):

Code variations between these versions are shown below.

```       Name: ARCTAN
Type: Subroutine
Category: Maths (Geometry)
Summary: Calculate A = arctan(P / Q)
Deep dive: The sine, cosine and arctan tables

Calculate the following:

A = arctan(P / Q)

In other words, this finds the angle in the right-angled triangle where the
opposite side to angle A is length P and the adjacent side to angle A has
length Q, so:

tan(A) = P / Q

The result in A is an integer representing the angle in radians. The routine
returns values in the range 0 to 128, which covers 0 to 180 degrees (or 0 to

```

Code variation 1 of 4A variation in the comments only

This variation is blank in the Cassette, Disc (flight), 6502 Second Processor and Electron versions.

```Master Other entry points:

ARSR1                Contains an RTS
```
```
.ARCTAN

```

Code variation 2 of 4A variation in the comments only

Tap on a block to expand it, and tap it again to revert.

```Cassette, 6502SP, MasterFlight, Electron LDA P                  \ Set T1 = P EOR Q, which will have the sign of P * Q
EOR Q                  \
\AND #%10000000         \ The AND is commented out in the original source
STA T1
LDA P                  \ Set T1 = P EOR Q, which will have the sign of P * Q
EOR Q
STA T1
```
``` LDA Q                  \ If Q = 0, jump to AR2 to return a right angle
BEQ AR2

ASL A                  \ Set Q = |Q| * 2 (this is a quick way of clearing the
STA Q                  \ sign bit, and we don't need to shift right again as we
\ only ever use this value in the division with |P| * 2,
\ which we set next)

LDA P                  \ Set A = |P| * 2
ASL A

CMP Q                  \ If A >= Q, i.e. |P| > |Q|, jump to AR1 to swap P
BCS AR1                \ and Q around, so we can still use the lookup table

JSR ARS1               \ Call ARS1 to set the following from the lookup table:
\
\   A = arctan(A / Q)
\     = arctan(|P / Q|)

SEC                    \ Set the C flag so the SBC instruction in AR3 will be
\ correct, should we jump there

.AR4

LDX T1                 \ If T1 is negative, i.e. P and Q have different signs,
BMI AR3                \ jump down to AR3 to return arctan(-|P / Q|)

RTS                    \ Otherwise P and Q have the same sign, so our result is
\ correct and we can return from the subroutine

.AR1

\ We want to calculate arctan(t) where |t| > 1, so we
\ can use the calculation described in the documentation
\ for the ACT table, i.e. 64 - arctan(1 / t)

LDX Q                  \ Swap the values in Q and P, using the fact that we
STA Q                  \ called AR1 with A = P
STX P                  \
TXA                    \ This also sets A = P (which now contains the original
\ argument |Q|)

JSR ARS1               \ Call ARS1 to set the following from the lookup table:
\
\   A = arctan(A / Q)
\     = arctan(|Q / P|)
\     = arctan(1 / |P / Q|)

STA T                  \ Set T = 64 - T
LDA #64
SBC T

BCS AR4                \ Jump to AR4 to continue the calculation (this BCS is
\ effectively a JMP as the subtraction will never
\ underflow, as ARS1 returns values in the range 0-31)

.AR2

\ If we get here then Q = 0, so tan(A) = infinity and
\ A is a right angle, or 0.25 of a circle. We allocate
\ 255 to a full circle, so we should return 63 for a
\ right angle

LDA #63                \ Set A to 63, to represent a right angle

RTS                    \ Return from the subroutine

.AR3

\ A contains arctan(|P / Q|) but P and Q have different
\ signs, so we need to return arctan(-|P / Q|), using
\ the calculation described in the documentation for the
\ ACT table, i.e. 128 - A

```

Code variation 3 of 4A variation in the comments only

Tap on a block to expand it, and tap it again to revert.

```Cassette, 6502SP, MasterFlight, Electron STA T                  \ Set A = 128 - A
LDA #128               \
\SEC                    \ The SEC instruction is commented out in the original
SBC T                  \ source, and isn't required as we did a SEC before
\ calling AR3
STA T                  \ Set A = 128 - A
LDA #128               \
SBC T                  \ The subtraction will work because we did a SEC before
\ calling AR3
```
``` RTS                    \ Return from the subroutine

.ARS1

\ This routine fetches arctan(A / Q) from the ACT table,
\ so A will be set to an integer in the range 0 to 31
\ that represents an angle from 0 to 45 degrees (or 0 to

JSR LL28               \ Call LL28 to calculate:
\
\   R = 256 * A / Q

LDA R                  \ Set X = R / 8
LSR A                  \       = 32 * A / Q
LSR A                  \
LSR A                  \ so X has the value t * 32 where t = A / Q, which is
TAX                    \ what we need to look up values in the ACT table

LDA ACT,X              \ Fetch ACT+X from the ACT table into A, so now:
\
\   A = value in ACT + X
\     = value in ACT + (32 * A / Q)
\     = arctan(A / Q)

```

Code variation 4 of 4A variation in the labels only

This variation is blank in the Cassette, Disc (flight), 6502 Second Processor and Electron versions.

```Master.ARSR1
```
``` RTS                    \ Return from the subroutine

```