/ src / ref / sinh.c
sinh.c
  1  /*
  2   * Copyright (C) 2008-2020 Advanced Micro Devices, Inc. All rights reserved.
  3   *
  4   * Redistribution and use in source and binary forms, with or without modification,
  5   * are permitted provided that the following conditions are met:
  6   * 1. Redistributions of source code must retain the above copyright notice,
  7   *    this list of conditions and the following disclaimer.
  8   * 2. Redistributions in binary form must reproduce the above copyright notice,
  9   *    this list of conditions and the following disclaimer in the documentation
 10   *    and/or other materials provided with the distribution.
 11   * 3. Neither the name of the copyright holder nor the names of its contributors
 12   *    may be used to endorse or promote products derived from this software without
 13   *    specific prior written permission.
 14   *
 15   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 16   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 17   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 18   * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 19   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 20   * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 21   * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 22   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 23   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 24   * POSSIBILITY OF SUCH DAMAGE.
 25   *
 26   */
 27  
 28  #include "libm_amd.h"
 29  #include "libm_util_amd.h"
 30  #include "libm_inlines_amd.h"
 31  #include "libm_special.h"
 32  
 33  double FN_PROTOTYPE_REF(sinh)(double x)
 34  {
 35    /*
 36      After dealing with special cases the computation is split into
 37      regions as follows:
 38  
 39      abs(x) >= max_sinh_arg:
 40      sinh(x) = sign(x)*Inf
 41  
 42      abs(x) >= small_threshold:
 43      sinh(x) = sign(x)*exp(abs(x))/2 computed using the
 44      splitexp and scaleDouble functions as for exp_amd().
 45  
 46      abs(x) < small_threshold:
 47      compute p = exp(y) - 1 and then z = 0.5*(p+(p/(p+1.0)))
 48      sinh(x) is then sign(x)*z.                             */
 49  
 50    static const double
 51      max_sinh_arg = 7.10475860073943977113e+02, /* 0x408633ce8fb9f87e */
 52      thirtytwo_by_log2 = 4.61662413084468283841e+01, /* 0x40471547652b82fe */
 53      log2_by_32_lead = 2.16608493356034159660e-02, /* 0x3f962e42fe000000 */
 54      log2_by_32_tail = 5.68948749532545630390e-11, /* 0x3dcf473de6af278e */
 55      small_threshold = 8*BASEDIGITS_DP64*0.30102999566398119521373889;
 56    /* (8*BASEDIGITS_DP64*log10of2) ' exp(-x) insignificant c.f. exp(x) */
 57  
 58    /* Lead and tail tabulated values of sinh(i) and cosh(i)
 59       for i = 0,...,36. The lead part has 26 leading bits. */
 60  
 61    static const double sinh_lead[37] = {
 62      0.00000000000000000000e+00,  /* 0x0000000000000000 */
 63      1.17520117759704589844e+00,  /* 0x3ff2cd9fc0000000 */
 64      3.62686038017272949219e+00,  /* 0x400d03cf60000000 */
 65      1.00178747177124023438e+01,  /* 0x40240926e0000000 */
 66      2.72899169921875000000e+01,  /* 0x403b4a3800000000 */
 67      7.42032089233398437500e+01,  /* 0x40528d0160000000 */
 68      2.01713153839111328125e+02,  /* 0x406936d228000000 */
 69      5.48316116333007812500e+02,  /* 0x4081228768000000 */
 70      1.49047882080078125000e+03,  /* 0x409749ea50000000 */
 71      4.05154187011718750000e+03,  /* 0x40afa71570000000 */
 72      1.10132326660156250000e+04,  /* 0x40c5829dc8000000 */
 73      2.99370708007812500000e+04,  /* 0x40dd3c4488000000 */
 74      8.13773945312500000000e+04,  /* 0x40f3de1650000000 */
 75      2.21206695312500000000e+05,  /* 0x410b00b590000000 */
 76      6.01302140625000000000e+05,  /* 0x412259ac48000000 */
 77      1.63450865625000000000e+06,  /* 0x4138f0cca8000000 */
 78      4.44305525000000000000e+06,  /* 0x4150f2ebd0000000 */
 79      1.20774762500000000000e+07,  /* 0x4167093488000000 */
 80      3.28299845000000000000e+07,  /* 0x417f4f2208000000 */
 81      8.92411500000000000000e+07,  /* 0x419546d8f8000000 */
 82      2.42582596000000000000e+08,  /* 0x41aceb0888000000 */
 83      6.59407856000000000000e+08,  /* 0x41c3a6e1f8000000 */
 84      1.79245641600000000000e+09,  /* 0x41dab5adb8000000 */
 85      4.87240166400000000000e+09,  /* 0x41f226af30000000 */
 86      1.32445608960000000000e+10,  /* 0x4208ab7fb0000000 */
 87      3.60024494080000000000e+10,  /* 0x4220c3d390000000 */
 88      9.78648043520000000000e+10,  /* 0x4236c93268000000 */
 89      2.66024116224000000000e+11,  /* 0x424ef822f0000000 */
 90      7.23128516608000000000e+11,  /* 0x42650bba30000000 */
 91      1.96566712320000000000e+12,  /* 0x427c9aae40000000 */
 92      5.34323724288000000000e+12,  /* 0x4293704708000000 */
 93      1.45244246507520000000e+13,  /* 0x42aa6b7658000000 */
 94      3.94814795284480000000e+13,  /* 0x42c1f43fc8000000 */
 95      1.07321789251584000000e+14,  /* 0x42d866f348000000 */
 96      2.91730863685632000000e+14,  /* 0x42f0953e28000000 */
 97      7.93006722514944000000e+14,  /* 0x430689e220000000 */
 98      2.15561576592179200000e+15}; /* 0x431ea215a0000000 */
 99  
100    static const double sinh_tail[37] = {
101      0.00000000000000000000e+00,  /* 0x0000000000000000 */
102      1.60467555584448807892e-08,  /* 0x3e513ae6096a0092 */
103      2.76742892754807136947e-08,  /* 0x3e5db70cfb79a640 */
104      2.09697499555224576530e-07,  /* 0x3e8c2526b66dc067 */
105      2.04940252448908240062e-07,  /* 0x3e8b81b18647f380 */
106      1.65444891522700935932e-06,  /* 0x3ebbc1cdd1e1eb08 */
107      3.53116789999998198721e-06,  /* 0x3ecd9f201534fb09 */
108      6.94023870987375490695e-06,  /* 0x3edd1c064a4e9954 */
109      4.98876893611587449271e-06,  /* 0x3ed4eca65d06ea74 */
110      3.19656024605152215752e-05,  /* 0x3f00c259bcc0ecc5 */
111      2.08687768377236501204e-04,  /* 0x3f2b5a6647cf9016 */
112      4.84668088325403796299e-05,  /* 0x3f09691adefb0870 */
113      1.17517985422733832468e-03,  /* 0x3f53410fc29cde38 */
114      6.90830086959560562415e-04,  /* 0x3f46a31a50b6fb3c */
115      1.45697262451506548420e-03,  /* 0x3f57defc71805c40 */
116      2.99859023684906737806e-02,  /* 0x3f9eb49fd80e0bab */
117      1.02538800507941396667e-02,  /* 0x3f84fffc7bcd5920 */
118      1.26787628407699110022e-01,  /* 0x3fc03a93b6c63435 */
119      6.86652479544033744752e-02,  /* 0x3fb1940bb255fd1c */
120      4.81593627621056619148e-01,  /* 0x3fded26e14260b50 */
121      1.70489513795397629181e+00,  /* 0x3ffb47401fc9f2a2 */
122      1.12416073482258713767e+01,  /* 0x40267bb3f55634f1 */
123      7.06579578070110514432e+00,  /* 0x401c435ff8194ddc */
124      5.91244512999659974639e+01,  /* 0x404d8fee052ba63a */
125      1.68921736147050694399e+02,  /* 0x40651d7edccde3f6 */
126      2.60692936262073658327e+02,  /* 0x40704b1644557d1a */
127      3.62419382134885609048e+02,  /* 0x4076a6b5ca0a9dc4 */
128      4.07689930834187271103e+03,  /* 0x40afd9cc72249aba */
129      1.55377375868385224749e+04,  /* 0x40ce58de693edab5 */
130      2.53720210371943067003e+04,  /* 0x40d8c70158ac6363 */
131      4.78822310734952334315e+04,  /* 0x40e7614764f43e20 */
132      1.81871712615542812273e+05,  /* 0x4106337db36fc718 */
133      5.62892347580489004031e+05,  /* 0x41212d98b1f611e2 */
134      6.41374032312148716301e+05,  /* 0x412392bc108b37cc */
135      7.57809544070145115256e+06,  /* 0x415ce87bdc3473dc */
136      3.64177136406482197344e+06,  /* 0x414bc8d5ae99ad14 */
137      7.63580561355670914054e+06}; /* 0x415d20d76744835c */
138  
139    static const double cosh_lead[37] = {
140      1.00000000000000000000e+00,  /* 0x3ff0000000000000 */
141      1.54308062791824340820e+00,  /* 0x3ff8b07550000000 */
142      3.76219564676284790039e+00,  /* 0x400e18fa08000000 */
143      1.00676617622375488281e+01,  /* 0x402422a490000000 */
144      2.73082327842712402344e+01,  /* 0x403b4ee858000000 */
145      7.42099475860595703125e+01,  /* 0x40528d6fc8000000 */
146      2.01715633392333984375e+02,  /* 0x406936e678000000 */
147      5.48317031860351562500e+02,  /* 0x4081228948000000 */
148      1.49047915649414062500e+03,  /* 0x409749eaa8000000 */
149      4.05154199218750000000e+03,  /* 0x40afa71580000000 */
150      1.10132329101562500000e+04,  /* 0x40c5829dd0000000 */
151      2.99370708007812500000e+04,  /* 0x40dd3c4488000000 */
152      8.13773945312500000000e+04,  /* 0x40f3de1650000000 */
153      2.21206695312500000000e+05,  /* 0x410b00b590000000 */
154      6.01302140625000000000e+05,  /* 0x412259ac48000000 */
155      1.63450865625000000000e+06,  /* 0x4138f0cca8000000 */
156      4.44305525000000000000e+06,  /* 0x4150f2ebd0000000 */
157      1.20774762500000000000e+07,  /* 0x4167093488000000 */
158      3.28299845000000000000e+07,  /* 0x417f4f2208000000 */
159      8.92411500000000000000e+07,  /* 0x419546d8f8000000 */
160      2.42582596000000000000e+08,  /* 0x41aceb0888000000 */
161      6.59407856000000000000e+08,  /* 0x41c3a6e1f8000000 */
162      1.79245641600000000000e+09,  /* 0x41dab5adb8000000 */
163      4.87240166400000000000e+09,  /* 0x41f226af30000000 */
164      1.32445608960000000000e+10,  /* 0x4208ab7fb0000000 */
165      3.60024494080000000000e+10,  /* 0x4220c3d390000000 */
166      9.78648043520000000000e+10,  /* 0x4236c93268000000 */
167      2.66024116224000000000e+11,  /* 0x424ef822f0000000 */
168      7.23128516608000000000e+11,  /* 0x42650bba30000000 */
169      1.96566712320000000000e+12,  /* 0x427c9aae40000000 */
170      5.34323724288000000000e+12,  /* 0x4293704708000000 */
171      1.45244246507520000000e+13,  /* 0x42aa6b7658000000 */
172      3.94814795284480000000e+13,  /* 0x42c1f43fc8000000 */
173      1.07321789251584000000e+14,  /* 0x42d866f348000000 */
174      2.91730863685632000000e+14,  /* 0x42f0953e28000000 */
175      7.93006722514944000000e+14,  /* 0x430689e220000000 */
176      2.15561576592179200000e+15}; /* 0x431ea215a0000000 */
177  
178    static const double cosh_tail[37] = {
179      0.00000000000000000000e+00,  /* 0x0000000000000000 */
180      6.89700037027478056904e-09,  /* 0x3e3d9f5504c2bd28 */
181      4.43207835591715833630e-08,  /* 0x3e67cb66f0a4c9fd */
182      2.33540217013828929694e-07,  /* 0x3e8f58617928e588 */
183      5.17452463948269748331e-08,  /* 0x3e6bc7d000c38d48 */
184      9.38728274131605919153e-07,  /* 0x3eaf7f9d4e329998 */
185      2.73012191010840495544e-06,  /* 0x3ec6e6e464885269 */
186      3.29486051438996307950e-06,  /* 0x3ecba3a8b946c154 */
187      4.75803746362771416375e-06,  /* 0x3ed3f4e76110d5a4 */
188      3.33050940471947692369e-05,  /* 0x3f017622515a3e2b */
189      9.94707313972136215365e-06,  /* 0x3ee4dc4b528af3d0 */
190      6.51685096227860253398e-05,  /* 0x3f11156278615e10 */
191      1.18132406658066663359e-03,  /* 0x3f535ad50ed821f5 */
192      6.93090416366541877541e-04,  /* 0x3f46b61055f2935c */
193      1.45780415323416845386e-03,  /* 0x3f57e2794a601240 */
194      2.99862082708111758744e-02,  /* 0x3f9eb4b45f6aadd3 */
195      1.02539925859688602072e-02,  /* 0x3f85000b967b3698 */
196      1.26787669807076286421e-01,  /* 0x3fc03a940fadc092 */
197      6.86652631843830962843e-02,  /* 0x3fb1940bf3bf874c */
198      4.81593633223853068159e-01,  /* 0x3fded26e1a2a2110 */
199      1.70489514001513020602e+00,  /* 0x3ffb4740205796d6 */
200      1.12416073489841270572e+01,  /* 0x40267bb3f55cb85d */
201      7.06579578098005001152e+00,  /* 0x401c435ff81e18ac */
202      5.91244513000686140458e+01,  /* 0x404d8fee052bdea4 */
203      1.68921736147088438429e+02,  /* 0x40651d7edccde926 */
204      2.60692936262087528121e+02,  /* 0x40704b1644557e0e */
205      3.62419382134890611269e+02,  /* 0x4076a6b5ca0a9e1c */
206      4.07689930834187453002e+03,  /* 0x40afd9cc72249abe */
207      1.55377375868385224749e+04,  /* 0x40ce58de693edab5 */
208      2.53720210371943103382e+04,  /* 0x40d8c70158ac6364 */
209      4.78822310734952334315e+04,  /* 0x40e7614764f43e20 */
210      1.81871712615542812273e+05,  /* 0x4106337db36fc718 */
211      5.62892347580489004031e+05,  /* 0x41212d98b1f611e2 */
212      6.41374032312148716301e+05,  /* 0x412392bc108b37cc */
213      7.57809544070145115256e+06,  /* 0x415ce87bdc3473dc */
214      3.64177136406482197344e+06,  /* 0x414bc8d5ae99ad14 */
215      7.63580561355670914054e+06}; /* 0x415d20d76744835c */
216  
217    unsigned long long ux, aux, xneg;
218    double y, z, z1, z2;
219    int m;
220  
221    /* Special cases */
222  
223    GET_BITS_DP64(x, ux);
224    aux = ux & ~SIGNBIT_DP64;
225    if (aux < 0x3e30000000000000) /* |x| small enough that sinh(x) = x */
226      {
227          if (aux == 0x0000000000000000)
228          {
229              /* x is +/-zero. Return the same zero. */
230              return x;
231          }
232          else
233          {
234             
235  #ifdef WINDOWS
236          return x;
237  #else
238          return __amd_handle_error("sinh", __amd_sinh, ux, _UNDERFLOW, AMD_F_INEXACT|AMD_F_UNDERFLOW, ERANGE, x, 0.0, 1);
239  #endif
240          }
241      }
242    else if (aux == 0x7ff0000000000000) /* |x| is Inf */
243      {
244          return x;
245      }
246    else if  (aux > 0x7ff0000000000000) /* |x| is NaN */
247      {
248  #ifdef WINDOWS
249  		return __amd_handle_error("sinh", __amd_sinh, ux|QNANBITPATT_DP64, _DOMAIN, AMD_F_NONE, EDOM, x, 0.0, 1);
250  #else
251          return x+x;
252  #endif
253      }
254  
255  
256    xneg = (aux != ux);
257  
258    y = x;
259    if (xneg) y = -x;
260  
261    if (y >= max_sinh_arg)
262      {
263        /* Return +/-infinity with overflow flag */
264        if (xneg)
265  		  return __amd_handle_error("sinh", __amd_sinh, NINFBITPATT_DP64, _OVERFLOW, AMD_F_OVERFLOW, ERANGE, x, 0.0, 1);
266        else
267  		  return __amd_handle_error("sinh", __amd_sinh, PINFBITPATT_DP64, _OVERFLOW, AMD_F_OVERFLOW, ERANGE, x, 0.0, 1);
268  
269      }
270    else if (y >= small_threshold)
271      {
272        /* In this range y is large enough so that
273           the negative exponential is negligible,
274           so sinh(y) is approximated by sign(x)*exp(y)/2. The
275           code below is an inlined version of that from
276           exp() with two changes (it operates on
277           y instead of x, and the division by 2 is
278           done by reducing m by 1). */
279  
280        splitexp(y, 1.0, thirtytwo_by_log2, log2_by_32_lead,
281                 log2_by_32_tail, &m, &z1, &z2);
282        m -= 1;
283  
284        if (m >= EMIN_DP64 && m <= EMAX_DP64)
285          z = scaleDouble_1((z1+z2),m);
286        else
287          z = scaleDouble_2((z1+z2),m);
288      }
289    else
290      {
291        /* In this range we find the integer part y0 of y
292           and the increment dy = y - y0. We then compute
293  
294           z = sinh(y) = sinh(y0)cosh(dy) + cosh(y0)sinh(dy)
295  
296           where sinh(y0) and cosh(y0) are tabulated above. */
297  
298        int ind;
299        double dy, dy2, sdy, cdy, sdy1, sdy2;
300  
301        ind = (int)y;
302        dy = y - ind;
303  
304        dy2 = dy*dy;
305        sdy = dy*dy2*(0.166666666666666667013899e0 +
306                      (0.833333333333329931873097e-2 +
307                       (0.198412698413242405162014e-3 +
308                        (0.275573191913636406057211e-5 +
309                         (0.250521176994133472333666e-7 +
310                          (0.160576793121939886190847e-9 +
311                           0.7746188980094184251527126e-12*dy2)*dy2)*dy2)*dy2)*dy2)*dy2);
312  
313        cdy = dy2*(0.500000000000000005911074e0 +
314                   (0.416666666666660876512776e-1 +
315                    (0.138888888889814854814536e-2 +
316                     (0.248015872460622433115785e-4 +
317                      (0.275573350756016588011357e-6 +
318                       (0.208744349831471353536305e-8 +
319                        0.1163921388172173692062032e-10*dy2)*dy2)*dy2)*dy2)*dy2)*dy2);
320  
321        /* At this point sinh(dy) is approximated by dy + sdy.
322  	 Shift some significant bits from dy to sdy. */
323  
324        GET_BITS_DP64(dy, ux);
325        ux &= 0xfffffffff8000000;
326        PUT_BITS_DP64(ux, sdy1);
327        sdy2 = sdy + (dy - sdy1);
328  
329        z = ((((((cosh_tail[ind]*sdy2 + sinh_tail[ind]*cdy)
330  	       + cosh_tail[ind]*sdy1) + sinh_tail[ind])
331  	     + cosh_lead[ind]*sdy2) + sinh_lead[ind]*cdy)
332  	   + cosh_lead[ind]*sdy1) + sinh_lead[ind];
333      }
334  
335    if (xneg) z = - z;
336    return z;
337  }
338  
339