/* * Copyright (c) 1999 * Silicon Graphics Computer Systems, Inc. * * Copyright (c) 1999 * Boris Fomitchev * * This material is provided "as is", with absolutely no warranty expressed * or implied. Any use is at your own risk. * * Permission to use or copy this software for any purpose is hereby granted * without fee, provided the above notices are retained on all copies. * Permission to modify the code and to distribute modified code is granted, * provided the above notices are retained, and a notice that the code was * modified is included with the above copyright notice. * */ #include "stlport_prefix.h" // Trigonometric and hyperbolic functions for complex<float>, // complex<double>, and complex<long double> #include <complex> #include <cfloat> #include <cmath> _STLP_BEGIN_NAMESPACE //---------------------------------------------------------------------- // helpers #if defined (__sgi) static const union { unsigned int i; float f; } float_ulimit = { 0x42b2d4fc }; static const float float_limit = float_ulimit.f; static union { struct { unsigned int h; unsigned int l; } w; double d; } double_ulimit = { 0x408633ce, 0x8fb9f87d }; static const double double_limit = double_ulimit.d; static union { struct { unsigned int h[2]; unsigned int l[2]; } w; long double ld; } ldouble_ulimit = {0x408633ce, 0x8fb9f87e, 0xbd23b659, 0x4e9bd8b1}; # if !defined (_STLP_NO_LONG_DOUBLE) # define ldouble_limit ldouble_ulimit.ld # endif #else # if defined (M_LN2) && defined (FLT_MAX_EXP) static const float float_limit = float(M_LN2 * FLT_MAX_EXP); static const double double_limit = M_LN2 * DBL_MAX_EXP; # else static const float float_limit = ::log(FLT_MAX); static const double double_limit = ::log(DBL_MAX); # endif # if !defined (_STLP_NO_LONG_DOUBLE) # if defined (M_LN2l) # define ldouble_limit (M_LN2l * LDBL_MAX_EXP) # else # define ldouble_limit ::log(LDBL_MAX) # endif # endif #endif //---------------------------------------------------------------------- // sin template <class _Tp> static complex<_Tp> sinT(const complex<_Tp>& z) { return complex<_Tp>(::sin(z._M_re) * ::cosh(z._M_im), ::cos(z._M_re) * ::sinh(z._M_im)); } _STLP_DECLSPEC complex<float> _STLP_CALL sin(const complex<float>& z) { return sinT(z); } _STLP_DECLSPEC complex<double> _STLP_CALL sin(const complex<double>& z) { return sinT(z); } #if !defined (_STLP_NO_LONG_DOUBLE) _STLP_DECLSPEC complex<long double> _STLP_CALL sin(const complex<long double>& z) { return sinT(z); } #endif //---------------------------------------------------------------------- // cos template <class _Tp> static complex<_Tp> cosT(const complex<_Tp>& z) { return complex<_Tp>(::cos(z._M_re) * ::cosh(z._M_im), -::sin(z._M_re) * ::sinh(z._M_im)); } _STLP_DECLSPEC complex<float> _STLP_CALL cos(const complex<float>& z) { return cosT(z); } _STLP_DECLSPEC complex<double> _STLP_CALL cos(const complex<double>& z) { return cosT(z); } #if !defined (_STLP_NO_LONG_DOUBLE) _STLP_DECLSPEC complex<long double> _STLP_CALL cos(const complex<long double>& z) { return cosT(z); } #endif //---------------------------------------------------------------------- // tan template <class _Tp> static complex<_Tp> tanT(const complex<_Tp>& z, const _Tp& Tp_limit) { _Tp re2 = 2.f * z._M_re; _Tp im2 = 2.f * z._M_im; if (::abs(im2) > Tp_limit) return complex<_Tp>(0.f, (im2 > 0 ? 1.f : -1.f)); else { _Tp den = ::cos(re2) + ::cosh(im2); return complex<_Tp>(::sin(re2) / den, ::sinh(im2) / den); } } _STLP_DECLSPEC complex<float> _STLP_CALL tan(const complex<float>& z) { return tanT(z, float_limit); } _STLP_DECLSPEC complex<double> _STLP_CALL tan(const complex<double>& z) { return tanT(z, double_limit); } #if !defined (_STLP_NO_LONG_DOUBLE) _STLP_DECLSPEC complex<long double> _STLP_CALL tan(const complex<long double>& z) { return tanT(z, ldouble_limit); } #endif //---------------------------------------------------------------------- // sinh template <class _Tp> static complex<_Tp> sinhT(const complex<_Tp>& z) { return complex<_Tp>(::sinh(z._M_re) * ::cos(z._M_im), ::cosh(z._M_re) * ::sin(z._M_im)); } _STLP_DECLSPEC complex<float> _STLP_CALL sinh(const complex<float>& z) { return sinhT(z); } _STLP_DECLSPEC complex<double> _STLP_CALL sinh(const complex<double>& z) { return sinhT(z); } #if !defined (_STLP_NO_LONG_DOUBLE) _STLP_DECLSPEC complex<long double> _STLP_CALL sinh(const complex<long double>& z) { return sinhT(z); } #endif //---------------------------------------------------------------------- // cosh template <class _Tp> static complex<_Tp> coshT(const complex<_Tp>& z) { return complex<_Tp>(::cosh(z._M_re) * ::cos(z._M_im), ::sinh(z._M_re) * ::sin(z._M_im)); } _STLP_DECLSPEC complex<float> _STLP_CALL cosh(const complex<float>& z) { return coshT(z); } _STLP_DECLSPEC complex<double> _STLP_CALL cosh(const complex<double>& z) { return coshT(z); } #if !defined (_STLP_NO_LONG_DOUBLE) _STLP_DECLSPEC complex<long double> _STLP_CALL cosh(const complex<long double>& z) { return coshT(z); } #endif //---------------------------------------------------------------------- // tanh template <class _Tp> static complex<_Tp> tanhT(const complex<_Tp>& z, const _Tp& Tp_limit) { _Tp re2 = 2.f * z._M_re; _Tp im2 = 2.f * z._M_im; if (::abs(re2) > Tp_limit) return complex<_Tp>((re2 > 0 ? 1.f : -1.f), 0.f); else { _Tp den = ::cosh(re2) + ::cos(im2); return complex<_Tp>(::sinh(re2) / den, ::sin(im2) / den); } } _STLP_DECLSPEC complex<float> _STLP_CALL tanh(const complex<float>& z) { return tanhT(z, float_limit); } _STLP_DECLSPEC complex<double> _STLP_CALL tanh(const complex<double>& z) { return tanhT(z, double_limit); } #if !defined (_STLP_NO_LONG_DOUBLE) _STLP_DECLSPEC complex<long double> _STLP_CALL tanh(const complex<long double>& z) { return tanhT(z, ldouble_limit); } #endif _STLP_END_NAMESPACE