162306a36Sopenharmony_ci| 262306a36Sopenharmony_ci| stanh.sa 3.1 12/10/90 362306a36Sopenharmony_ci| 462306a36Sopenharmony_ci| The entry point sTanh computes the hyperbolic tangent of 562306a36Sopenharmony_ci| an input argument; sTanhd does the same except for denormalized 662306a36Sopenharmony_ci| input. 762306a36Sopenharmony_ci| 862306a36Sopenharmony_ci| Input: Double-extended number X in location pointed to 962306a36Sopenharmony_ci| by address register a0. 1062306a36Sopenharmony_ci| 1162306a36Sopenharmony_ci| Output: The value tanh(X) returned in floating-point register Fp0. 1262306a36Sopenharmony_ci| 1362306a36Sopenharmony_ci| Accuracy and Monotonicity: The returned result is within 3 ulps in 1462306a36Sopenharmony_ci| 64 significant bit, i.e. within 0.5001 ulp to 53 bits if the 1562306a36Sopenharmony_ci| result is subsequently rounded to double precision. The 1662306a36Sopenharmony_ci| result is provably monotonic in double precision. 1762306a36Sopenharmony_ci| 1862306a36Sopenharmony_ci| Speed: The program stanh takes approximately 270 cycles. 1962306a36Sopenharmony_ci| 2062306a36Sopenharmony_ci| Algorithm: 2162306a36Sopenharmony_ci| 2262306a36Sopenharmony_ci| TANH 2362306a36Sopenharmony_ci| 1. If |X| >= (5/2) log2 or |X| <= 2**(-40), go to 3. 2462306a36Sopenharmony_ci| 2562306a36Sopenharmony_ci| 2. (2**(-40) < |X| < (5/2) log2) Calculate tanh(X) by 2662306a36Sopenharmony_ci| sgn := sign(X), y := 2|X|, z := expm1(Y), and 2762306a36Sopenharmony_ci| tanh(X) = sgn*( z/(2+z) ). 2862306a36Sopenharmony_ci| Exit. 2962306a36Sopenharmony_ci| 3062306a36Sopenharmony_ci| 3. (|X| <= 2**(-40) or |X| >= (5/2) log2). If |X| < 1, 3162306a36Sopenharmony_ci| go to 7. 3262306a36Sopenharmony_ci| 3362306a36Sopenharmony_ci| 4. (|X| >= (5/2) log2) If |X| >= 50 log2, go to 6. 3462306a36Sopenharmony_ci| 3562306a36Sopenharmony_ci| 5. ((5/2) log2 <= |X| < 50 log2) Calculate tanh(X) by 3662306a36Sopenharmony_ci| sgn := sign(X), y := 2|X|, z := exp(Y), 3762306a36Sopenharmony_ci| tanh(X) = sgn - [ sgn*2/(1+z) ]. 3862306a36Sopenharmony_ci| Exit. 3962306a36Sopenharmony_ci| 4062306a36Sopenharmony_ci| 6. (|X| >= 50 log2) Tanh(X) = +-1 (round to nearest). Thus, we 4162306a36Sopenharmony_ci| calculate Tanh(X) by 4262306a36Sopenharmony_ci| sgn := sign(X), Tiny := 2**(-126), 4362306a36Sopenharmony_ci| tanh(X) := sgn - sgn*Tiny. 4462306a36Sopenharmony_ci| Exit. 4562306a36Sopenharmony_ci| 4662306a36Sopenharmony_ci| 7. (|X| < 2**(-40)). Tanh(X) = X. Exit. 4762306a36Sopenharmony_ci| 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci| Copyright (C) Motorola, Inc. 1990 5062306a36Sopenharmony_ci| All Rights Reserved 5162306a36Sopenharmony_ci| 5262306a36Sopenharmony_ci| For details on the license for this file, please see the 5362306a36Sopenharmony_ci| file, README, in this same directory. 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci|STANH idnt 2,1 | Motorola 040 Floating Point Software Package 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci |section 8 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci#include "fpsp.h" 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci .set X,FP_SCR5 6262306a36Sopenharmony_ci .set XDCARE,X+2 6362306a36Sopenharmony_ci .set XFRAC,X+4 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci .set SGN,L_SCR3 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci .set V,FP_SCR6 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ciBOUNDS1: .long 0x3FD78000,0x3FFFDDCE | ... 2^(-40), (5/2)LOG2 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci |xref t_frcinx 7262306a36Sopenharmony_ci |xref t_extdnrm 7362306a36Sopenharmony_ci |xref setox 7462306a36Sopenharmony_ci |xref setoxm1 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci .global stanhd 7762306a36Sopenharmony_cistanhd: 7862306a36Sopenharmony_ci|--TANH(X) = X FOR DENORMALIZED X 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci bra t_extdnrm 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci .global stanh 8362306a36Sopenharmony_cistanh: 8462306a36Sopenharmony_ci fmovex (%a0),%fp0 | ...LOAD INPUT 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci fmovex %fp0,X(%a6) 8762306a36Sopenharmony_ci movel (%a0),%d0 8862306a36Sopenharmony_ci movew 4(%a0),%d0 8962306a36Sopenharmony_ci movel %d0,X(%a6) 9062306a36Sopenharmony_ci andl #0x7FFFFFFF,%d0 9162306a36Sopenharmony_ci cmp2l BOUNDS1(%pc),%d0 | ...2**(-40) < |X| < (5/2)LOG2 ? 9262306a36Sopenharmony_ci bcss TANHBORS 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci|--THIS IS THE USUAL CASE 9562306a36Sopenharmony_ci|--Y = 2|X|, Z = EXPM1(Y), TANH(X) = SIGN(X) * Z / (Z+2). 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci movel X(%a6),%d0 9862306a36Sopenharmony_ci movel %d0,SGN(%a6) 9962306a36Sopenharmony_ci andl #0x7FFF0000,%d0 10062306a36Sopenharmony_ci addl #0x00010000,%d0 | ...EXPONENT OF 2|X| 10162306a36Sopenharmony_ci movel %d0,X(%a6) 10262306a36Sopenharmony_ci andl #0x80000000,SGN(%a6) 10362306a36Sopenharmony_ci fmovex X(%a6),%fp0 | ...FP0 IS Y = 2|X| 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci movel %d1,-(%a7) 10662306a36Sopenharmony_ci clrl %d1 10762306a36Sopenharmony_ci fmovemx %fp0-%fp0,(%a0) 10862306a36Sopenharmony_ci bsr setoxm1 | ...FP0 IS Z = EXPM1(Y) 10962306a36Sopenharmony_ci movel (%a7)+,%d1 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci fmovex %fp0,%fp1 11262306a36Sopenharmony_ci fadds #0x40000000,%fp1 | ...Z+2 11362306a36Sopenharmony_ci movel SGN(%a6),%d0 11462306a36Sopenharmony_ci fmovex %fp1,V(%a6) 11562306a36Sopenharmony_ci eorl %d0,V(%a6) 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci fmovel %d1,%FPCR |restore users exceptions 11862306a36Sopenharmony_ci fdivx V(%a6),%fp0 11962306a36Sopenharmony_ci bra t_frcinx 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ciTANHBORS: 12262306a36Sopenharmony_ci cmpl #0x3FFF8000,%d0 12362306a36Sopenharmony_ci blt TANHSM 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci cmpl #0x40048AA1,%d0 12662306a36Sopenharmony_ci bgt TANHHUGE 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci|-- (5/2) LOG2 < |X| < 50 LOG2, 12962306a36Sopenharmony_ci|--TANH(X) = 1 - (2/[EXP(2X)+1]). LET Y = 2|X|, SGN = SIGN(X), 13062306a36Sopenharmony_ci|--TANH(X) = SGN - SGN*2/[EXP(Y)+1]. 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci movel X(%a6),%d0 13362306a36Sopenharmony_ci movel %d0,SGN(%a6) 13462306a36Sopenharmony_ci andl #0x7FFF0000,%d0 13562306a36Sopenharmony_ci addl #0x00010000,%d0 | ...EXPO OF 2|X| 13662306a36Sopenharmony_ci movel %d0,X(%a6) | ...Y = 2|X| 13762306a36Sopenharmony_ci andl #0x80000000,SGN(%a6) 13862306a36Sopenharmony_ci movel SGN(%a6),%d0 13962306a36Sopenharmony_ci fmovex X(%a6),%fp0 | ...Y = 2|X| 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci movel %d1,-(%a7) 14262306a36Sopenharmony_ci clrl %d1 14362306a36Sopenharmony_ci fmovemx %fp0-%fp0,(%a0) 14462306a36Sopenharmony_ci bsr setox | ...FP0 IS EXP(Y) 14562306a36Sopenharmony_ci movel (%a7)+,%d1 14662306a36Sopenharmony_ci movel SGN(%a6),%d0 14762306a36Sopenharmony_ci fadds #0x3F800000,%fp0 | ...EXP(Y)+1 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci eorl #0xC0000000,%d0 | ...-SIGN(X)*2 15062306a36Sopenharmony_ci fmoves %d0,%fp1 | ...-SIGN(X)*2 IN SGL FMT 15162306a36Sopenharmony_ci fdivx %fp0,%fp1 | ...-SIGN(X)2 / [EXP(Y)+1 ] 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci movel SGN(%a6),%d0 15462306a36Sopenharmony_ci orl #0x3F800000,%d0 | ...SGN 15562306a36Sopenharmony_ci fmoves %d0,%fp0 | ...SGN IN SGL FMT 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci fmovel %d1,%FPCR |restore users exceptions 15862306a36Sopenharmony_ci faddx %fp1,%fp0 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci bra t_frcinx 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ciTANHSM: 16362306a36Sopenharmony_ci movew #0x0000,XDCARE(%a6) 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci fmovel %d1,%FPCR |restore users exceptions 16662306a36Sopenharmony_ci fmovex X(%a6),%fp0 |last inst - possible exception set 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci bra t_frcinx 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ciTANHHUGE: 17162306a36Sopenharmony_ci|---RETURN SGN(X) - SGN(X)EPS 17262306a36Sopenharmony_ci movel X(%a6),%d0 17362306a36Sopenharmony_ci andl #0x80000000,%d0 17462306a36Sopenharmony_ci orl #0x3F800000,%d0 17562306a36Sopenharmony_ci fmoves %d0,%fp0 17662306a36Sopenharmony_ci andl #0x80000000,%d0 17762306a36Sopenharmony_ci eorl #0x80800000,%d0 | ...-SIGN(X)*EPS 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci fmovel %d1,%FPCR |restore users exceptions 18062306a36Sopenharmony_ci fadds %d0,%fp0 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci bra t_frcinx 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci |end 185