diff options
Diffstat (limited to 'src/classlibnative/float/floatdouble.cpp')
-rw-r--r-- | src/classlibnative/float/floatdouble.cpp | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/src/classlibnative/float/floatdouble.cpp b/src/classlibnative/float/floatdouble.cpp new file mode 100644 index 0000000000..d9603c0636 --- /dev/null +++ b/src/classlibnative/float/floatdouble.cpp @@ -0,0 +1,280 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// +// File: FloatDouble.cpp +// + +#include <common.h> + +#include "floatdouble.h" + +#define IS_DBL_INFINITY(x) (((*((INT64*)((void*)&x))) & I64(0x7FFFFFFFFFFFFFFF)) == I64(0x7FF0000000000000)) + +// The default compilation mode is /fp:precise, which disables floating-point intrinsics. This +// default compilation mode has previously caused performance regressions in floating-point code. +// We enable /fp:fast semantics for the majority of the math functions, as it will speed up performance +// and is really unlikely to cause any other code regressions. + +// Sin, Cos, and Tan on AMD64 Windows were previously implemented in vm\amd64\JitHelpers_Fast.asm +// by calling x87 floating point code (fsin, fcos, fptan) because the CRT helpers were too slow. This +// is no longer the case and the CRT call is used on all platforms. + +// Log, Log10 and Exp were previously slower with /fp:fast on SSE2 enabled hardware (see #500373). +// This is no longer the case and they now consume use the /fp:fast versions. + +// Exp(+/-INFINITY) did not previously return the expected results of +0.0 (for -INFINITY) +// and +INFINITY (for +INFINITY) so these cases were handled specially. As this is no longer +// the case and the expected results are now returned, the special handling has been removed. + +// Previously there was more special handling for the x86 Windows version of Pow. +// This additional handling was unnecessary and has since been removed. + +//////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////// +/// +/// beginning of /fp:fast scope +/// +//////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////// + +#ifdef _MSC_VER +#pragma float_control(precise, off) +#endif + +/*=====================================Abs====================================== +** +==============================================================================*/ +FCIMPL1_V(double, COMDouble::Abs, double x) + FCALL_CONTRACT; + + return (double)fabs(x); +FCIMPLEND + +/*=====================================Acos===================================== +** +==============================================================================*/ +FCIMPL1_V(double, COMDouble::Acos, double x) + FCALL_CONTRACT; + + return (double)acos(x); +FCIMPLEND + +/*=====================================Asin===================================== +** +==============================================================================*/ +FCIMPL1_V(double, COMDouble::Asin, double x) + FCALL_CONTRACT; + + return (double)asin(x); +FCIMPLEND + +/*=====================================Atan===================================== +** +==============================================================================*/ +FCIMPL1_V(double, COMDouble::Atan, double x) + FCALL_CONTRACT; + + return (double)atan(x); +FCIMPLEND + +/*=====================================Atan2==================================== +** +==============================================================================*/ +FCIMPL2_VV(double, COMDouble::Atan2, double y, double x) + FCALL_CONTRACT; + + // atan2(+/-INFINITY, +/-INFINITY) produces +/-0.78539816339744828 (x is +INFINITY) and + // +/-2.3561944901923448 (x is -INFINITY) instead of the expected value of NaN. We handle + // that case here ourselves. + if (IS_DBL_INFINITY(y) && IS_DBL_INFINITY(x)) { + return (double)(y / x); + } + + return (double)atan2(y, x); +FCIMPLEND + +/*====================================Ceil====================================== +** +==============================================================================*/ +FCIMPL1_V(double, COMDouble::Ceil, double x) + FCALL_CONTRACT; + + return (double)ceil(x); +FCIMPLEND + +/*=====================================Cos====================================== +** +==============================================================================*/ +FCIMPL1_V(double, COMDouble::Cos, double x) + FCALL_CONTRACT; + + return (double)cos(x); +FCIMPLEND + +/*=====================================Cosh===================================== +** +==============================================================================*/ +FCIMPL1_V(double, COMDouble::Cosh, double x) + FCALL_CONTRACT; + + return (double)cosh(x); +FCIMPLEND + +/*=====================================Exp====================================== +** +==============================================================================*/ +FCIMPL1_V(double, COMDouble::Exp, double x) + FCALL_CONTRACT; + + return (double)exp(x); +FCIMPLEND + +/*====================================Floor===================================== +** +==============================================================================*/ +FCIMPL1_V(double, COMDouble::Floor, double x) + FCALL_CONTRACT; + + return (double)floor(x); +FCIMPLEND + +/*=====================================Log====================================== +** +==============================================================================*/ +FCIMPL1_V(double, COMDouble::Log, double x) + FCALL_CONTRACT; + + return (double)log(x); +FCIMPLEND + +/*====================================Log10===================================== +** +==============================================================================*/ +FCIMPL1_V(double, COMDouble::Log10, double x) + FCALL_CONTRACT; + + return (double)log10(x); +FCIMPLEND + +/*=====================================ModF===================================== +** +==============================================================================*/ +FCIMPL1(double, COMDouble::ModF, double* iptr) + FCALL_CONTRACT; + + return (double)modf(*iptr, iptr); +FCIMPLEND + +/*=====================================Pow====================================== +** +==============================================================================*/ +FCIMPL2_VV(double, COMDouble::Pow, double x, double y) + FCALL_CONTRACT; + + // The CRT version of pow preserves the NaN payload of x over the NaN payload of y. + + if(_isnan(y)) { + return y; // IEEE 754-2008: NaN payload must be preserved + } + + if(_isnan(x)) { + return x; // IEEE 754-2008: NaN payload must be preserved + } + + // The CRT version of pow does not return NaN for pow(-1.0, +/-INFINITY) and + // instead returns +1.0. + + if(IS_DBL_INFINITY(y) && (x == -1.0)) { + INT64 result = CLR_NAN_64; + return (*((double*)((INT64*)&result))); + } + + return (double)pow(x, y); +FCIMPLEND + +/*====================================Round===================================== +** +==============================================================================*/ +FCIMPL1_V(double, COMDouble::Round, double x) + FCALL_CONTRACT; + + // If the number has no fractional part do nothing + // This shortcut is necessary to workaround precision loss in borderline cases on some platforms + if (x == (double)((INT64)x)) { + return x; + } + + // We had a number that was equally close to 2 integers. + // We need to return the even one. + + double tempVal = (x + 0.5); + double flrTempVal = floor(tempVal); + + if ((flrTempVal == tempVal) && (fmod(tempVal, 2.0) != 0)) { + flrTempVal -= 1.0; + } + + return _copysign(flrTempVal, x); +FCIMPLEND + +/*=====================================Sin====================================== +** +==============================================================================*/ +FCIMPL1_V(double, COMDouble::Sin, double x) + FCALL_CONTRACT; + + return (double)sin(x); +FCIMPLEND + +/*=====================================Sinh===================================== +** +==============================================================================*/ +FCIMPL1_V(double, COMDouble::Sinh, double x) + FCALL_CONTRACT; + + return (double)sinh(x); +FCIMPLEND + +/*=====================================Sqrt===================================== +** +==============================================================================*/ +FCIMPL1_V(double, COMDouble::Sqrt, double x) + FCALL_CONTRACT; + + return (double)sqrt(x); +FCIMPLEND + +/*=====================================Tan====================================== +** +==============================================================================*/ +FCIMPL1_V(double, COMDouble::Tan, double x) + FCALL_CONTRACT; + + return (double)tan(x); +FCIMPLEND + +/*=====================================Tanh===================================== +** +==============================================================================*/ +FCIMPL1_V(double, COMDouble::Tanh, double x) + FCALL_CONTRACT; + + return (double)tanh(x); +FCIMPLEND + +#ifdef _MSC_VER +#pragma float_control(precise, on ) +#endif + +//////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////// +/// +/// End of /fp:fast scope +/// +//////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////// |