@@ -482,10 +482,9 @@ static @ctype@ _npy_scaled_cexp@c@(@type@ x, @type@ y, npy_int expt)
482482#ifndef HAVE_CSIN @C @
483483@ctype @ npy_csin @c @(@ctype @ z )
484484{
485- @type @ x , y ;
486- x = npy_creal @c @(z );
487- y = npy_cimag @c @(z );
488- return npy_cpack @c @(npy_sin @c @(x ) * npy_cosh @c @(y ), npy_cos @c @(x ) * npy_sinh @c @(y ));
485+ /* csin(z) = -I * csinh(I * z) */
486+ z = npy_csinh @c @(npy_cpack @c @(- npy_cimag @c @(z ), npy_creal @c @(z )));
487+ return npy_cpack @c @(npy_cimag @c @(z ), - npy_creal @c @(z ));
489488}
490489#endif
491490
@@ -627,13 +626,132 @@ static @ctype@ _npy_scaled_cexp@c@(@type@ x, @type@ y, npy_int expt)
627626#endif
628627
629628#ifndef HAVE_CSINH @C @
629+ /*
630+ * Taken from the msun library in FreeBSD, rev 226599.
631+ *
632+ * Hyperbolic sine of a complex argument z = x + i y.
633+ *
634+ * sinh(z) = sinh(x+iy)
635+ * = sinh(x) cos(y) + i cosh(x) sin(y).
636+ *
637+ * Exceptional values are noted in the comments within the source code.
638+ * These values and the return value were taken from n1124.pdf.
639+ */
640+
641+ #if @precision @ == 1
642+ #define CSINH_BIG 9.0f
643+ #define CSINH_HUGE 1.70141183e+38f
644+ #endif
645+ #if @precision @ == 2
646+ #define CSINH_BIG 22.0
647+ #define CSINH_HUGE 8.9884656743115795e+307
648+ #endif
649+ #if @precision @ >= 3
650+ #define CSINH_BIG 24.0L
651+ #define CSINH_HUGE 5.94865747678615882543e+4931L
652+ #endif
653+
630654@ctype @ npy_csinh @c @(@ctype @ z )
631655{
632- @type @ x , y ;
656+ @type @ x , y , h , absx ;
657+ npy_int xfinite , yfinite ;
658+
633659 x = npy_creal @c @(z );
634660 y = npy_cimag @c @(z );
635- return npy_cpack @c @(npy_cos @c @(y )* npy_sinh @c @(x ), npy_sin @c @(y )* npy_cosh @c @(x ));
661+
662+ xfinite = npy_isfinite (x );
663+ yfinite = npy_isfinite (y );
664+
665+ /* Handle the nearly-non-exceptional cases where x and y are finite. */
666+ if (xfinite && yfinite ) {
667+ if (y == 0 )
668+ return npy_cpack @c @(npy_sinh @c @(x ), y );
669+ absx = npy_fabs @c @(x );
670+ if (absx < CSINH_BIG ) /* small x: normal case */
671+ return npy_cpack @c @(npy_sinh @c @(x ) * npy_cos @c @(y ), npy_cosh @c @(x ) * npy_sin @c @(y ));
672+
673+ /* |x| >= 22, so cosh(x) ~= exp(|x|) */
674+ if (absx < SCALED_CEXP_LOWER @C @) {
675+ /* x < 710: exp(|x|) won't overflow */
676+ h = npy_exp @c @(npy_fabs @c @(x )) * 0.5 ;
677+ return npy_cpack @c @(npy_copysign @c @(h , x ) * npy_cos @c @(y ), h * npy_sin @c @(y ));
678+ } else if (x < SCALED_CEXP_UPPER @C @) {
679+ /* x < 1455: scale to avoid overflow */
680+ z = _npy_scaled_cexp @c @(absx , y , -1 );
681+ return npy_cpack @c @(npy_creal @c @(z ) * npy_copysign @c @(1 , x ), npy_cimag @c @(z ));
682+ } else {
683+ /* x >= 1455: the result always overflows */
684+ h = CSINH_HUGE * x ;
685+ return npy_cpack @c @(h * npy_cos @c @(y ), h * h * npy_sin @c @(y ));
686+ }
687+ }
688+
689+ /*
690+ * sinh(+-0 +- I Inf) = sign(d(+-0, dNaN))0 + I dNaN.
691+ * The sign of 0 in the result is unspecified. Choice = normally
692+ * the same as dNaN. Raise the invalid floating-point exception.
693+ *
694+ * sinh(+-0 +- I NaN) = sign(d(+-0, NaN))0 + I d(NaN).
695+ * The sign of 0 in the result is unspecified. Choice = normally
696+ * the same as d(NaN).
697+ */
698+ if (x == 0 && !yfinite )
699+ return npy_cpack @c @(npy_copysign @c @(0 , x * (y - y )), y - y );
700+
701+ /*
702+ * sinh(+-Inf +- I 0) = +-Inf + I +-0.
703+ *
704+ * sinh(NaN +- I 0) = d(NaN) + I +-0.
705+ */
706+ if (y == 0 && !xfinite ) {
707+ if (npy_isnan (x ))
708+ return z ;
709+ return npy_cpack @c @(x , npy_copysign @c @(0 , y ));
710+ }
711+
712+ /*
713+ * sinh(x +- I Inf) = dNaN + I dNaN.
714+ * Raise the invalid floating-point exception for finite nonzero x.
715+ *
716+ * sinh(x + I NaN) = d(NaN) + I d(NaN).
717+ * Optionally raises the invalid floating-point exception for finite
718+ * nonzero x. Choice = don't raise (except for signaling NaNs).
719+ */
720+ if (xfinite && !yfinite )
721+ return npy_cpack @c @(y - y , x * (y - y ));
722+
723+ /*
724+ * sinh(+-Inf + I NaN) = +-Inf + I d(NaN).
725+ * The sign of Inf in the result is unspecified. Choice = normally
726+ * the same as d(NaN).
727+ *
728+ * sinh(+-Inf +- I Inf) = +Inf + I dNaN.
729+ * The sign of Inf in the result is unspecified. Choice = always +.
730+ * Raise the invalid floating-point exception.
731+ *
732+ * sinh(+-Inf + I y) = +-Inf cos(y) + I Inf sin(y)
733+ */
734+ if (!xfinite && !npy_isnan (x )) {
735+ if (!yfinite )
736+ return npy_cpack @c @(x * x , x * (y - y ));
737+ return npy_cpack @c @(x * npy_cos @c @(y ), NPY_INFINITY @C @ * npy_sin @c @(y ));
738+ }
739+
740+ /*
741+ * sinh(NaN + I NaN) = d(NaN) + I d(NaN).
742+ *
743+ * sinh(NaN +- I Inf) = d(NaN) + I d(NaN).
744+ * Optionally raises the invalid floating-point exception.
745+ * Choice = raise.
746+ *
747+ * sinh(NaN + I y) = d(NaN) + I d(NaN).
748+ * Optionally raises the invalid floating-point exception for finite
749+ * nonzero y. Choice = don't raise (except for signaling NaNs).
750+ */
751+ return npy_cpack @c @((x * x ) * (y - y ), (x + x ) * (y - y ));
636752}
753+ #undef CSINH_BIG
754+ #undef CSINH_HUGE
637755#endif
638756
639757#ifndef HAVE_CTANH @C @
0 commit comments