×   Main Menu ALL The 8BS News Manuals (New menu) Links Worth a Look Tools Disc and Basic Webring Site Map 8BS Guestbook Old Guest Book Me The Barnsley Rovers   
8-Bit Software

The BBC and Master Computer Public Domain Library

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

 


 Back to 8BS
Or