summaryrefslogtreecommitdiff
path: root/src/classlibnative/float/floatdouble.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/classlibnative/float/floatdouble.cpp')
-rw-r--r--src/classlibnative/float/floatdouble.cpp280
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
+///
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////