^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) | stanh.sa 3.1 12/10/90
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) | The entry point sTanh computes the hyperbolic tangent of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) | an input argument; sTanhd does the same except for denormalized
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) | input.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) | Input: Double-extended number X in location pointed to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) | by address register a0.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) | Output: The value tanh(X) returned in floating-point register Fp0.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) | Accuracy and Monotonicity: The returned result is within 3 ulps in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) | 64 significant bit, i.e. within 0.5001 ulp to 53 bits if the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) | result is subsequently rounded to double precision. The
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) | result is provably monotonic in double precision.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) | Speed: The program stanh takes approximately 270 cycles.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) | Algorithm:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) | TANH
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) | 1. If |X| >= (5/2) log2 or |X| <= 2**(-40), go to 3.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) | 2. (2**(-40) < |X| < (5/2) log2) Calculate tanh(X) by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) | sgn := sign(X), y := 2|X|, z := expm1(Y), and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) | tanh(X) = sgn*( z/(2+z) ).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) | Exit.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) | 3. (|X| <= 2**(-40) or |X| >= (5/2) log2). If |X| < 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) | go to 7.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) | 4. (|X| >= (5/2) log2) If |X| >= 50 log2, go to 6.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) | 5. ((5/2) log2 <= |X| < 50 log2) Calculate tanh(X) by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) | sgn := sign(X), y := 2|X|, z := exp(Y),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) | tanh(X) = sgn - [ sgn*2/(1+z) ].
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) | Exit.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) | 6. (|X| >= 50 log2) Tanh(X) = +-1 (round to nearest). Thus, we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) | calculate Tanh(X) by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) | sgn := sign(X), Tiny := 2**(-126),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) | tanh(X) := sgn - sgn*Tiny.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) | Exit.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) | 7. (|X| < 2**(-40)). Tanh(X) = X. Exit.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) | Copyright (C) Motorola, Inc. 1990
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) | All Rights Reserved
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) | For details on the license for this file, please see the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) | file, README, in this same directory.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) |STANH idnt 2,1 | Motorola 040 Floating Point Software Package
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) |section 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #include "fpsp.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) .set X,FP_SCR5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) .set XDCARE,X+2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) .set XFRAC,X+4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) .set SGN,L_SCR3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) .set V,FP_SCR6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) BOUNDS1: .long 0x3FD78000,0x3FFFDDCE | ... 2^(-40), (5/2)LOG2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) |xref t_frcinx
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) |xref t_extdnrm
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) |xref setox
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) |xref setoxm1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) .global stanhd
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) stanhd:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) |--TANH(X) = X FOR DENORMALIZED X
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) bra t_extdnrm
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) .global stanh
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) stanh:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) fmovex (%a0),%fp0 | ...LOAD INPUT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) fmovex %fp0,X(%a6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) movel (%a0),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) movew 4(%a0),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) movel %d0,X(%a6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) andl #0x7FFFFFFF,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) cmp2l BOUNDS1(%pc),%d0 | ...2**(-40) < |X| < (5/2)LOG2 ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) bcss TANHBORS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) |--THIS IS THE USUAL CASE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) |--Y = 2|X|, Z = EXPM1(Y), TANH(X) = SIGN(X) * Z / (Z+2).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) movel X(%a6),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) movel %d0,SGN(%a6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) andl #0x7FFF0000,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) addl #0x00010000,%d0 | ...EXPONENT OF 2|X|
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) movel %d0,X(%a6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) andl #0x80000000,SGN(%a6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) fmovex X(%a6),%fp0 | ...FP0 IS Y = 2|X|
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) movel %d1,-(%a7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) clrl %d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) fmovemx %fp0-%fp0,(%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) bsr setoxm1 | ...FP0 IS Z = EXPM1(Y)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) movel (%a7)+,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) fmovex %fp0,%fp1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) fadds #0x40000000,%fp1 | ...Z+2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) movel SGN(%a6),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) fmovex %fp1,V(%a6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) eorl %d0,V(%a6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) fmovel %d1,%FPCR |restore users exceptions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) fdivx V(%a6),%fp0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) bra t_frcinx
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) TANHBORS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) cmpl #0x3FFF8000,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) blt TANHSM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) cmpl #0x40048AA1,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) bgt TANHHUGE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) |-- (5/2) LOG2 < |X| < 50 LOG2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) |--TANH(X) = 1 - (2/[EXP(2X)+1]). LET Y = 2|X|, SGN = SIGN(X),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) |--TANH(X) = SGN - SGN*2/[EXP(Y)+1].
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) movel X(%a6),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) movel %d0,SGN(%a6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) andl #0x7FFF0000,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) addl #0x00010000,%d0 | ...EXPO OF 2|X|
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) movel %d0,X(%a6) | ...Y = 2|X|
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) andl #0x80000000,SGN(%a6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) movel SGN(%a6),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) fmovex X(%a6),%fp0 | ...Y = 2|X|
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) movel %d1,-(%a7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) clrl %d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) fmovemx %fp0-%fp0,(%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) bsr setox | ...FP0 IS EXP(Y)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) movel (%a7)+,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) movel SGN(%a6),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) fadds #0x3F800000,%fp0 | ...EXP(Y)+1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) eorl #0xC0000000,%d0 | ...-SIGN(X)*2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) fmoves %d0,%fp1 | ...-SIGN(X)*2 IN SGL FMT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) fdivx %fp0,%fp1 | ...-SIGN(X)2 / [EXP(Y)+1 ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) movel SGN(%a6),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) orl #0x3F800000,%d0 | ...SGN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) fmoves %d0,%fp0 | ...SGN IN SGL FMT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) fmovel %d1,%FPCR |restore users exceptions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) faddx %fp1,%fp0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) bra t_frcinx
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) TANHSM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) movew #0x0000,XDCARE(%a6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) fmovel %d1,%FPCR |restore users exceptions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) fmovex X(%a6),%fp0 |last inst - possible exception set
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) bra t_frcinx
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) TANHHUGE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) |---RETURN SGN(X) - SGN(X)EPS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) movel X(%a6),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) andl #0x80000000,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) orl #0x3F800000,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) fmoves %d0,%fp0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) andl #0x80000000,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) eorl #0x80800000,%d0 | ...-SIGN(X)*EPS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) fmovel %d1,%FPCR |restore users exceptions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) fadds %d0,%fp0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) bra t_frcinx
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) |end