A90E COS
Submitted by Steve Fewell
Description:
On entry to the COS routine, the carry flag will be set - this indicates that the Cosine result is required (a clear carry
flag indicates that the Sine result is required!).
Store the 6502 flags to the 6502 stack, so that the carry flag can be checked later.
Call routine &A93A to obtain the Floating-Point argument and calculate the Sine or Cosine value (the value returned
will be either COS or SIN - depending on the value of the Floating-Point argument.
-
Routine &A93A does the following:
- * Call routine &96DA to obtain the value at the Text pointer B location (convert it to Float if it is
- Integer or issue 'Type mismatch' error if it is a String value).
- * If the FWA exponent (location &30) is more than or equal to #&98 then issue 'Accuracy lost' error
- as the FWA value is too large to use to calculate the SIN/COS value.
- * Store the FWA value to temporary Floating point value location &046C-&0470.
- * Set the argument pointer (&4A-&4B) to &BF2E (which points to the Float value 1.57079633 in the
- Floating-Point constant table).
- * Call &A4E0 to unpack the Floating-Point constant at &BF2E (1.57079633, which is PI/2) to the FWB
- * Store the FWA sign (location &2E) in the FWB sign byte (location &3B) so that the PI/2 value has
- the same sign as the argument (the FWA value).
- * Decrement the FWB exponent (location &3C) to divide the FWB value by 2 - so the FWB now contains the
- value 0.785398165.
- * Call routine &A692 to add the FWB value (PI/4) to the FWA value.
- * Set A to #&33.
- * Call routine &A9D4 to set the argument pointer (&4A-&4B) to &BF00 + A = &BF33 (which points to
- the Float value 0.636619772 (which is 2/PI) in the Floating-Point constant table)
- and then multiply the FWA by the Float value pointed to by the argument pointer (&4A-&4B).
- * Call routine &96C3 to convert the Float value (FWA) to an Integer and place the result in the IWA.
- * Store A (the LSB of the IWA value - from location &2A) in location &49.
- * If the Integer value (&2A-&2C) is zero then jump to &A98D (as the FWA value does not need to be
- reduced to a value within the required range -(PI/4) to (PI/4) [i.e. -0.785398 to 0.785398]),
- so [&A98D] load the FWA with the original Sine/Cosine argument (from location &046C-&0470).
- * Otherwise, the FWA value is out of the Sine/Cosine range, and needs to be reduced, so:
- * Call &8189 to convert the Integer value (IWA) to a Float and store the result in the temporary
- Floating-point variable located at &0471-&0475.
- * Then set the argp pointer (&4A-&4B) to pointer to &BF24 (which is the Floating-point constant
- value -1.57080078) and multiply the FWA by this constant.
- * Set the argp pointer (&4A-&4B) to point to the temporary Floating-point variable location &046C
- (which is the original FWA Sine/Cosine argument value) and add the Floating-Point
- value at &046C-&0470 to the FWA value.
- * Store the result in temporary Floating-Point value location &046C-&0470.
- * Set the FWA to the Floating-Point value stored at location &0471-&0475 (the IWA value).
- * Set the argp pointer (&4A-&4B) to point to &BF29 (the address of the value 0.00000445445511
- in the Floating-Point constant table).
- * Multiply the FWA by the Floating-Point constant 0.00000445445511 (store the result in the FWA).
- * Set the argp pointer (&4A-&4B) to &046C and add the Floating-Point value at &046C-&0470
- to the FWA.
- * Jump to &A990 to perform the Sine/Cosine calculation as the value is now within the required range.
- * [A990] Store the FWA value (the actual Sine/Cosine argument, which has been reduced where necessary) to location
- &0476-&047A.
- * Multiply the FWA by the Floating-point value at &0476-&047A (i.e. square the FWA value).
- * Set X to #&74 (i.e. the LSB of the first fraction to apply)
- * Set A to #&92 (i.e. the LSB of the default value (if the FWA value is too small to evaluate)
- * Set Y to #&02 (the number of continued-fraction expansion cycles to evaluate)
- * Call routine &A861 to evaluate the continued-fraction expansions, as follows:
- * If the FWA exponent is less than #&40 then the FWA value is too small to evaluate, so exit with the
- FWA set to the Floating-Point constant at &BF92 (i.e. 1.0).
- * Calculate the reciple of the FWA value (FWA = 1/FWA) and store the result in the FWA and location
- &046C-&0470
- * Add the Floating-Point constant at &BF74 (-0.0119090311) to the FWA
- * Cycle 1:
- * Divide the Floating-Point constant at &BF79 (0.000107499459) by the FWA, storing the result in the FWA.
- * Add the Floating-Point constant at &BF7E (-0.0171640246) to the FWA.
- * Add the Reciple value (from location &046C-&0470) to the FWA.
- * Cycle 2:
- * Divide the Floating-Point constant at &BF83 (0.0013095369) by the FWA, storing the result in the FWA.
- * Add the Floating-Point constant at &BF88 (0.0499999922) to the FWA.
- * Add the Reciple value (from location &046C-&0470) to the FWA.
- Last Cycle calculation:
- * Divide the Floating-Point constant at &BF8D (-0.166666666) by the FWA, storing the result in the FWA.
- * Add the Floating-Point constant at &BF92 (1.0) to the FWA.
- * Multiply the FWA by the Temporary Floating-Point variable stored at location &0476-&047A (the argument
- value).
- * Exit with A = #&FF (as the result is a Floating-Point value in the FWA)
Now, the FWA contains either the Sine result or the Cosine result (which will have to be converted to the value
requested by the user).
Retrieve the carry flag value from the 6502 stack.
As the carry flag is set (Cosine result required), increment the value stored at location &49 (the integer part of
the FWA argument value).
[&A923] If bit 0 of location &49 is clear (i.e. the original argument was an even value (in the case of Sine) - or
an odd value (in the case of Cosine)) then Set A to #&FF (to indicate that the result is a Floating-point value) and
[&A917] check the value in location &49 - if bit 1 is not set then complement the FWA value (FWA=-FWA) and exit;
otherwise, just exit.
-
Otherwise, bit 0 of location &49 is set (indicating that the original argument was odd (in the case of Sine) or even (in
the case of Cosine); so, adjust the calculated result as follows:
- * Square the FWA value (FWA = FWA * FWA),
- * Subtract the FWA value from 1 (FWA=1.0-FWA) and
- * Set the FWA value to the square root of the FWA (FWA=SQR(FWA)).
[&A917] check the value in location &49 - if bit 1 is not set then complement the FWA value (FWA=-FWA) and exit;
otherwise, just exit.
Example 1: COS(1.5)
-
- Set &046C = 1.5 (the argument)
- Set FWB to 0.785398165 (PI/4)
- FWA = FWA + FWB = 2.285398
- FWA = FWA * 0.636619772 = 1.4549294
- ?&49 = 1 (Integer part of FWA value). FWA = IWA = 1
- Store the FWA in &0471
- FWA = FWA * -1.57080078 = -1.57080078
- FWA = FWA + &046C = -0.07080078
- Store FWA in &046C
- Store &0471 (1) in FWA
- FWA = FWA * 0.0000044544511 = 0.0000044544511
- FWA = FWA + &046C = -0.0707963255
- Store the FWA in &0476
- FWA = FWA * FWA = 0.0050121197
- [&A861]: FWA = 1 / FWA = 199.51638
- Store FWA in &046C
- FWA = FWA + -0.0119090311 = 199.504474778
- FWA = 0.000107499 / FWA = 0.00000005388
- FWA = -0.017164024 + FWA = -0.017163485
- FWA = &046C + FWA = 199.499216515
- FWA = 0.0013095369 / FWA = 0.000006564
- FWA = 0.04999999 + FWA = 0.050006554
- FWA = &046C + FWA = 199.566387
- FWA = -0.16666666 / FWA = -0.00083514
- FWA = 1 + FWA = 0.999164856
- FWA = FWA * &0476 = -0.070737200377
-
- Increment &49 -> now &49 = 2
- Bit 0 of &49 is clear and Bit 1 of &49 is set, indicating that the FWA value needs
- to be complemented - so exit with FWA = - FWA = 0.070737200377
Example 2: COS(-0.75)
-
- Set &046C = -0.75 (the argument)
- Set FWB to -0.785398165 -(PI/4)
- FWA = FWA + FWB = -1.535398165
- FWA = FWA * 0.636619772 = -0.9774646
- ?&49 = 0 (Integer part of FWA value). FWA = IWA = 0
- [&A98D] As &49 is 0, store value at &046C in FWA = -0.75
- Store the FWA in &0476
- FWA = FWA * FWA = 0.5625
- [&A861]: FWA = 1 / FWA = 1.777777
- Store FWA in &046C
- FWA = FWA + -0.0119090311 = 1.7896868
- FWA = 0.000107499 / FWA = 0.00006
- FWA = -0.017164024 + FWA = -0.0171039
- FWA = &046C + FWA = 1.7606737
- FWA = 0.0013095369 / FWA = 0.0007437
- FWA = 0.04999999 + FWA = 0.0507436
- FWA = &046C + FWA = 1.8285213
- FWA = -0.16666666 / FWA = -0.0911482
- FWA = 1 + FWA = 0.9088517
- FWA = FWA * &0476 = -0.6816387
-
- Increment &49 -> now &49 = 1
- Bit 0 of &49 is set, so adjust the calculated value as follows:
- FWA = FWA * FWA = 0.4646313
- FWA = 1 - FWA = 0.5353686
- FWA = SQR(FWA) = 0.7316889
- Bit 1 of &49 is not set, so exit with FWA unchanged.
Example 3: COS(0.0)
-
- Set &046C = 0.0 (the argument)
- Set FWB to 0.785398165 (PI/4)
- FWA = FWA + FWB = 0.785398165
- FWA = FWA * 0.636619772 = 0.50000000
- ?&49 = 0 (Integer part of FWA value). FWA = IWA = 0
- [&A98D] As &49 is 0, store value at &046C in FWA = 0.0
- Store the FWA in &0476
- FWA = FWA * FWA = 0.0
- [&A861]: FWA = 1.0 (as argument is zero)
- FWA = FWA * &0476 = 0.0
-
- Increment &49 -> now &49 = 1
- Bit 0 of &49 is set, so adjust the calculated value as follows:
- FWA = FWA * FWA = 0.0
- FWA = 1 - FWA = 1.0
- FWA = SQR(FWA) = 1.0
- Bit 1 of &49 is not set, so exit with FWA unchanged.
Example 4: COS(0.25)
-
- Set &046C = 0.25 (the argument)
- Set FWB to 0.785398165 (PI/4)
- FWA = FWA + FWB = 1.0353982
- FWA = FWA * 0.636619772 = 0.6591548
- ?&49 = 0 (Integer part of FWA value). FWA = IWA = 0
- [&A98D] As &49 is 0, store value at &046C in FWA = 0.25
- Store the FWA in &0476
- FWA = FWA * FWA = 0.0625
- [&A861]: FWA = 1 / FWA = 16
- Store FWA in &046C
- FWA = FWA + -0.0119090311 = 15.988091
- FWA = 0.000107499 / FWA = 0.0000067
- FWA = -0.0171640246 + FWA = -0.0171572
- FWA = &046C + FWA = 15.982843
- FWA = 0.0013095369 / FWA = 0.0000819
- FWA = 0.04999999 + FWA = 0.0500818
- FWA = &046C + FWA = 16.050082
- FWA = -0.16666666 / FWA = -0.0103841
- FWA = 1 + FWA = 0.9896158
- FWA = FWA * &0476 = 0.2474039
-
- Increment &49 -> now &49 = 1
- Bit 0 of &49 is set, so adjust the calculated value as follows:
- FWA = FWA * FWA = 0.0612086
- FWA = 1 - FWA = 0.9387913
- FWA = SQR(FWA) = 0.9689124
- Bit 1 of &49 is not set, so exit with FWA unchanged.
Example 5: COS(2.41)
-
- Set &046C = 2.41 (the argument)
- Set FWB to 0.785398165 (PI/4)
- FWA = FWA + FWB = 3.195398
- FWA = FWA * 0.636619772 = 2.0342533
- ?&49 = 2 (Integer part of FWA value). FWA = IWA = 2
- Store the FWA in &0471
- FWA = FWA * -1.57080078 = -3.1416014
- FWA = FWA + &046C = -0.7316014
- Store FWA in &046C
- Store &0471 (2) in FWA
- FWA = FWA * 0.0000044544511 = 0.0000089
- FWA = FWA + &046C = -0.7315924
- Store the FWA in &0476
- FWA = FWA * FWA = 0.5352275
- [&A861]: FWA = 1 / FWA = 1.8683641
- Store FWA in &046C
- FWA = FWA + -0.0119090311 = 1.8564551
- FWA = 0.000107499 / FWA = 0.0000057
- FWA = -0.017164024 + FWA = -0.0171583
- FWA = &046C + FWA = 1.8512058
- FWA = 0.0013095369 / FWA = 0.0007073
- FWA = 0.04999999 + FWA = 0.0507072
- FWA = &046C + FWA = 1.9190714
- FWA = -0.16666666 / FWA = -0.0868475
- FWA = 1 + FWA = 0.9131524
- FWA = FWA * &0476 = -0.6680554
-
- Increment &49 -> now &49 = 3
- Bit 0 of &49 is set, so adjust the calculated value as follows:
- FWA = FWA * FWA = 0.446298
- FWA = 1 - FWA = 0.5537019
- FWA = SQR(FWA) = 0.7441115
- Bit 1 of &49 is set, so FWA = - FWA = -0.7441115
Example 6: COS(5.63)
-
- Set &046C = 5.63 (the argument)
- Set FWB to 0.785398165 (PI/4)
- FWA = FWA + FWB = 6.415398
- FWA = FWA * 0.636619772 = 4.0841688
- ?&49 = 4 (Integer part of FWA value). FWA = IWA = 4
- Store the FWA in &0471
- FWA = FWA * -1.57080078 = -6.2832028
- FWA = FWA + &046C = -0.6532028
- Store FWA in &046C
- Store &0471 (4) in FWA
- FWA = FWA * 0.0000044544511 = 0.0000178
- FWA = FWA + &046C = -0.6531849
- [&A990] Store the FWA in &0476
- FWA = FWA * FWA = 0.4266506
- [&A861]: FWA = 1 / FWA = 2.3438381
- Store FWA in &046C
- FWA = FWA + -0.0119090311 = 2.3319291
- FWA = 0.000107499 / FWA = 0.000046
- FWA = -0.017164024 + FWA = -0.0171179
- FWA = &046C + FWA = 2.3267202
- FWA = 0.0013095369 / FWA = 0.0056282
- FWA = 0.04999999 + FWA = 0.0556281
- FWA = &046C + FWA = 2.3994662
- FWA = -0.16666666 / FWA = -0.0694598
- FWA = 1 + FWA = 0.9305401
- FWA = FWA * &0476 = -0.6078147
-
- Increment &49 -> now &49 = 5
- Bit 0 of &49 is set, so adjust the calculated value as follows:
- FWA = FWA * FWA = 0.3694387
- FWA = 1 - FWA = 0.6305612
- FWA = SQR(FWA) = 0.7940788
- Bit 1 of &49 is not set, so exit with FWA unchanged.
Example 7: COS(90)
-
- Set &046C = 90 (the argument)
- Set FWB to 0.785398165 (PI/4)
- FWA = FWA + FWB = 90.785398
- FWA = FWA * 0.636619772 = 57.795773
- ?&49 = 57 (Integer part of FWA value). FWA = IWA = 57
- Store the FWA in &0471
- FWA = FWA * -1.57080078 = -89.53564
- FWA = FWA + &046C = 0.4643601
- Store FWA in &046C
- Store &0471 (57) in FWA
- FWA = FWA * 0.0000044544511 = 0.0002539
- FWA = FWA + &046C = 0.464614
- Store the FWA in &0476
- FWA = FWA * FWA = 0.2158661
- [&A861]: FWA = 1 / FWA = 4.6324998
- Store FWA in &046C
- FWA = FWA + -0.0119090311 = 4.6205908
- FWA = 0.000107499 / FWA = 0.0000023
- FWA = -0.017164024 + FWA = -0.0171616
- FWA = &046C + FWA = 4.6153381
- FWA = 0.0013095369 / FWA = 0.0002837
- FWA = 0.04999999 + FWA = 0.0502836
- FWA = &046C + FWA = 4.6827834
- FWA = -0.16666666 / FWA = -0.0355913
- FWA = 1 + FWA = 0.9644086
- FWA = FWA * &0476 = 0.4480777
-
- Increment &49 -> now &49 = 58 (0011 1010)
- Bit 0 of &49 is clear and Bit 1 of &49 is set, indicating that the FWA value needs
- to be complemented - so exit with FWA = - FWA = -0.4480777
This diagram shows the relationship between the trig functions.
Disassembly for the COS routine
A90E |
|
008 |
08 |
PHP |
A90F |
: |
032 058 169 |
20 3A A9 |
JSR &A93A Get value and calculate Sine or Cosine wave |
A912 |
( |
040 |
28 |
PLP |
A913 |
|
144 002 |
90 02 |
BCC 2 --> &A917 |
A915 |
I |
230 073 |
E6 49 |
INC &49 |
A917 |
I |
165 073 |
A5 49 |
LDA &49 |
A919 |
|
137 002 |
89 02 |
BIT#&02 |
A91B |
|
240 006 |
F0 06 |
BEQ 6 --> &A923 |
A91D |
# |
032 035 169 |
20 23 A9 |
JSR &A923 |
A920 |
L |
076 202 172 |
4C CA AC |
JMP &ACCA Compliment FWA value [FWA=-FWA] |
A923 |
J |
074 |
4A |
LSR A |
A924 |
|
176 003 |
B0 03 |
BCS 3 --> &A929 |
A926 |
|
169 255 |
A9 FF |
LDA#&FF |
A928 |
` |
096 |
60 |
RTS |
A929 |
|
032 017 165 |
20 11 A5 |
JSR &A511 Store FWA to &046C & set argp=&046C |
A92C |
|
032 166 166 |
20 A6 A6 |
JSR &A6A6 Multiply the FWA by argp [i.e. &046C] |
A92F |
|
169 146 |
A9 92 |
LDA#&92 |
A931 |
|
032 139 165 |
20 8B A5 |
JSR &A58B Set argp to &BF00 + A |
A934 |
|
032 138 166 |
20 8A A6 |
JSR &A68A Floating-Point Subtraction [FWA=argp-FWA] |
A937 |
L |
076 184 167 |
4C B8 A7 |
JMP &A7B8 Floating-point Square Root [FWA = SQRT(FWA)] |
A93A |
|
032 218 150 |
20 DA 96 |
JSR &96DA Get and Check Float (convert if Int) |
A93D |
0 |
165 048 |
A5 30 |
LDA &30 |
A93F |
|
201 152 |
C9 98 |
CMP#&98 |
A941 |
j |
176 106 |
B0 6A |
BCS 106 --> &A9AD 'Accuracy lost' error |
A943 |
|
032 017 165 |
20 11 A5 |
JSR &A511 Store FWA to &046C & set argp=&046C |
A946 |
|
032 137 165 |
20 89 A5 |
JSR &A589 Set argp to &BF2E |
A949 |
|
032 224 164 |
20 E0 A4 |
JSR &A4E0 Unpack (&4A, &4B) variable to FWB |
A94C |
. |
165 046 |
A5 2E |
LDA &2E |
A94E |
; |
133 059 |
85 3B |
STA &3B |
A950 |
< |
198 060 |
C6 3C |
DEC &3C |
A952 |
|
032 146 166 |
20 92 A6 |
JSR &A692 FWA = FWA + FWB (PI/4) |
A955 |
3 |
169 051 |
A9 33 |
LDA#&33 |
A957 |
|
032 212 169 |
20 D4 A9 |
JSR &A9D4 Multiply FWA by &BF33 (0.636619772 - 2/PI) |
A95A |
|
032 195 150 |
20 C3 96 |
JSR &96C3 Convert Float to Integer |
A95D |
I |
133 073 |
85 49 |
STA &49 |
A95F |
+ |
005 043 |
05 2B |
ORA &2B |
A961 |
, |
005 044 |
05 2C |
ORA &2C |
A963 |
( |
240 040 |
F0 28 |
BEQ 40 --> &A98D |
A965 |
|
032 137 129 |
20 89 81 |
JSR &8189 Convert Integer value (IWA) to Floating-Point (FWA) |
A968 |
q |
169 113 |
A9 71 |
LDA#&71 |
A96A |
|
032 019 165 |
20 13 A5 |
JSR &A513 Store FWA to &047B |
A96D |
$ |
169 036 |
A9 24 |
LDA#&24 |
A96F |
|
032 212 169 |
20 D4 A9 |
JSR &A9D4 Multiply FWA by &BF24 (-1.57080078) |
A972 |
|
032 146 165 |
20 92 A5 |
JSR &A592 Set argp to &046C |
A975 |
|
032 141 166 |
20 8D A6 |
JSR &A68D Floating-Point Addition [FWA=argp+FWA] |
A978 |
|
032 025 165 |
20 19 A5 |
JSR &A519 Store FWA to argp address (&4A-&4B) |
A97B |
q |
169 113 |
A9 71 |
LDA#&71 |
A97D |
; |
032 059 165 |
20 3B A5 |
JSR &A53B Load FWA from variable at &0400 + A (i.e. &0471) |
A980 |
) |
169 041 |
A9 29 |
LDA#&29 |
A982 |
|
032 212 169 |
20 D4 A9 |
JSR &A9D4 Multiply FWA by &BF29 (0.00000445445511) |
A985 |
|
032 146 165 |
20 92 A5 |
JSR &A592 Set argp to &046C |
A988 |
|
032 141 166 |
20 8D A6 |
JSR &A68D Floating-Point Addition [FWA=argp+FWA] |
A98B |
|
128 003 |
80 03 |
BRA 3 --> &A990 |
A98D |
9 |
032 057 165 |
20 39 A5 |
JSR &A539 Load FWA from &046C |
A990 |
|
032 013 165 |
20 0D A5 |
JSR &A50D Store FWA to &0476 and set argp to &0476 |
A993 |
|
032 166 166 |
20 A6 A6 |
JSR &A6A6 Multiply the FWA by argp [i.e. &0476] |
A996 |
t |
162 116 |
A2 74 |
LDX#&74 |
A998 |
|
169 146 |
A9 92 |
LDA#&92 |
A99A |
|
160 002 |
A0 02 |
LDY#&02 |
A99C |
a |
032 097 168 |
20 61 A8 |
JSR &A861 Evaluate continued-fraction expansion series |
A99F |
v |
169 118 |
A9 76 |
LDA#&76 |
A9A1 Multiply FWA by &0400 + A
A9A1 |
|
160 004 |
A0 04 |
LDY#&04 |
A9A3 |
K |
132 075 |
84 4B |
STY &4B |
A9A5 |
J |
133 074 |
85 4A |
STA &4A |
A9A7 |
|
032 166 166 |
20 A6 A6 |
JSR &A6A6 Multiply the FWA by argp [i.e. &0400 + A] |
A9AA |
|
169 255 |
A9 FF |
LDA#&FF |
A9AC |
` |
096 |
60 |
RTS |
Or