Improvements to System.Math InternalCall code. (#4847)
authorTanner Gooding <tannergooding@users.noreply.github.com>
Thu, 2 Jun 2016 01:17:24 +0000 (18:17 -0700)
committerJan Vorlicek <janvorli@microsoft.com>
Thu, 2 Jun 2016 01:17:24 +0000 (03:17 +0200)
* Adding some basic System.Math performance tests.

* Renaming 'floatnative' to 'floatdouble'.

* Removing outdated workarounds in the floatdouble interop code.

* Renaming 'finite.cpp' to 'math.cpp'

* Updating the double-precision math tests.

* Updating PAL_EPSILON to be more precise.

120 files changed:
src/classlibnative/float/CMakeLists.txt
src/classlibnative/float/Float.nativeproj
src/classlibnative/float/floatdouble.cpp [new file with mode: 0644]
src/classlibnative/float/floatnative.cpp [deleted file]
src/classlibnative/float/floatnative.h [deleted file]
src/classlibnative/float/floatsingle.cpp [new file with mode: 0644]
src/classlibnative/inc/floatclass.h [deleted file]
src/classlibnative/inc/floatdouble.h [new file with mode: 0644]
src/classlibnative/inc/floatsingle.h [new file with mode: 0644]
src/jit/utils.cpp
src/jit/utils.h
src/pal/inc/pal.h
src/pal/src/CMakeLists.txt
src/pal/src/cruntime/math.cpp [moved from src/pal/src/cruntime/finite.cpp with 72% similarity]
src/pal/src/include/pal/palinternal.h
src/pal/tests/palsuite/c_runtime/CMakeLists.txt
src/pal/tests/palsuite/c_runtime/_finite/CMakeLists.txt
src/pal/tests/palsuite/c_runtime/_finite/test1/test1.c
src/pal/tests/palsuite/c_runtime/_finite/test1/testinfo.dat
src/pal/tests/palsuite/c_runtime/_isnan/CMakeLists.txt
src/pal/tests/palsuite/c_runtime/_isnan/test1/test1.c
src/pal/tests/palsuite/c_runtime/acos/CMakeLists.txt
src/pal/tests/palsuite/c_runtime/acos/test1/test1.c
src/pal/tests/palsuite/c_runtime/acos/test1/testinfo.dat
src/pal/tests/palsuite/c_runtime/asin/CMakeLists.txt
src/pal/tests/palsuite/c_runtime/asin/test1/test1.c
src/pal/tests/palsuite/c_runtime/asin/test1/testinfo.dat
src/pal/tests/palsuite/c_runtime/atan/CMakeLists.txt
src/pal/tests/palsuite/c_runtime/atan/test1/test1.c
src/pal/tests/palsuite/c_runtime/atan/test1/testinfo.dat
src/pal/tests/palsuite/c_runtime/atan2/CMakeLists.txt
src/pal/tests/palsuite/c_runtime/atan2/test1/test1.c
src/pal/tests/palsuite/c_runtime/ceil/CMakeLists.txt
src/pal/tests/palsuite/c_runtime/ceil/test1/test1.c
src/pal/tests/palsuite/c_runtime/cos/CMakeLists.txt
src/pal/tests/palsuite/c_runtime/cos/test1/test1.c
src/pal/tests/palsuite/c_runtime/cos/test1/testinfo.dat
src/pal/tests/palsuite/c_runtime/cosh/CMakeLists.txt
src/pal/tests/palsuite/c_runtime/cosh/test1/test1.c
src/pal/tests/palsuite/c_runtime/cosh/test1/testinfo.dat
src/pal/tests/palsuite/c_runtime/exp/CMakeLists.txt
src/pal/tests/palsuite/c_runtime/exp/test1/test1.c
src/pal/tests/palsuite/c_runtime/exp/test2/test2.c [deleted file]
src/pal/tests/palsuite/c_runtime/exp/test3/test3.c [deleted file]
src/pal/tests/palsuite/c_runtime/fabs/CMakeLists.txt
src/pal/tests/palsuite/c_runtime/fabs/test1/test1.c
src/pal/tests/palsuite/c_runtime/fabs/test1/testinfo.dat
src/pal/tests/palsuite/c_runtime/fabsf/CMakeLists.txt [new file with mode: 0644]
src/pal/tests/palsuite/c_runtime/fabsf/test1/CMakeLists.txt [moved from src/pal/tests/palsuite/c_runtime/exp/test2/CMakeLists.txt with 50% similarity]
src/pal/tests/palsuite/c_runtime/fabsf/test1/test1.c [new file with mode: 0644]
src/pal/tests/palsuite/c_runtime/fabsf/test1/testinfo.dat [moved from src/pal/tests/palsuite/c_runtime/exp/test2/testinfo.dat with 59% similarity]
src/pal/tests/palsuite/c_runtime/floor/CMakeLists.txt
src/pal/tests/palsuite/c_runtime/floor/test1/test1.c
src/pal/tests/palsuite/c_runtime/floor/test1/testinfo.dat
src/pal/tests/palsuite/c_runtime/fmod/CMakeLists.txt
src/pal/tests/palsuite/c_runtime/fmod/test1/test1.c
src/pal/tests/palsuite/c_runtime/fmod/test1/testinfo.dat
src/pal/tests/palsuite/c_runtime/fmodf/CMakeLists.txt [new file with mode: 0644]
src/pal/tests/palsuite/c_runtime/fmodf/test1/CMakeLists.txt [moved from src/pal/tests/palsuite/c_runtime/pow/test2/CMakeLists.txt with 50% similarity]
src/pal/tests/palsuite/c_runtime/fmodf/test1/test1.c [new file with mode: 0644]
src/pal/tests/palsuite/c_runtime/fmodf/test1/testinfo.dat [moved from src/pal/tests/palsuite/c_runtime/pow/test3/testinfo.dat with 55% similarity]
src/pal/tests/palsuite/c_runtime/log/CMakeLists.txt
src/pal/tests/palsuite/c_runtime/log/test1/test1.c
src/pal/tests/palsuite/c_runtime/log/test1/testinfo.dat
src/pal/tests/palsuite/c_runtime/log10/CMakeLists.txt
src/pal/tests/palsuite/c_runtime/log10/test1/test1.c
src/pal/tests/palsuite/c_runtime/modf/test1/test1.c
src/pal/tests/palsuite/c_runtime/modff/CMakeLists.txt [new file with mode: 0644]
src/pal/tests/palsuite/c_runtime/modff/test1/CMakeLists.txt [moved from src/pal/tests/palsuite/c_runtime/exp/test3/CMakeLists.txt with 50% similarity]
src/pal/tests/palsuite/c_runtime/modff/test1/test1.c [new file with mode: 0644]
src/pal/tests/palsuite/c_runtime/modff/test1/testinfo.dat [moved from src/pal/tests/palsuite/c_runtime/exp/test3/testinfo.dat with 55% similarity]
src/pal/tests/palsuite/c_runtime/pow/CMakeLists.txt
src/pal/tests/palsuite/c_runtime/pow/test1/test1.c
src/pal/tests/palsuite/c_runtime/pow/test2/test2.c [deleted file]
src/pal/tests/palsuite/c_runtime/pow/test2/testinfo.dat [deleted file]
src/pal/tests/palsuite/c_runtime/pow/test3/CMakeLists.txt [deleted file]
src/pal/tests/palsuite/c_runtime/pow/test3/test3.c [deleted file]
src/pal/tests/palsuite/c_runtime/sin/CMakeLists.txt
src/pal/tests/palsuite/c_runtime/sin/test1/test1.c
src/pal/tests/palsuite/c_runtime/sin/test1/testinfo.dat
src/pal/tests/palsuite/c_runtime/sinh/CMakeLists.txt
src/pal/tests/palsuite/c_runtime/sinh/test1/test1.c
src/pal/tests/palsuite/c_runtime/sinh/test1/testinfo.dat
src/pal/tests/palsuite/c_runtime/sqrt/test1/test1.c
src/pal/tests/palsuite/c_runtime/tan/CMakeLists.txt
src/pal/tests/palsuite/c_runtime/tan/test1/test1.c
src/pal/tests/palsuite/c_runtime/tan/test1/testinfo.dat
src/pal/tests/palsuite/c_runtime/tanh/CMakeLists.txt
src/pal/tests/palsuite/c_runtime/tanh/test1/test1.c
src/pal/tests/palsuite/c_runtime/tanh/test1/testinfo.dat
src/pal/tests/palsuite/paltestlist.txt
src/pal/tests/palsuite/palverify.dat
src/vm/amd64/JitHelpers_Fast.asm
src/vm/ecalllist.h
src/vm/mscorlib.cpp
tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/AbsDouble.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/AcosDouble.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/AsinDouble.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/Atan2Double.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/AtanDouble.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/CeilingDouble.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/CosDouble.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/CoshDouble.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/ExpDouble.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/FloorDouble.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/Log10Double.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/LogDouble.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/PowDouble.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/RoundDouble.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/SinDouble.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/SinhDouble.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/SqrtDouble.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/TanDouble.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/TanhDouble.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/Math/Functions/Functions.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/Math/Functions/Functions.csproj [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/Math/Functions/MathTests.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/Math/Functions/Single/AbsSingle.cs [new file with mode: 0644]
tests/src/JIT/Performance/RunBenchmarks/benchmarks.xml
tests/src/JIT/Performance/RunBenchmarks/coreclr_benchmarks.xml

index 3350df9..7cb7ded 100644 (file)
@@ -3,7 +3,8 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
 include_directories("../inc")
 
 set(FLOAT_SOURCES
-    floatnative.cpp
+    floatdouble.cpp
+    floatsingle.cpp
 )
 
 if(CLR_CMAKE_PLATFORM_UNIX)
index 091b8a7..ef7f818 100644 (file)
@@ -28,7 +28,8 @@
   </PropertyGroup>
   <!--Leaf Project Items-->
   <ItemGroup>
-    <CppCompile Include="FloatNative.cpp" />
+    <CppCompile Include="floatdouble.cpp" />
+    <CppCompile Include="floatsingle.cpp" />
   </ItemGroup>
   <!--Import the targets-->
   <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.targets" />
diff --git a/src/classlibnative/float/floatdouble.cpp b/src/classlibnative/float/floatdouble.cpp
new file mode 100644 (file)
index 0000000..d9603c0
--- /dev/null
@@ -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
+///
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/classlibnative/float/floatnative.cpp b/src/classlibnative/float/floatnative.cpp
deleted file mode 100644 (file)
index a8a1afc..0000000
+++ /dev/null
@@ -1,490 +0,0 @@
-// 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: FloatNative.cpp
-// 
-
-#include <common.h>
-
-#include "floatnative.h"
-#include "floatclass.h"
-
-#define IS_DBL_INFINITY(x) ((*((UINT64 *)((void *)&x)) & UI64(0x7FFFFFFFFFFFFFFF)) == UI64(0x7FF0000000000000))
-#define IS_DBL_ONE(x)      ((*((UINT64 *)((void *)&x))) == UI64(0x3FF0000000000000))
-#define IS_DBL_NEGATIVEONE(x)      ((*((UINT64 *)((void *)&x))) == UI64(0xBFF0000000000000))
-
-
-// Default compilation mode is /fp:precise, which disables fp intrinsics. This has caused
-// regression in floating point code. I've grouped all the helpers that are really simple
-// (where /fp:fast semantics are really unlikely to cause any regression) and grouped them 
-// here in order to get back to Everett performance numbers
-
-////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////
-///
-///                         Beggining of /fp:fast scope    
-///
-////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////
-
-#ifdef _MSC_VER
-#pragma float_control(precise, off)
-#endif
-
-/*====================================Floor=====================================
-**
-==============================================================================*/
-FCIMPL1_V(double, COMDouble::Floor, double d) 
-    FCALL_CONTRACT;
-
-    return (double) floor(d);
-FCIMPLEND
-
-
-/*====================================Ceil=====================================
-**
-==============================================================================*/
-FCIMPL1_V(double, COMDouble::Ceil, double d) 
-    FCALL_CONTRACT;
-
-    return (double) ceil(d);
-FCIMPLEND
-
-/*=====================================Sqrt=====================================
-**
-==============================================================================*/
-FCIMPL1_V(double, COMDouble::Sqrt, double d) 
-    FCALL_CONTRACT;
-
-    return (double) sqrt(d);
-FCIMPLEND
-
-/*=====================================Acos=====================================
-**
-==============================================================================*/
-FCIMPL1_V(double, COMDouble::Acos, double d) 
-    FCALL_CONTRACT;
-
-    return (double) acos(d);
-FCIMPLEND
-
-
-/*=====================================Asin=====================================
-**
-==============================================================================*/
-FCIMPL1_V(double, COMDouble::Asin, double d) 
-    FCALL_CONTRACT;
-
-    return (double) asin(d);
-FCIMPLEND
-
-
-/*=====================================AbsFlt=====================================
-**
-==============================================================================*/
-FCIMPL1_V(float, COMDouble::AbsFlt, float f) 
-    FCALL_CONTRACT;
-
-    FCUnique(0x14);
-
-    return fabsf(f);
-FCIMPLEND
-
-/*=====================================AbsDbl=====================================
-**
-==============================================================================*/
-FCIMPL1_V(double, COMDouble::AbsDbl, double d) 
-    FCALL_CONTRACT;
-
-    return fabs(d);
-FCIMPLEND
-
-/*=====================================Atan=====================================
-**
-==============================================================================*/
-FCIMPL1_V(double, COMDouble::Atan, double d) 
-    FCALL_CONTRACT;
-
-    return (double) atan(d);
-FCIMPLEND
-
-/*=====================================Atan2=====================================
-**
-==============================================================================*/
-FCIMPL2_VV(double, COMDouble::Atan2, double x, double y) 
-    FCALL_CONTRACT;
-
-        // the intrinsic for Atan2 does not produce Nan for Atan2(+-inf,+-inf)
-    if (IS_DBL_INFINITY(x) && IS_DBL_INFINITY(y)) {
-        return(x / y);      // create a NaN
-    }
-    return (double) atan2(x, y);
-FCIMPLEND
-
-// COMDouble::Sin/Cos/Tan are all implemented in JitHelpers_Fast.asm as x87 floating
-// point for code AMD64 (on Windows) because the CRT helpers is too slow (apparently they don't
-// have a /fp:fast v ersion).
-#if !defined(_TARGET_AMD64_) || defined(FEATURE_PAL)
-
-/*=====================================Sin=====================================
-**
-==============================================================================*/
-FCIMPL1_V(double, COMDouble::Sin, double d) 
-    FCALL_CONTRACT;
-
-    return (double) sin(d);
-FCIMPLEND
-
-/*=====================================Cos=====================================
-**
-==============================================================================*/
-FCIMPL1_V(double, COMDouble::Cos, double d) 
-    FCALL_CONTRACT;
-
-    return (double) cos(d);
-FCIMPLEND
-
-/*=====================================Tan=====================================
-**
-==============================================================================*/
-FCIMPL1_V(double, COMDouble::Tan, double d) 
-    FCALL_CONTRACT;
-
-    return (double) tan(d);
-FCIMPLEND
-
-#endif // !defined(_TARGET_AMD64_) || defined(FEATURE_PAL)
-
-/*=====================================Sinh====================================
-**
-==============================================================================*/
-FCIMPL1_V(double, COMDouble::Sinh, double d) 
-    FCALL_CONTRACT;
-
-    return (double) sinh(d);
-FCIMPLEND
-
-/*=====================================Cosh====================================
-**
-==============================================================================*/
-FCIMPL1_V(double, COMDouble::Cosh, double d) 
-    FCALL_CONTRACT;
-
-    return (double) cosh(d);
-FCIMPLEND
-
-/*=====================================Tanh====================================
-**
-==============================================================================*/
-FCIMPL1_V(double, COMDouble::Tanh, double d) 
-    FCALL_CONTRACT;
-
-    return (double) tanh(d);
-FCIMPLEND
-
-FCIMPL1(double, COMDouble::ModFDouble, double* pdblValue)
-    FCALL_CONTRACT;
-
-    double      dblFrac;
-    dblFrac = modf(*pdblValue, pdblValue);
-    return dblFrac;
-FCIMPLEND
-
-#ifdef _MSC_VER
-#pragma float_control(precise, on )
-#endif
-
-////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////
-///
-///                         End of /fp:fast scope    
-///
-////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////
-//
-// Log, Log10 and Exp are slower with /fp:fast on SSE2 enabled HW (see #500373)
-// So we'll leave them as fp precise for the moment
-
-/*=====================================Log======================================
-**This is the natural log
-==============================================================================*/
-FCIMPL1_V(double, COMDouble::Log, double d) 
-    FCALL_CONTRACT;
-
-    return (double) log(d);
-FCIMPLEND
-
-
-/*====================================Log10=====================================
-**This is log-10
-==============================================================================*/
-FCIMPL1_V(double, COMDouble::Log10, double d) 
-    FCALL_CONTRACT;
-
-    return (double) log10(d);
-FCIMPLEND
-
-
-/*=====================================Exp======================================
-**
-==============================================================================*/
-FCIMPL1_V(double, COMDouble::Exp, double x) 
-    FCALL_CONTRACT;
-
-        // The C intrinsic below does not handle +- infinity properly
-        // so we handle these specially here
-    if (IS_DBL_INFINITY(x)) {
-        if (x < 0)      
-            return(+0.0);
-        return(x);      // Must be + infinity
-    }
-    return((double) exp(x));
-FCIMPLEND
-
-#if defined(_TARGET_X86_)
-/*=====================================Pow======================================
-**This is the power function.  Simple powers are done inline, and special
-  cases are sent to the CRT via the helper. 
-==============================================================================*/
-FCIMPL2_VV(double, COMDouble::PowHelperSimple, double x, double y)
-{
-    FCALL_CONTRACT;
-
-    return (double) pow(x,y);
-}
-FCIMPLEND
-
-FCIMPL2_VV(double, COMDouble::PowHelper, double x, double y) 
-{
-    FCALL_CONTRACT;
-
-    double r1;
-
-    // TODO: we can get rid following code if VC fixes pow function someday.
-    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
-    }
-    if(IS_DBL_INFINITY(y)) {
-        if(IS_DBL_ONE(x)) {
-            return x;        
-        }
-
-        if(IS_DBL_NEGATIVEONE(x)) {
-            *((INT64 *)(&r1)) = CLR_NAN_64;
-            return r1;
-        }    
-    }
-    
-    return (double) pow(x, y);
-}
-FCIMPLEND
-
-#if defined (_DEBUG)
-__declspec(naked) static double F_CALL_CONV PowRetail(double x, double y)
-#else
-__declspec(naked) double F_CALL_CONV COMDouble::Pow(double x, double y)
-#endif
-{
-    WRAPPER_NO_CONTRACT;
-    STATIC_CONTRACT_SO_TOLERANT;
-
-    // Arguments:
-    // exponent: esp+4
-    // base:     esp+12
-    
-    _asm
-    {
-        mov     ecx, [esp+8]           ; high dword of exponent
-        mov     edx, [esp+16]          ; high dword of base
-        
-        and     ecx,  7ff00000H        ; check for special exponent
-        cmp     ecx,  7ff00000H
-        je      callHelper
-
-        and     edx,  7ff00000H        ; check for special base
-        cmp     edx,  7ff00000H
-        je      callHelper
-
-        test    edx,  7ff00000H        ; see if the base has a zero exponent
-        jz      test_if_we_have_zero_base
-
-base_is_not_zero:
-
-        mov     cl,  [esp+19]          ; Handle negative base in the helper
-        and     cl,  80H
-        jnz     callHelper
-
-       jmp     COMDouble::PowHelperSimple      ;
-
-test_if_we_have_zero_base:
-            
-        mov     eax, [esp+16]
-        and     eax, 000fffffH
-        or      eax, [esp+12]
-        jnz     base_is_not_zero
-        ; fall through to the helper
-
-callHelper:
-
-        jmp     COMDouble::PowHelper   ; The helper will return control
-                                       ; directly to our caller.
-    }
-}
-
-#ifdef _DEBUG
-
-#define EPSILON 0.0000000001
-
-void assertDoublesWithinRange(double r1, double r2)
-{
-    WRAPPER_NO_CONTRACT;
-
-    if (_finite(r1) && _finite(r2))
-    {
-        // Both numbers are finite--we need to check that they are close to
-        // each other.  If they are large (> 1), the error could also be large,
-        // which is acceptable, so we compare the error against EPSILON*norm.
-
-        double norm = max(fabs(r1), fabs(r2));
-        double error = fabs(r1-r2);
-        
-        assert((error < (EPSILON * norm)) || (error < EPSILON));
-    }
-    else if (!_isnan(r1) && !_isnan(r2))
-    {
-        // At least one of r1 and r2 is infinite, so when multiplied by
-        // (1 + EPSILON) they should be the same infinity.
-
-        assert((r1 * (1 + EPSILON)) == (r2 * (1 + EPSILON)));
-    }
-    else
-    {
-        // Otherwise at least one of r1 or r2 is a Nan.  Is that case, they better be in
-        // the same class.
-
-        assert(_fpclass(r1) == _fpclass(r2));
-    }
-}
-
-FCIMPL2_VV(double, COMDouble::Pow, double x, double y) 
-{
-    FCALL_CONTRACT;
-
-    double r1, r2;
-
-    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
-    }
-
-    if(IS_DBL_INFINITY(y)) {
-        if(IS_DBL_ONE(x)) {
-            return x;        
-        }
-
-        if(IS_DBL_NEGATIVEONE(x)) {
-            *((INT64 *)(&r1)) = CLR_NAN_64;
-            return r1;
-        }    
-    }  
-
-    // Note that PowRetail expects the argument order to be reversed
-    
-    r1 = (double) PowRetail(y, x);
-    
-    r2 = (double) pow(x, y);
-
-    // Can't do a floating point compare in case r1 and r2 aren't 
-    // valid fp numbers.
-
-    assertDoublesWithinRange(r1, r2);
-
-    return (double) r1; 
-}
-FCIMPLEND
-
-#endif  // _DEBUG
-
-#else   // !defined(_TARGET_X86_)
-FCIMPL2_VV(double, COMDouble::Pow, double x, double y)
-{
-    FCALL_CONTRACT;
-
-    double r1;
-
-    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
-    }
-
-    if(IS_DBL_INFINITY(y)) {
-        if(IS_DBL_ONE(x)) {
-            return x;        
-        }
-
-        if(IS_DBL_NEGATIVEONE(x)) {
-            *((INT64 *)(&r1)) = CLR_NAN_64;
-            return r1;
-        }    
-    }
-    
-    return (double) pow(x, y);
-}
-FCIMPLEND
-
-#endif  // defined(_TARGET_X86_)
-
-
-/*====================================Round=====================================
-**
-==============================================================================*/
-#if defined(_TARGET_X86_)
-__declspec(naked)
-double __fastcall COMDouble::Round(double d)
-{
-    LIMITED_METHOD_CONTRACT;
-
-    __asm {
-        fld QWORD PTR [ESP+4]
-        frndint
-        ret 8
-    }
-}
-
-#else // !defined(_TARGET_X86_)
-FCIMPL1_V(double, COMDouble::Round, double d) 
-    FCALL_CONTRACT;
-
-    double tempVal;
-    double flrTempVal;
-    // If the number has no fractional part do nothing
-    // This shortcut is necessary to workaround precision loss in borderline cases on some platforms
-    if ( d == (double)(__int64)d )
-        return d;
-    tempVal = (d+0.5);
-    //We had a number that was equally close to 2 integers. 
-    //We need to return the even one.
-    flrTempVal = floor(tempVal);
-    if (flrTempVal==tempVal) {
-        if (0 != fmod(tempVal, 2.0)) {
-            flrTempVal -= 1.0;
-        }
-    }
-    flrTempVal = _copysign(flrTempVal, d);
-    return flrTempVal;
-FCIMPLEND
-#endif // defined(_TARGET_X86_)
-
-
diff --git a/src/classlibnative/float/floatnative.h b/src/classlibnative/float/floatnative.h
deleted file mode 100644 (file)
index a2fe17a..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-// 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: FloatNative.h
-// 
-
-#ifndef _FLOATNATIVE_H
-#define _FLOATNATIVE_H
-
-// Removed due to compiler bug
-//
-// _CRTIMP double __cdecl floor(double);
-// _CRTIMP double __cdecl ceil(double);
-
-double __cdecl sqrt(double);
-double __cdecl log(double);
-double __cdecl log10(double);
-double __cdecl exp(double);
-double __cdecl pow(double, double);
-double __cdecl acos(double);
-double __cdecl asin(double);
-double __cdecl atan(double);
-double __cdecl atan2(double,double);
-double __cdecl cos(double);
-double __cdecl sin(double);
-double __cdecl tan(double);
-double __cdecl cosh(double);
-double __cdecl sinh(double);
-double __cdecl tanh(double);
-double __cdecl fmod(double, double);
-
-#endif  // _FLOATNATIVE_H
diff --git a/src/classlibnative/float/floatsingle.cpp b/src/classlibnative/float/floatsingle.cpp
new file mode 100644 (file)
index 0000000..dd1bb43
--- /dev/null
@@ -0,0 +1,54 @@
+// 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: FloatSingle.cpp
+//
+
+#include <common.h>
+
+#include "floatsingle.h"
+
+#define IS_FLT_INFINITY(x)         (((*((INT32*)((void*)&x))) & 0x7FFFFFFF) == 0x7F800000)
+
+// 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.
+
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+///
+///                         beginning of /fp:fast scope
+///
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef _MSC_VER
+#pragma float_control(precise, off)
+#endif
+
+/*=====================================Abs=====================================
+**
+==============================================================================*/
+FCIMPL1(float, COMSingle::Abs, float x)
+    FCALL_CONTRACT;
+
+    return (float)fabsf(x);
+FCIMPLEND
+
+#ifdef _MSC_VER
+#pragma float_control(precise, on )
+#endif
+
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+///
+///                         End of /fp:fast scope
+///
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/classlibnative/inc/floatclass.h b/src/classlibnative/inc/floatclass.h
deleted file mode 100644 (file)
index 831f731..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-// 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.
-
-#ifndef _FLOATCLASS_H_
-#define _FLOATCLASS_H_
-
-#include <object.h>
-#include <fcall.h>
-
-class COMDouble {
-public:
-    FCDECL1_V(static double, Floor, double d);
-    FCDECL1_V(static double, Sqrt, double d);
-    FCDECL1_V(static double, Log, double d);
-    FCDECL1_V(static double, Log10, double d);
-    FCDECL1_V(static double, Exp, double d);
-    FCDECL2_VV(static double, Pow, double x, double y);
-    FCDECL1_V(static double, Acos, double d);
-    FCDECL1_V(static double, Asin, double d);
-    FCDECL1_V(static double, Atan, double d);
-    FCDECL2_VV(static double, Atan2, double x, double y);
-    FCDECL1_V(static double, Cos, double d);
-    FCDECL1_V(static double, Sin, double d);
-    FCDECL1_V(static double, Tan, double d);
-    FCDECL1_V(static double, Cosh, double d);
-    FCDECL1_V(static double, Sinh, double d);
-    FCDECL1_V(static double, Tanh, double d);
-    FCDECL1_V(static double, Round, double d);
-    FCDECL1_V(static double, Ceil, double d);
-    FCDECL1_V(static float, AbsFlt, float f);
-    FCDECL1_V(static double, AbsDbl, double d);
-    FCDECL1(static double, ModFDouble, double* d);
-
-#if defined(_TARGET_X86_)
-//private:
-    FCDECL2_VV(static double, PowHelper, double x, double y);
-    FCDECL2_VV(static double, PowHelperSimple, double x, double y);
-#endif
-
-};
-    
-
-#endif // _FLOATCLASS_H_
diff --git a/src/classlibnative/inc/floatdouble.h b/src/classlibnative/inc/floatdouble.h
new file mode 100644 (file)
index 0000000..16403c1
--- /dev/null
@@ -0,0 +1,35 @@
+// 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.
+
+#ifndef _FLOATDOUBLE_H_
+#define _FLOATDOUBLE_H_
+
+#include <object.h>
+#include <fcall.h>
+
+class COMDouble {
+public:
+    FCDECL1_V(static double, Abs, double x);
+    FCDECL1_V(static double, Acos, double x);
+    FCDECL1_V(static double, Asin, double x);
+    FCDECL1_V(static double, Atan, double x);
+    FCDECL2_VV(static double, Atan2, double y, double x);
+    FCDECL1_V(static double, Ceil, double x);
+    FCDECL1_V(static double, Cos, double x);
+    FCDECL1_V(static double, Cosh, double x);
+    FCDECL1_V(static double, Exp, double x);
+    FCDECL1_V(static double, Floor, double x);
+    FCDECL1_V(static double, Log, double x);
+    FCDECL1_V(static double, Log10, double x);
+    FCDECL1(static double, ModF, double* iptr);
+    FCDECL2_VV(static double, Pow, double x, double y);
+    FCDECL1_V(static double, Round, double x);
+    FCDECL1_V(static double, Sin, double x);
+    FCDECL1_V(static double, Sinh, double x);
+    FCDECL1_V(static double, Sqrt, double x);
+    FCDECL1_V(static double, Tan, double x);
+    FCDECL1_V(static double, Tanh, double x);
+};
+
+#endif // _FLOATDOUBLE_H_
diff --git a/src/classlibnative/inc/floatsingle.h b/src/classlibnative/inc/floatsingle.h
new file mode 100644 (file)
index 0000000..6d123ec
--- /dev/null
@@ -0,0 +1,16 @@
+// 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.
+
+#ifndef _FLOATSINGLE_H_
+#define _FLOATSINGLE_H_
+
+#include <object.h>
+#include <fcall.h>
+
+class COMSingle {
+public:
+    FCDECL1(static float, Abs, float x);
+};
+
+#endif // _FLOATSINGLE_H_
index 37164c9..c8ec69e 100644 (file)
@@ -1700,26 +1700,26 @@ unsigned __int64 FloatingPointUtils::convertDoubleToUInt64(double d) {
 
 // Rounds a double-precision floating-point value to the nearest integer,
 // and rounds midpoint values to the nearest even number.
-// Note this should align with classlib in floatnative.cpp
+// Note this should align with classlib in floatdouble.cpp
 // Specializing for x86 using a x87 instruction is optional since
 // this outcome is identical across targets.
-double FloatingPointUtils::round(double d)
+double FloatingPointUtils::round(double x)
 {
     // If the number has no fractional part do nothing
     // This shortcut is necessary to workaround precision loss in borderline cases on some platforms
-    if (d == (double)(__int64)d)
-        return d;
+    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 = (d + 0.5);
-    //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) {
-        if (fmod(tempVal, 2.0) != 0) {
-            flrTempVal -= 1.0;
-        }
+
+    if ((flrTempVal == tempVal) && (fmod(tempVal, 2.0) != 0)) {
+        flrTempVal -= 1.0;
     }
 
-    flrTempVal = _copysign(flrTempVal, d);
-    return flrTempVal;
+    return _copysign(flrTempVal, x);
 }
index af9f2db..7d77e76 100644 (file)
@@ -575,7 +575,7 @@ public:
 
     static unsigned __int64 convertDoubleToUInt64(double d);
 
-    static double round(double d);
+    static double round(double x);
 };
 
 
index de683fd..baa11a4 100644 (file)
@@ -5781,11 +5781,11 @@ CoCreateGuid(OUT GUID * pguid);
 #define ungetc        PAL_ungetc
 #define setvbuf       PAL_setvbuf
 #define atol          PAL_atol
+#define labs          PAL_labs
 #define acos          PAL_acos
 #define asin          PAL_asin
 #define atan2         PAL_atan2
 #define exp           PAL_exp
-#define labs          PAL_labs
 #define log           PAL_log
 #define log10         PAL_log10
 #define pow           PAL_pow
@@ -6007,40 +6007,39 @@ unsigned int __cdecl _rotr(unsigned int value, int shift)
 }
 
 PALIMPORT int __cdecl abs(int);
-PALIMPORT double __cdecl fabs(double); 
 #ifndef PAL_STDCPP_COMPAT
 PALIMPORT LONG __cdecl labs(LONG);
-PALIMPORT double __cdecl fabs(double);
 #endif // !PAL_STDCPP_COMPAT
 // clang complains if this is declared with __int64
 PALIMPORT long long __cdecl llabs(long long);
 
-PALIMPORT double __cdecl sqrt(double);
-PALIMPORT double __cdecl log(double);
-PALIMPORT double __cdecl log10(double);
-PALIMPORT double __cdecl exp(double);
-PALIMPORT double __cdecl pow(double, double);
+PALIMPORT int __cdecl _finite(double);
+PALIMPORT int __cdecl _isnan(double);
+PALIMPORT double __cdecl _copysign(double, double);
 PALIMPORT double __cdecl acos(double);
 PALIMPORT double __cdecl asin(double);
 PALIMPORT double __cdecl atan(double);
-PALIMPORT double __cdecl atan2(double,double);
+PALIMPORT double __cdecl atan2(double, double);
+PALIMPORT double __cdecl ceil(double);
 PALIMPORT double __cdecl cos(double);
-PALIMPORT double __cdecl sin(double);
-PALIMPORT double __cdecl tan(double);
 PALIMPORT double __cdecl cosh(double);
+PALIMPORT double __cdecl exp(double);
+PALIMPORT double __cdecl fabs(double);
+PALIMPORT double __cdecl floor(double);
+PALIMPORT double __cdecl fmod(double, double); 
+PALIMPORT double __cdecl log(double);
+PALIMPORT double __cdecl log10(double);
+PALIMPORT double __cdecl modf(double, double*);
+PALIMPORT double __cdecl pow(double, double);
+PALIMPORT double __cdecl sin(double);
 PALIMPORT double __cdecl sinh(double);
+PALIMPORT double __cdecl sqrt(double);
+PALIMPORT double __cdecl tan(double);
 PALIMPORT double __cdecl tanh(double);
-PALIMPORT double __cdecl fmod(double, double);
-PALIMPORT float __cdecl fmodf(float, float);
-PALIMPORT double __cdecl floor(double);
-PALIMPORT double __cdecl ceil(double);
-PALIMPORT float __cdecl fabsf(float);
-PALIMPORT double __cdecl modf(double, double *);
-PALIMPORT float __cdecl modff(float, float *);
 
-PALIMPORT int __cdecl _finite(double);
-PALIMPORT int __cdecl _isnan(double);
-PALIMPORT double __cdecl _copysign(double, double);
+PALIMPORT float __cdecl fabsf(float);
+PALIMPORT float __cdecl fmodf(float, float); 
+PALIMPORT float __cdecl modff(float, float*);
 
 #ifndef PAL_STDCPP_COMPAT
 
index 976e609..b61c9cd 100644 (file)
@@ -98,9 +98,9 @@ endif(PAL_CMAKE_PLATFORM_ARCH_ARM)
 set(SOURCES
   cruntime/file.cpp
   cruntime/filecrt.cpp
-  cruntime/finite.cpp
   cruntime/lstr.cpp
   cruntime/malloc.cpp
+  cruntime/math.cpp
   cruntime/mbstring.cpp
   cruntime/misc.cpp
   cruntime/misctls.cpp
similarity index 72%
rename from src/pal/src/cruntime/finite.cpp
rename to src/pal/src/cruntime/math.cpp
index 1777f7d..dd45110 100644 (file)
@@ -8,11 +8,11 @@
 
 Module Name:
 
-    finite.cpp
+    math.cpp
 
 Abstract:
 
-    Implementation of _finite function (Windows specific runtime function).
+    Implementation of math family functions.
 
 
 
@@ -20,20 +20,21 @@ Abstract:
 
 #include "pal/palinternal.h"
 #include "pal/dbgmsg.h"
+
 #include <math.h>
 
 #if HAVE_IEEEFP_H
 #include <ieeefp.h>
 #endif  // HAVE_IEEEFP_H
+
 #include <errno.h>
 
-#define PAL_NAN sqrt(-1.0)
-#define PAL_POSINF -log(0.0)
-#define PAL_NEGINF log(0.0)
+#define PAL_NAN_DBL     sqrt(-1.0)
+#define PAL_POSINF_DBL -log(0.0)
+#define PAL_NEGINF_DBL  log(0.0)
 
 SET_DEFAULT_DEBUG_CHANNEL(CRT);
 
-
 /*++
 Function:
   _finite
@@ -51,41 +52,37 @@ Parameter
 x  Double-precision floating-point value
 
 --*/
-int
-__cdecl
-_finite(
-        double x)
+int __cdecl _finite(double x)
 {
     int ret;
     PERF_ENTRY(_finite);
     ENTRY("_finite (x=%f)\n", x);
+
 #if defined(_IA64_) && defined (_HPUX_)
-    ret = !isnan(x) && x != PAL_POSINF && x != PAL_NEGINF;
+    ret = !isnan(x) && (x != PAL_POSINF_DBL) && (x != PAL_NEGINF_DBL);
 #else
     ret = isfinite(x);
 #endif
+
     LOGEXIT("_finite returns int %d\n", ret);
     PERF_EXIT(_finite);
     return ret;
 }
 
-
 /*++
 Function:
   _isnan
 
 See MSDN doc
 --*/
-int
-__cdecl
-_isnan(
-       double x)
+int __cdecl _isnan(double x)
 {
     int ret;
-
     PERF_ENTRY(_isnan);
     ENTRY("_isnan (x=%f)\n", x);
+
     ret = isnan(x);
+
     LOGEXIT("_isnan returns int %d\n", ret);
     PERF_EXIT(_isnan);
     return ret;
@@ -97,17 +94,14 @@ Function:
 
 See MSDN doc
 --*/
-double 
-__cdecl 
-_copysign(
-          double x,
-          double y)
+double __cdecl _copysign(double x, double y)
 {
     double ret;
-
     PERF_ENTRY(_copysign);
-    ENTRY("_copysign (x=%f,y=%f)\n", x, y);
+    ENTRY("_copysign (x=%f, y=%f)\n", x, y);
+
     ret = copysign(x, y);
+
     LOGEXIT("_copysign returns double %f\n", ret);
     PERF_EXIT(_copysign);
     return ret;
@@ -122,19 +116,22 @@ See MSDN.
 PALIMPORT double __cdecl PAL_acos(double x)
 {
     double ret;
-
     PERF_ENTRY(acos);
     ENTRY("acos (x=%f)\n", x);
+
 #if !HAVE_COMPATIBLE_ACOS
     errno = 0;
 #endif  // HAVE_COMPATIBLE_ACOS
+
     ret = acos(x);
+    
 #if !HAVE_COMPATIBLE_ACOS
     if (errno == EDOM)
     {
-        ret = PAL_NAN;  // NaN
+        ret = PAL_NAN_DBL;  // NaN
     }
 #endif  // HAVE_COMPATIBLE_ACOS
+
     LOGEXIT("acos returns double %f\n", ret);
     PERF_EXIT(acos);
     return ret;
@@ -149,19 +146,22 @@ See MSDN.
 PALIMPORT double __cdecl PAL_asin(double x)
 {
     double ret;
-
     PERF_ENTRY(asin);
     ENTRY("asin (x=%f)\n", x);
+
 #if !HAVE_COMPATIBLE_ASIN
     errno = 0;
 #endif  // HAVE_COMPATIBLE_ASIN
+
     ret = asin(x);
+
 #if !HAVE_COMPATIBLE_ASIN
     if (errno == EDOM)
     {
-        ret = PAL_NAN;  // NaN
+        ret = PAL_NAN_DBL;  // NaN
     }
 #endif  // HAVE_COMPATIBLE_ASIN
+
     LOGEXIT("asin returns double %f\n", ret);
     PERF_EXIT(asin);
     return ret;
@@ -176,35 +176,32 @@ See MSDN.
 PALIMPORT double __cdecl PAL_atan2(double y, double x)
 {
     double ret;
-
     PERF_ENTRY(atan2);
     ENTRY("atan2 (y=%f, x=%f)\n", y, x);
+
 #if !HAVE_COMPATIBLE_ATAN2
     errno = 0;
 #endif  // !HAVE_COMPATIBLE_ATAN2
+
     ret = atan2(y, x);
+
 #if !HAVE_COMPATIBLE_ATAN2
-    if (errno == EDOM)
+    if ((errno == EDOM) && (x == 0.0) && (y == 0.0))
     {
-#if HAVE_COPYSIGN
-        if (x == 0.0 && y == 0.0)
+        const double sign_x = copysign(1.0, x);
+        const double sign_y = copysign(1.0, y);
+
+        if (sign_x > 0)
         {
-            const double sign_x = copysign (1.0, x);
-            const double sign_y = copysign (1.0, y);
-            if (sign_x > 0)
-            {
-                ret = copysign (0.0, sign_y);
-            }
-            else
-            {
-                ret = copysign (atan2 (0.0, -1.0), sign_y);
-            }
+            ret = copysign(0.0, sign_y);
+        }
+        else
+        {
+            ret = copysign(atan2(0.0, -1.0), sign_y);
         }
-#else   // HAVE_COPYSIGN
-#error  Missing copysign or equivalent on this platform!
-#endif  // HAVE_COPYSIGN
     }
 #endif  // !HAVE_COMPATIBLE_ATAN2
+
     LOGEXIT("atan2 returns double %f\n", ret);
     PERF_EXIT(atan2);
     return ret;
@@ -219,9 +216,9 @@ See MSDN.
 PALIMPORT double __cdecl PAL_exp(double x)
 {
     double ret;
-
     PERF_ENTRY(exp);
     ENTRY("exp (x=%f)\n", x);
+
 #if !HAVE_COMPATIBLE_EXP
     if (x == 1.0) 
     {
@@ -229,11 +226,14 @@ PALIMPORT double __cdecl PAL_exp(double x)
     }
     else
     {
-        ret = exp(x);
-    }
-#else // !HAVE_COMPATIBLE_EXP
+#endif  // HAVE_COMPATIBLE_EXP
+
     ret = exp(x);
-#endif // !HAVE_COMPATIBLE_EXP
+    
+#if !HAVE_COMPATIBLE_EXP
+    }
+#endif // HAVE_COMPATIBLE_EXP
+
     LOGEXIT("exp returns double %f\n", ret);
     PERF_EXIT(exp);
     return ret;
@@ -248,7 +248,6 @@ See MSDN.
 PALIMPORT LONG __cdecl PAL_labs(LONG l)
 {
     long lRet;
-
     PERF_ENTRY(labs);
     ENTRY("labs (l=%ld)\n", l);
     
@@ -256,9 +255,7 @@ PALIMPORT LONG __cdecl PAL_labs(LONG l)
 
     LOGEXIT("labs returns long %ld\n", lRet);
     PERF_EXIT(labs);
-      /* This explicit cast to LONG is used to silence any potential warnings
-         due to implicitly casting the native long lRet to LONG when returning. */
-    return (LONG)lRet;
+    return (LONG)lRet; // This explicit cast to LONG is used to silence any potential warnings due to implicitly casting the native long lRet to LONG when returning.
 }
 
 /*++
@@ -270,22 +267,22 @@ See MSDN.
 PALIMPORT double __cdecl PAL_log(double x)
 {
     double ret;
-
     PERF_ENTRY(log);
     ENTRY("log (x=%f)\n", x);
+
 #if !HAVE_COMPATIBLE_LOG
     errno = 0;
 #endif  // !HAVE_COMPATIBLE_LOG
+
     ret = log(x);
+
 #if !HAVE_COMPATIBLE_LOG
-    if (errno == EDOM)
+    if ((errno == EDOM) && (x < 0))
     {
-        if (x < 0)
-        {
-           ret = PAL_NAN;    // NaN
-        }
+        ret = PAL_NAN_DBL;    // NaN
     }
 #endif  // !HAVE_COMPATIBLE_LOG
+
     LOGEXIT("log returns double %f\n", ret);
     PERF_EXIT(log);
     return ret;
@@ -300,22 +297,22 @@ See MSDN.
 PALIMPORT double __cdecl PAL_log10(double x)
 {
     double ret;
-
     PERF_ENTRY(log10);
     ENTRY("log10 (x=%f)\n", x);
+
 #if !HAVE_COMPATIBLE_LOG10
     errno = 0;
 #endif  // !HAVE_COMPATIBLE_LOG10
+
     ret = log10(x);
+    
 #if !HAVE_COMPATIBLE_LOG10
-    if (errno == EDOM)
+    if ((errno == EDOM) && (x < 0))
     {
-        if (x < 0)
-        {
-           ret = PAL_NAN;    // NaN
-        }
+        ret = PAL_NAN_DBL;    // NaN
     }
 #endif  // !HAVE_COMPATIBLE_LOG10
+
     LOGEXIT("log10 returns double %f\n", ret);
     PERF_EXIT(log10);
     return ret;
@@ -330,63 +327,66 @@ See MSDN.
 PALIMPORT double __cdecl PAL_pow(double x, double y)
 {
     double ret;
-
     PERF_ENTRY(pow);
     ENTRY("pow (x=%f, y=%f)\n", x, y);
+
 #if !HAVE_COMPATIBLE_POW
-    if (y == PAL_POSINF && !isnan(x))    // +Inf
+    if (y == PAL_POSINF_DBL && !isnan(x))    // +Inf
     {
-        if (x == 1.0 || x == -1.0)
+        if ((x == 1.0) || (x == -1.0))
         {
-           ret = PAL_NAN;    // NaN
+            ret = PAL_NAN_DBL;    // NaN
         }
-        else if (x > -1.0 && x < 1.0)
+        else if ((x > -1.0) && (x < 1.0))
         {
-           ret = 0.0;
+            ret = 0.0;
         }
         else
         {
-           ret = PAL_POSINF;    // +Inf
+            ret = PAL_POSINF_DBL;    // +Inf
         }
     }
-    else if (y == PAL_NEGINF && !isnan(x))   // -Inf
+    else if ((y == PAL_NEGINF_DBL) && !isnan(x))   // -Inf
     {
-        if (x == 1.0 || x == -1.0)
+        if ((x == 1.0) || (x == -1.0))
         {
-           ret = PAL_NAN;    // NaN
+            ret = PAL_NAN_DBL;    // NaN
         }
-        else if (x > -1.0 && x < 1.0)
+        else if ((x > -1.0) && (x < 1.0))
         {
-           ret = PAL_POSINF;    // +Inf
+            ret = PAL_POSINF_DBL;    // +Inf
         }
         else
         {
-           ret = 0.0;
+            ret = 0.0;
         }
     }
-    else if (x == 0.0 && y < 0.0)
+    else if ((x == 0.0) && (y < 0.0))
     {
-        ret = PAL_POSINF;    // +Inf
+        ret = PAL_POSINF_DBL;    // +Inf
     }
     else
 #endif  // !HAVE_COMPATIBLE_POW
-    if (y == 0.0 && isnan(x))
+
+    if ((y == 0.0) && isnan(x))
     {
         // Windows returns NaN for pow(NaN, 0), but POSIX specifies
         // a return value of 1 for that case.  We need to return
         // the same result as Windows.
-        ret = PAL_NAN;
+        ret = PAL_NAN_DBL;
     }
     else
     {
       ret = pow(x, y);
     }
+    
 #if !HAVE_VALID_NEGATIVE_INF_POW
-    if (ret == PAL_POSINF && x < 0 && finite(x) && ceil(y/2) != floor(y/2))
+    if ((ret == PAL_POSINF_DBL) && (x < 0) && isfinite(x) && (ceil(y / 2) != floor(y / 2)))
     {
-        ret = PAL_NEGINF;   // -Inf
+        ret = PAL_NEGINF_DBL;   // -Inf
     }
 #endif  // !HAVE_VALID_NEGATIVE_INF_POW
+
 #if !HAVE_VALID_POSITIVE_INF_POW
     /*
     * The even/odd test in the if (this one and the one above) used to be ((long long) y % 2 == 0)
@@ -398,11 +398,12 @@ PALIMPORT double __cdecl PAL_pow(double x, double y)
     * 
     * The (ceil(y/2) == floor(y/2)) test is slower, but more robust.
     */
-    if (ret == PAL_NEGINF && x < 0 && finite(x) && ceil(y/2) == floor(y/2))
+    if ((ret == PAL_NEGINF_DBL) && (x < 0) && isfinite(x) && (ceil(y / 2) == floor(y / 2)))
     {
-        ret = PAL_POSINF;   // +Inf
+        ret = PAL_POSINF_DBL;   // +Inf
     }
 #endif  // !HAVE_VALID_POSITIVE_INF_POW
+
     LOGEXIT("pow returns double %f\n", ret);
     PERF_EXIT(pow);
     return ret;
index fdebc8d..7348192 100644 (file)
@@ -205,21 +205,20 @@ function_name() to call the system's implementation
 #define va_list DUMMY_va_list
 #define abs DUMMY_abs
 #define llabs DUMMY_llabs
-#define atan DUMMY_atan
-#define tan DUMMY_tan
+#define ceil DUMMY_ceil
 #define cos DUMMY_cos
-#define sin DUMMY_sin
 #define cosh DUMMY_cosh
-#define sinh DUMMY_sinh
-#define tanh DUMMY_tanh
-#define modf DUMMY_modf
+#define fabs DUMMY_fabs
+#define floor DUMMY_floor
 #define fmod DUMMY_fmod
-#define fmodf DUMMY_fmodf
+#define modf DUMMY_modf
+#define sin DUMMY_sin
+#define sinh DUMMY_sinh
 #define sqrt DUMMY_sqrt
-#define ceil DUMMY_ceil
-#define fabs DUMMY_fabs
+#define tan DUMMY_tan
+#define tanh DUMMY_tanh
 #define fabsf DUMMY_fabsf
-#define floor DUMMY_floor
+#define fmodf DUMMY_fmodf
 #define modff DUMMY_modff
 
 /* RAND_MAX needed to be renamed to avoid duplicate definition when including 
@@ -443,11 +442,27 @@ function_name() to call the system's implementation
 #undef llabs
 #undef acos
 #undef asin
+#undef atan
 #undef atan2
+#undef ceil
+#undef cos
+#undef cosh
 #undef exp
+#undef fabs
+#undef floor
+#undef fmod
 #undef log
 #undef log10
+#undef modf
 #undef pow
+#undef sin
+#undef sinh
+#undef sqrt
+#undef tan
+#undef tanh
+#undef fabsf
+#undef fmodf
+#undef modff
 #undef rand
 #undef srand
 #undef errno
@@ -455,22 +470,6 @@ function_name() to call the system's implementation
 #undef wcsspn
 #undef open
 #undef glob
-#undef atan
-#undef tan
-#undef cos
-#undef sin
-#undef cosh
-#undef sinh
-#undef tanh
-#undef modf
-#undef fmod
-#undef fmodf
-#undef sqrt
-#undef ceil
-#undef fabs
-#undef fabsf
-#undef floor
-#undef modff
 
 #undef wchar_t
 #undef ptrdiff_t
index 5bc2e1e..533454c 100644 (file)
@@ -20,6 +20,7 @@ add_subdirectory(errno)
 add_subdirectory(exit)
 add_subdirectory(exp)
 add_subdirectory(fabs)
+add_subdirectory(fabsf)
 add_subdirectory(fclose)
 add_subdirectory(feof)
 add_subdirectory(ferror)
@@ -27,6 +28,7 @@ add_subdirectory(fflush)
 add_subdirectory(fgets)
 add_subdirectory(floor)
 add_subdirectory(fmod)
+add_subdirectory(fmodf)
 add_subdirectory(fopen)
 add_subdirectory(fprintf)
 add_subdirectory(fputs)
@@ -62,6 +64,7 @@ add_subdirectory(memcpy)
 add_subdirectory(memmove)
 add_subdirectory(memset)
 add_subdirectory(modf)
+add_subdirectory(modff)
 add_subdirectory(pow)
 add_subdirectory(printf)
 add_subdirectory(qsort)
@@ -157,4 +160,3 @@ add_subdirectory(_wmakepath)
 add_subdirectory(_wsplitpath)
 add_subdirectory(_wtoi)
 add_subdirectory(__iscsym)
-
index d832a91..c815055 100644 (file)
 **          of floating point numbers (NaN, -Infinity, Infinity,
 **          finite nonzero, unnormalized, 0, and -0)
 **
-**
 **==========================================================================*/
 
-
 #include <palsuite.h>
 
 /*
@@ -37,86 +35,85 @@ If E=0 and F is zero and S is 0, then V=0
 
 */
 
+#define TO_DOUBLE(x)    (*((double*)((void*)&x)))
+
 int __cdecl main(int argc, char **argv)
 {
     /*non-finite numbers*/
-    __int64 lnan =              0x7fffffffffffffff;
-    __int64 lnan2 =             0xffffffffffffffff;
-    __int64 lneginf =           0xfff0000000000000;
-    __int64 linf =              0x7ff0000000000000;
+    UINT64 lsnan =              UI64(0xffffffffffffffff);
+    UINT64 lqnan =              UI64(0x7fffffffffffffff);
+    UINT64 lneginf =            UI64(0xfff0000000000000);
+    UINT64 lposinf =            UI64(0x7ff0000000000000);
+
+    double snan =               TO_DOUBLE(lsnan);
+    double qnan =               TO_DOUBLE(lqnan);
+    double neginf =             TO_DOUBLE(lneginf);
+    double posinf =             TO_DOUBLE(lposinf);
 
     /*finite numbers*/
-    __int64 lUnnormalized =     0x000fffffffffffff;
-    __int64 lNegUnnormalized =  0x800fffffffffffff;
-    __int64 lNegZero =          0x8000000000000000;
-
-    double nan = *(double *)&lnan;
-    double nan2 = *(double *)&lnan2;
-    double neginf = *(double *)&lneginf;
-    double inf = *(double *)&linf;
-    double unnormalized = *(double *)&lUnnormalized;
-    double negUnnormalized = *(double *)&lNegUnnormalized;
-    double negZero = *(double *)&lNegZero;
-    double pos = 123.456;
-    double neg = -123.456;
+    UINT64 lnegunnormalized =   UI64(0x800fffffffffffff);
+    UINT64 lposunnormalized =   UI64(0x000fffffffffffff);
+    UINT64 lnegzero =           UI64(0x8000000000000000);
+
+    double negunnormalized =    TO_DOUBLE(lnegunnormalized);
+    double posunnormalized =    TO_DOUBLE(lposunnormalized);
+    double negzero =            TO_DOUBLE(lnegzero);
 
     /*
      * Initialize the PAL and return FAIL if this fails
      */
-    if (0 != (PAL_Initialize(argc, argv)))
+    if (PAL_Initialize(argc, argv) != 0)
     {
         return FAIL;
     }
 
     /*non-finite numbers*/
-    if (_finite(nan) || _finite(nan2))
+    if (_finite(snan) || _finite(qnan))
     {
-        Fail ("_finite() found NAN to be finite.\n");
+        Fail("_finite() found NAN to be finite.\n");
     }
+
     if (_finite(neginf))
     {
-        Fail ("_finite() found negative infinity to be finite.\n");
+        Fail("_finite() found negative infinity to be finite.\n");
     }
-    if (_finite(inf))
+
+    if (_finite(posinf))
     {
-        Fail ("_finite() found infinity to be finite.\n");
+        Fail("_finite() found infinity to be finite.\n");
     }
 
-
     /*finite numbers*/
-    if (!_finite(unnormalized))
+    if (!_finite(negunnormalized))
     {
-        Fail ("_finite() found an unnormalized value to be infinite.\n");
+        Fail("_finite() found a negative unnormalized value to be infinite.\n");
     }
-    if (!_finite(negUnnormalized))
+
+    if (!_finite(posunnormalized))
     {
-        Fail ("_finite() found a negative unnormalized value to be infinite.\n");
+        Fail("_finite() found an unnormalized value to be infinite.\n");
     }
-    if (!_finite((double)0))
+
+    if (!_finite(negzero))
     {
-        Fail ("_finite found zero to be infinite.\n");
+        Fail("_finite() found negative zero to be infinite.\n");
     }
-    if (!_finite(negZero))
+
+    if (!_finite(+0.0))
     {
-        Fail ("_finite() found negative zero to be infinite.\n");
+        Fail("_finite() found zero to be infinite.\n");
     }
-    if (!_finite(pos))
+
+    if (!_finite(-123.456))
     {
-        Fail ("_finite() found %f to be infinite.\n", pos);
+        Fail("_finite() found %f to be infinite.\n", -123.456);
     }
-    if (!_finite(neg))
+
+    if (!_finite(+123.456))
     {
-        Fail ("_finite() found %f to be infinite.\n", neg);
+        Fail("_finite() found %f to be infinite.\n", +123.456);
     }
+
     PAL_Terminate();
     return PASS;
 }
-
-
-
-
-
-
-
-
-
index cb2c6c3..cec0f8a 100644 (file)
@@ -9,6 +9,5 @@ Name = Positive Test for _finite
 TYPE = DEFAULT
 EXE1 = test1
 Description
-=Checks that _finite correctly classifies all types of floating 
-=point numbers
-=(NaN, -Infinity, Infinity, finite nonzero, unnormalized, 0, and -0).
+= Checks that _finite correctly classifies all types of floating point
+= numbers (NaN, -Infinity, Infinity, finite nonzero, unnormalized, 0, and -0).
index 08664d7..d793c9b 100644 (file)
 ** the fraction to positive and negative, at which point it should return
 ** the true value. 
 **
-**
 **==========================================================================*/
 
 #include <palsuite.h>
 
-#define TO_DOUBLE(a) (*(double*)&a)
-#define TO_I64(a) (*(INT64*) &a)
+#define TO_DOUBLE(x)    (*((double*)((void*)&x)))
+#define TO_I64(x)       (*((INT64*)((void*)&x)))
 
 /*
  * NaN: any double with maximum exponent (0x7ff) and non-zero fraction
  */
 int __cdecl main(int argc, char *argv[])
 {
-    UINT64 PosInf=0;
-    UINT64 NegInf=0;
-    UINT64 val=0;
-
     /*
      * Initialize the PAL and return FAIL if this fails
      */
-    if (0 != (PAL_Initialize(argc, argv)))
+    if (PAL_Initialize(argc, argv) != 0)
     {
         return FAIL;
     }
+
     /*
      * Try some trivial values
      */
-    if (_isnan(0))
+    if (_isnan(0.0))
     {
-        Fail ("_isnan() incorrectly identified %f as NaN!\n", 0);
+        Fail("_isnan() incorrectly identified %f as NaN!\n", 0.0);
     }
-    if (_isnan(1.2423456))
+
+    if (_isnan(1.23456))
     {
-        Fail ("_isnan() incorrectly identified %f as NaN!\n", 0);
+        Fail("_isnan() incorrectly identified %f as NaN!\n", 1.234567);
     }
-    if (_isnan(42))
+
+    if (_isnan(42.0))
     {
-        Fail ("_isnan() incorrectly identified %f as NaN!\n", 0);
+        Fail("_isnan() incorrectly identified %f as NaN!\n", 42.0);
     }
 
-
-    PosInf = 0x7ff00000;
-    PosInf <<=32;
-
-    NegInf = 0xfff00000;
-    NegInf <<=32;
+    UINT64 lneginf =            UI64(0xfff0000000000000);
+    UINT64 lposinf =            UI64(0x7ff0000000000000);
+    
+    double neginf =             TO_DOUBLE(lneginf);
+    double posinf =             TO_DOUBLE(lposinf);
 
     /*
      * Try positive and negative infinity
      */
-    if (_isnan(TO_DOUBLE(PosInf)))
+    if (_isnan(neginf))
     {
-        Fail ("_isnan() incorrectly identified %I64x as NaN!\n", PosInf);
+        Fail("_isnan() incorrectly identified negative infinity as NaN!\n");
     }
 
-    if (_isnan(TO_DOUBLE(NegInf)))
+    if (_isnan(posinf))
     {
-        Fail ("_isnan() incorrectly identified %I64x as NaN!\n", NegInf);
+        Fail("_isnan() incorrectly identified infinity as NaN!\n");
     }
 
     /*
      * Try setting the least significant bit of the fraction,
      * positive and negative
      */
-    val = PosInf + 1;
-    if (!_isnan(TO_DOUBLE(val)))
+    UINT64 lsnan =              UI64(0xfff0000000000001);
+    double snan =               TO_DOUBLE(lsnan);
+    
+    if (!_isnan(snan))
     {
-        Fail ("_isnan() failed to identify %I64x as NaN!\n", val);
+        Fail("_isnan() failed to identify %I64x as NaN!\n", lsnan);
     }
 
-    val = NegInf + 1;
-    if (!_isnan(TO_DOUBLE(val)))
+    UINT64 lqnan =              UI64(0x7ff0000000000001);
+    double qnan =               TO_DOUBLE(lqnan);
+    
+    if (!_isnan(qnan))
     {
-        Fail ("_isnan() failed to identify %I64x as NaN!\n", val);
+        Fail("_isnan() failed to identify %I64x as NaN!\n", lqnan);
     }
 
-
     /*
      * Try setting the most significant bit of the fraction,
      * positive and negative
      */
-    val = 0x7ff80000;
-    val <<=32;
-    if (!_isnan(TO_DOUBLE(val)))
+    lsnan =                     UI64(0xfff8000000000000);
+    snan =                      TO_DOUBLE(lsnan);
+
+    if (!_isnan(snan))
     {
-        Fail ("_isnan() failed to identify %I64x as NaN!\n", val);
+        Fail ("_isnan() failed to identify %I64x as NaN!\n", lsnan);
     }
 
-    val = 0xfff80000;
-    val <<=32;
-    if (!_isnan(TO_DOUBLE(val)))
+    lqnan =                     UI64(0x7ff8000000000000);
+    qnan =                      TO_DOUBLE(lqnan);
+
+    if (!_isnan(qnan))
     {
-        Fail ("_isnan() failed to identify %I64x as NaN!\n", val);
+        Fail ("_isnan() failed to identify %I64x as NaN!\n", lqnan);
     }
 
     PAL_Terminate();
-
     return PASS;
 }
-
index 6c38859..c6ed069 100644 (file)
 **
 ** Source: test1.c
 **
-** Purpose: Test to ensure that acos returns correct values.
+** Purpose: Test to ensure that acos return the correct values
 ** 
 ** Dependencies: PAL_Initialize
 **               PAL_Terminate
-**                              Fail
+**               Fail
 **               fabs
-**               _finite
-** 
-
 **
 **===========================================================================*/
 
 #include <palsuite.h>
 
-/* Error acceptance level to the 7th decimal */
-#define DELTA 0.0000001 
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this 
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN     sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF  log(0.0)
 
 /**
  * Helper test structure
  */
 struct test
 {
-    double value;   /* value to test the function with */
-    double result;  /* expected result */
+    double value;     /* value to test the function with */
+    double expected;  /* expected result */
+    double variance;  /* maximum delta between the expected and actual result */
 };
 
 /**
- * main
- * 
- * executable entry point
+ * validate
+ *
+ * test validation function
  */
-INT __cdecl main(INT argc, CHAR **argv)
+void __cdecl validate(double value, double expected, double variance)
 {
-    double pi = 3.1415926535;
-    int i;
+    double result = acos(value);
 
-    struct test tests[] = 
-    {
-        /* Value        test result */
-        { 1,                0 },
-        { 0.9,              0.451026811796 },
-        { 0.8,              0.643501108793 },
-        { 0.7,              0.795398830184 },
-        { 0.6,              0.927295218002 },
-        { 0.5,              1.047197551197 },
-        { 0.4,              1.159279480727 },
-        { 0.3,              1.266103672779 },
-        { 0.2,              1.369438406005 },
-        { 0.1,              1.470628905633 },
-        { 0,                pi/2.0 },
-        { -0.1,             1.670963747956 },
-        { -0.2,             1.772154247585 },
-        { -0.3,             1.875488980810 },
-        { -0.4,             1.982313172862 },
-        { -0.5,             2.094395102393 },
-        { -0.6,             2.214297435588 },
-        { -0.7,             2.346193823406 },
-        { -0.8,             2.498091544797 },
-        { -0.9,             2.690565841794 },
-        { -1,              pi }
-    };
+    /*
+     * The test is valid when the difference between result
+     * and expected is less than or equal to variance
+     */
+    double delta = fabs(result - expected);
 
-    double outofrange[] =
+    if (delta > variance)
     {
-        -864278.51, -1000.2, -2, 2, 10, 100, 1234567.8, 1.7e308
-    };
+        Fail("acos(%g) returned %20.17g when it should have returned %20.17g",
+             value, result, expected);
+    }
+}
 
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+    double result = acos(value);
 
-    /* PAL initialization */
-    if( PAL_Initialize(argc, argv) != 0 )
+    if (!_isnan(result))
     {
-           return (FAIL);
+        Fail("acos(%g) returned %20.17g when it should have returned %20.17g",
+             value, result, PAL_NAN);
     }
+}
 
-    for( i = 0; i < sizeof(tests) / sizeof(struct test); i++)
+/**
+ * main
+ * 
+ * executable entry point
+ */
+int __cdecl main(int argc, char **argv)
+{
+    struct test tests[] = 
     {
-        double result;
-        double testDelta;
-
-        result = acos( tests[i].value );
+        /* value                   expected                variance */
+        { -1,                      3.1415926535897932,     PAL_EPSILON * 10 },      // expected:  pi
+        { -0.91173391478696510,    2.7182818284590452,     PAL_EPSILON * 10 },      // expected:  e
+        { -0.66820151019031295,    2.3025850929940457,     PAL_EPSILON * 10 },      // expected:  ln(10)
+        {  0,                      1.5707963267948966,     PAL_EPSILON * 10 },      // expected:  pi / 2
+        {  0.12775121753523991,    1.4426950408889634,     PAL_EPSILON * 10 },      // expected:  log2(e)
+        {  0.15594369476537447,    1.4142135623730950,     PAL_EPSILON * 10 },      // expected:  sqrt(2)
+        {  0.42812514788535792,    1.1283791670955126,     PAL_EPSILON * 10 },      // expected:  2 / sqrt(pi)
+        {  0.54030230586813972,    1,                      PAL_EPSILON * 10 },
+        {  0.70710678118654752,    0.78539816339744831,    PAL_EPSILON },           // expected:  pi / 4,         value:  1 / sqrt(2)
+        {  0.76024459707563015,    0.70710678118654752,    PAL_EPSILON },           // expected:  1 / sqrt(2)
+        {  0.76923890136397213,    0.69314718055994531,    PAL_EPSILON },           // expected:  ln(2)
+        {  0.80410982822879171,    0.63661977236758134,    PAL_EPSILON },           // expected:  2 / pi
+        {  0.90716712923909839,    0.43429448190325183,    PAL_EPSILON },           // expected:  log10(e)
+        {  0.94976571538163866,    0.31830988618379067,    PAL_EPSILON },           // expected:  1 / pi
+        {  1,                      0,                      PAL_EPSILON },
+    };
 
-        /*
-         * The test is valid when the difference between the
-         * result and the expectation is less than DELTA
-         */
-        testDelta = fabs( result - tests[i].result );
-        if( testDelta >= DELTA )
-        {
-            Fail( "acos(%g) returned %20.10f"
-                  " when it should have returned %20.10f",
-                  tests[i].value,
-                  result, 
-                  tests[i].result );
-        }
+    /* PAL initialization */
+    if (PAL_Initialize(argc, argv) != 0)
+    {
+        return FAIL;
     }
 
-    for( i = 0; i < sizeof(outofrange) / sizeof(double); i++)
+    for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
     {
-        double result;
-
-        result = acos( outofrange[i] );
-
-        /* The test is valid when the function returns an infinite result */
-        if( _finite( result ) )
-        {
-            Fail( "acos(%g) returned %20.10f"
-                  " when it should have returned -1.#IND00000000",
-                  outofrange[i],
-                  result );
-        }
+        validate(tests[i].value, tests[i].expected, tests[i].variance);
     }
+    
+    validate_isnan(PAL_NEGINF);
+    validate_isnan(PAL_NAN);
+    validate_isnan(PAL_POSINF);
 
     PAL_Terminate();
     return PASS;
index cfa70e7..4b43982 100644 (file)
@@ -12,6 +12,3 @@ Description
 = Passes a series of values to the acos() function,
 = checking each for the expected result. Also checks
 = for proper handling of out-of-range values.
-
-
-
index b772cc7..0a63356 100644 (file)
 **
 ** Source: test1.c
 **
-** Purpose: Test to ensure that asin returns correct values.
+** Purpose: Test to ensure that asin return the correct values
 ** 
 ** Dependencies: PAL_Initialize
 **               PAL_Terminate
-**                              Fail
+**               Fail
 **               fabs
-**               _finite
-** 
-
 **
 **===========================================================================*/
 
 #include <palsuite.h>
 
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this 
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
 
-#define DELTA 0.0000001 /* Error acceptance level to the 7th decimal */
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN     sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF  log(0.0)
 
 /**
  * Helper test structure
  */
 struct test
 {
-    double value;   /* value to test the function with */
-    double result;  /* expected result */
+    double value;     /* value to test the function with */
+    double expected;  /* expected result */
+    double variance;  /* maximum delta between the expected and actual result */
 };
 
 /**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+    double result = asin(value);
+
+    /*
+     * The test is valid when the difference between result
+     * and expected is less than or equal to variance
+     */
+    double delta = fabs(result - expected);
+
+    if (delta > variance)
+    {
+        Fail("asin(%g) returned %20.17g when it should have returned %20.17g",
+             value, result, expected);
+    }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+    double result = asin(value);
+
+    if (!_isnan(result))
+    {
+        Fail("asin(%g) returned %20.17g when it should have returned %20.17g",
+             value, result, PAL_NAN);
+    }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning +INF
+ */
+void __cdecl validate_isinf_positive(double value)
+{
+    double result = asin(value);
+
+    if (result != PAL_POSINF)
+    {
+        Fail("asin(%g) returned %20.17g when it should have returned %20.17g",
+             value, result, PAL_POSINF);
+    }
+}
+
+/**
  * main
  * 
  * executable entry point
  */
-INT __cdecl main(INT argc, CHAR **argv)
+int __cdecl main(int argc, char **argv)
 {
-    double pi = 3.1415926535;
-    int i;
-
     struct test tests[] = 
     {
-        /* Value        test result */
-        { 1,                pi/2.0 },
-        { 0.9,              1.119769514999 },
-        { 0.8,              0.927295218002 },
-        { 0.7,              0.775397496611 },
-        { 0.6,              0.643501108793 },
-        { 0.5,              0.523598775598 },
-        { 0.4,              0.411516846067 },
-        { 0.3,              0.304692654015 },
-        { 0.2,              0.201357920790 },
-        { 0.1,              0.100167421162 },
-        { 0,                0 },
-        { -0.1,             -0.100167421162 },
-        { -0.2,             -0.201357920790 },
-        { -0.3,             -0.304692654015 },
-        { -0.4,             -0.411516846067 },
-        { -0.5,             -0.523598775598 },
-        { -0.6,             -0.643501108793 },
-        { -0.7,             -0.775397496611 },
-        { -0.8,             -0.927295218002 },
-        { -0.9,             -1.119769514999 },
-        { -1,              -(pi/2.0) }
-    };
-    
-    double outofrange[] =
-    {
-        -864278.51, -1000.2, -2, 2, 10, 100, 1234567.8, 1.7e308
+        /* value                   expected                variance */
+        {  0,                      0,                      PAL_EPSILON },
+        {  0.31296179620778659,    0.31830988618379067,    PAL_EPSILON },           // expected:  1 / pi
+        {  0.41078129050290870,    0.42331082513074800,    PAL_EPSILON },           // expected:  pi - e
+        {  0.42077048331375735,    0.43429448190325183,    PAL_EPSILON },           // expected:  log10(e)
+        {  0.59448076852482208,    0.63661977236758134,    PAL_EPSILON },           // expected:  2 / pi
+        {  0.63896127631363480,    0.69314718055994531,    PAL_EPSILON },           // expected:  ln(2)
+        {  0.64963693908006244,    0.70710678118654752,    PAL_EPSILON },           // expected:  1 / sqrt(2)
+        {  0.70710678118654752,    0.78539816339744831,    PAL_EPSILON },           // expected:  pi / 4,         value: 1 / sqrt(2)
+        {  0.74398033695749319,    0.83900756059574755,    PAL_EPSILON },           // expected:  pi - ln(10)
+        {  0.84147098480789651,    1,                      PAL_EPSILON * 10 },
+        {  0.90371945743584630,    1.1283791670955126,     PAL_EPSILON * 10 },      // expected:  2 / sqrt(pi)
+        {  0.98776594599273553,    1.4142135623730950,     PAL_EPSILON * 10 },      // expected:  sqrt(2)
+        {  0.99180624439366372,    1.4426950408889634,     PAL_EPSILON * 10 },      // expected:  log2(e)
+        {  1,                      1.5707963267948966,     PAL_EPSILON * 10 },      // expected:  pi / 2
     };
-    
 
     /* PAL initialization */
-    if( PAL_Initialize(argc, argv) != 0 )
-    {
-           return (FAIL);
-    }
-
-    for( i = 0; i < sizeof(tests) / sizeof(struct test); i++)
+    if (PAL_Initialize(argc, argv) != 0)
     {
-        double result;
-        double testDelta;
-
-        result = asin( tests[i].value );
-
-        /*
-         * The test is valid when the difference between the
-         * result and the expectation is less than DELTA
-         */
-        testDelta = fabs( result - tests[i].result );
-        if( testDelta >= DELTA )
-        {
-            Fail( "asin(%g) returned %20.10f"
-                  " when it should have returned %20.10f",
-                  tests[i].value,
-                  result, 
-                  tests[i].result );
-        }
+        return FAIL;
     }
 
-    for( i = 0; i < sizeof(outofrange) / sizeof(double); i++)
+    for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
     {
-        double result;
-
-        result = asin( outofrange[i] );
-
-        /* The test is valid when the function returns an infinite result */
-        if( _finite( result ) )
-        {
-            Fail( "asin(%g) returned %20.10f"
-                  " when it should have returned -1.#IND00000000",
-                  outofrange[i],
-                  result );
-        }
+        validate( tests[i].value,  tests[i].expected, tests[i].variance);
+        validate(-tests[i].value, -tests[i].expected, tests[i].variance);
     }
     
+    validate_isnan(PAL_NEGINF);
+    validate_isnan(PAL_NAN);
+    validate_isnan(PAL_POSINF);
+
     PAL_Terminate();
     return PASS;
 }
-
-
-
-
-
-
-
-
-
-
-
-
-
index da3e0c2..fba9f95 100644 (file)
@@ -12,6 +12,3 @@ Description
 = Passes a series of values to the asin() function,
 = checking each for the expected result. Also checks
 = for proper handling of out-of-range values.
-
-
-
index 1f7d89c..6840d46 100644 (file)
 **
 ** Source: test1.c
 **
-** Purpose: Test to ensure that atan returns correct values.
+** Purpose: Test to ensure that atan return the correct values
 ** 
 ** Dependencies: PAL_Initialize
 **               PAL_Terminate
-**                              Fail
+**               Fail
 **               fabs
-** 
-
 **
 **===========================================================================*/
 
 #include <palsuite.h>
 
-#define DELTA 0.0000001 /* Error acceptance level to the 7th decimal */
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this 
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN     sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF  log(0.0)
 
 /**
  * Helper test structure
  */
 struct test
 {
-    double value;   /* value to test the function with */
-    double result;  /* expected result */
+    double value;     /* value to test the function with */
+    double expected;  /* expected result */
+    double variance;  /* maximum delta between the expected and actual result */
 };
 
 /**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+    double result = atan(value);
+
+    /*
+     * The test is valid when the difference between result
+     * and expected is less than or equal to variance
+     */
+    double delta = fabs(result - expected);
+
+    if (delta > variance)
+    {
+        Fail("atan(%g) returned %20.17g when it should have returned %20.17g",
+             value, result, expected);
+    }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+    double result = atan(value);
+
+    if (!_isnan(result))
+    {
+        Fail("atan(%g) returned %20.17g when it should have returned %20.17g",
+             value, result, PAL_NAN);
+    }
+}
+
+/**
  * main
  * 
  * executable entry point
  */
-INT __cdecl main(INT argc, CHAR **argv)
+int __cdecl main(int argc, char **argv)
 {
-    double pi = 3.1415926535;
-    int i;
-
     struct test tests[] = 
     {
-        /* Value                       test result */
-        { -1.7976931348623158e+307,         -(pi/2) },
-        { -25928.789941099276,     -1.570757759627 },
-        { -10162.054261909849,     -1.570697921495 },
-        { -7742.279976805932,      -1.570667165876 },
-        { -4027.241187780389,      -1.570548017858 },
-        { -2020.329477828303,      -1.570301358064 },
-        { -928.811975463118,       -1.569719683039 },
-        { -0.993835261086,         -0.782306273415 },
-        { -0.936490981780,         -0.752613986257 },
-        { -0.884395886105,         -0.724126849580 },
-        { -0.728537858211,         -0.629623252584 },
-        { -0.571733756523,         -0.519376146611 },
-        { -0.370342112491,         -0.354680802574 },
-        { -0.264778588214,         -0.258838835750 },
-        { -0.199255348369,         -0.196679446239 },
-        { -0.077700125126,         -0.077544322548 },
-        { -0.036713766900,         -0.036697284724 },
-        { 0,                        0},
-        { 0.284035767693,           0.276747134475 },
-        { 0.329264198737,           0.318083873607 },
-        { 0.332560197760,           0.321054571066 },
-        { 0.338206122013,           0.326129634676 },
-        { 0.421887874996,           0.399231699263 },
-        { 0.645222327342,           0.573009239835 },
-        { 0.648396252327,           0.575246979388 },
-        { 0.721427045503,           0.624962252188 },
-        { 0.723685415204,           0.626445984185 },
-        { 0.747856074709,           0.642127583998 },
-        { 401.853083895383,         1.568307860298 },
-        { 1579.672322763756,        1.570163284200 },
-        { 2540.318308053835,        1.570402675359 },
-        { 6105.661946470535,        1.570632544391 },
-        { 10221.297708059939,       1.570698491860 },
-        { 17155.000305185094,       1.570738034753 },
-        { 20600.197424237798,       1.570747783571 },
-        { 1.7976931348623158e+308,            pi/2 }
+        /* value                   expected                variance */
+        {  0,                      0,                      PAL_EPSILON },
+        {  0.32951473309607836,    0.31830988618379067,    PAL_EPSILON },           // expected:  1 / pi
+        {  0.45054953406980750,    0.42331082513074800,    PAL_EPSILON },           // expected:  pi - e
+        {  0.46382906716062964,    0.43429448190325183,    PAL_EPSILON },           // expected:  log10(e)
+        {  0.73930295048660405,    0.63661977236758134,    PAL_EPSILON },           // expected:  2 / pi
+        {  0.83064087786078395,    0.69314718055994531,    PAL_EPSILON },           // expected:  ln(2)
+        {  0.85451043200960189,    0.70710678118654752,    PAL_EPSILON },           // expected:  1 / sqrt(2)
+        {  1,                      0.78539816339744831,    PAL_EPSILON },           // expected:  pi / 4
+        {  1.1134071468135374,     0.83900756059574755,    PAL_EPSILON },           // expected:  pi - ln(10)
+        {  1.5574077246549022,     1,                      PAL_EPSILON * 10 },
+        {  2.1108768356626451,     1.1283791670955126,     PAL_EPSILON * 10 },      // expected:  2 / sqrt(pi)
+        {  6.3341191670421916,     1.4142135623730950,     PAL_EPSILON * 10 },      // expected:  sqrt(2)
+        {  7.7635756709721848,     1.4426950408889634,     PAL_EPSILON * 10 },      // expected:  log2(e)
+        {  PAL_POSINF,             1.5707963267948966,     PAL_EPSILON * 10 },      // expected:  pi / 2
     };
 
-
     /* PAL initialization */
-    if( PAL_Initialize(argc, argv) != 0 )
+    if (PAL_Initialize(argc, argv) != 0)
     {
-           return (FAIL);
+        return FAIL;
     }
 
-    for( i = 0; i < sizeof(tests) / sizeof(struct test); i++)
+    for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
     {
-        double result;
-        double testDelta;
-
-        result = atan( tests[i].value );
-
-        /*
-         * The test is valid when the difference between the
-         * result and the expectation is less than DELTA
-         */
-        testDelta = fabs( result - tests[i].result );
-        if( testDelta >= DELTA )
-        {
-            Fail( "atan(%g) returned %20.10f"
-                  " when it should have returned %20.10f",
-                  tests[i].value,
-                  result, 
-                  tests[i].result );
-        }
+        validate( tests[i].value,  tests[i].expected, tests[i].variance);
+        validate(-tests[i].value, -tests[i].expected, tests[i].variance);
     }
 
+    validate_isnan(PAL_NAN);
+
     PAL_Terminate();
     return PASS;
 }
index 8f18fd5..8a181b8 100644 (file)
@@ -11,6 +11,3 @@ EXE1 = test1
 Description
 = Passes a series of values to the atan() function,
 = checking each for the expected result.
-
-
-
index d28bbb9..15aa8f5 100644 (file)
 **          Tests with positive and negative values of x and y to ensure
 **          atan2 is returning results from the correct quadrant.
 **
-**
 **===================================================================*/
 
 #include <palsuite.h>
 
-#define DELTA 0.0000001 //Error acceptance level to the 7th decimal
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this 
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
 
+#define PAL_NAN     sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF  log(0.0)
 
 struct test
 {
-    double x;
-    double y;
-    double result;  // expected result
+    double y;         /* second component of the value to test the function with */
+    double x;         /* first component of the value to test the function with */
+    double expected;  /* expected result */
+    double variance;  /* maximum delta between the expected and actual result */
 };
 
-
-void DoTest(double x, double y, double expected)
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double y, double x, double expected, double variance)
 {
-    double result;
-    double testDelta;
+    double result = atan2(y, x);
 
-    result = atan2(x, y);
+    /*
+     * The test is valid when the difference between result
+     * and expected is less than or equal to variance
+     */
+    double delta = fabs(result - expected);
 
-    // The test is valid when the difference between the
-    // result and the expectation is less than DELTA
-    testDelta = fabs(result - expected);
-    if( testDelta >= DELTA )
+    if (delta > variance)
     {
-        Fail( "atan2(%g, %g) returned %g when it should have returned %g",
-                x, y, result, expected);
+        Fail("atan2(%g, %g) returned %20.17g when it should have returned %20.17g",
+             y, x, result, expected);
     }
 }
 
-int __cdecl main(int argc, char **argv)
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double y, double x)
 {
-    double pi = 3.1415926535;
-    int i;
+    double result = atan2(y, x);
 
+    if (!_isnan(result))
+    {
+        Fail("atan2(%g, %g) returned %20.17g when it should have returned %20.17g",
+             y, x, result, PAL_NAN);
+    }
+}
+
+/**
+ * main
+ * 
+ * executable entry point
+ */
+int __cdecl main(int argc, char **argv)
+{
     struct test tests[] = 
     {
-        {0, 0, 0},
-        {0, 1, 0},
-        {0.104528463, 0.994521895, 0.104719755},
-        {0.207911691, 0.978147601, 0.20943951},
-        {0.309016994, 0.951056516, 0.314159265},
-        {0.406736643, 0.913545458, 0.41887902},
-        {0.5, 0.866025404, 0.523598776},
-        {0.587785252, 0.809016994, 0.628318531},
-        {0.669130606, 0.743144825, 0.733038286},
-        {0.743144825, 0.669130606, 0.837758041},
-        {0.809016994, 0.587785252, 0.942477796},
-        {0.866025404, 0.5, 1.04719755},
-        {0.913545458, 0.406736643, 1.15191731},
-        {0.951056516, 0.309016994, 1.25663706},
-        {0.978147601, 0.207911691, 1.36135682},
-        {0.994521895, 0.104528463, 1.46607657},
-        {1, 4.48965922e-011, 1.57079633},    
+        /* y                       x                       expected                variance */
+        {  0,                      PAL_POSINF,             0,                      PAL_EPSILON },
+        {  0,                      0,                      0,                      PAL_EPSILON },
+        {  0.31296179620778659,    0.94976571538163866,    0.31830988618379067,    PAL_EPSILON },           // expected:  1 / pi
+        {  0.42077048331375735,    0.90716712923909839,    0.43429448190325183,    PAL_EPSILON },           // expected:  log10(e)
+        {  0.59448076852482208,    0.80410982822879171,    0.63661977236758134,    PAL_EPSILON },           // expected:  2 / pi
+        {  0.63896127631363480,    0.76923890136397213,    0.69314718055994531,    PAL_EPSILON },           // expected:  ln(2)
+        {  0.64963693908006244,    0.76024459707563015,    0.70710678118654752,    PAL_EPSILON },           // expected:  1 / sqrt(2)
+        {  0.70710678118654752,    0.70710678118654752,    0.78539816339744831,    PAL_EPSILON },           // expected:  pi / 4,         value:  1 / sqrt(2)
+        {  1,                      1,                      0.78539816339744831,    PAL_EPSILON },           // expected:  pi / 4
+        {  PAL_POSINF,             PAL_POSINF,             0.78539816339744831,    PAL_EPSILON },           // expected:  pi / 4
+        {  0.84147098480789651,    0.54030230586813972,    1,                      PAL_EPSILON * 10 },
+        {  0.90371945743584630,    0.42812514788535792,    1.1283791670955126,     PAL_EPSILON * 10 },      // expected:  2 / sqrt(pi)
+        {  0.98776594599273553,    0.15594369476537447,    1.4142135623730950,     PAL_EPSILON * 10 },      // expected:  sqrt(2)
+        {  0.99180624439366372,    0.12775121753523991,    1.4426950408889634,     PAL_EPSILON * 10 },      // expected:  log2(e)
+        {  1,                      0,                      1.5707963267948966,     PAL_EPSILON * 10 },      // expected:  pi / 2
+        {  PAL_POSINF,             0,                      1.5707963267948966,     PAL_EPSILON * 10 },      // expected:  pi / 2
+        {  PAL_POSINF,             1,                      1.5707963267948966,     PAL_EPSILON * 10 },      // expected:  pi / 2
+        {  0.74398033695749319,   -0.66820151019031295,    2.3025850929940457,     PAL_EPSILON * 10 },      // expected:  ln(10)
+        {  0.41078129050290870,   -0.91173391478696510,    2.7182818284590452,     PAL_EPSILON * 10 },      // expected:  e
+        {  0,                     -1,                      3.1415926535897932,     PAL_EPSILON * 10 },      // expected:  pi
+        {  1,                      PAL_POSINF,             0,                      PAL_EPSILON },
     };
 
-
     if (PAL_Initialize(argc, argv) != 0)
     {
-           return FAIL;
+        return FAIL;
     }
 
-    for( i = 0; i < sizeof(tests) / sizeof(struct test); i++)
+    for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
     {
-        DoTest(tests[i].x, tests[i].y, tests[i].result);
-        DoTest(-tests[i].x, tests[i].y, -tests[i].result);
-        DoTest(tests[i].x, -tests[i].y, pi - tests[i].result);
-        DoTest(-tests[i].x, -tests[i].y, tests[i].result - pi);
+        const double pi = 3.1415926535897932;
+        
+        validate( tests[i].y,  tests[i].x,  tests[i].expected,      tests[i].variance);
+        validate(-tests[i].y,  tests[i].x, -tests[i].expected,      tests[i].variance);
+        validate( tests[i].y, -tests[i].x,  pi - tests[i].expected, tests[i].variance);
+        validate(-tests[i].y, -tests[i].x,  tests[i].expected - pi, tests[i].variance);
     }
+    
+    validate_isnan(PAL_NEGINF, PAL_NAN);
+    validate_isnan(PAL_NAN,    PAL_NEGINF);
+    validate_isnan(PAL_NAN,    PAL_POSINF);
+    validate_isnan(PAL_POSINF, PAL_NAN);
+    
+    validate_isnan(PAL_NAN, -1);
+    validate_isnan(PAL_NAN, -0.0);
+    validate_isnan(PAL_NAN,  0);
+    validate_isnan(PAL_NAN,  1);
+    
+    validate_isnan(-1,   PAL_NAN);
+    validate_isnan(-0.0, PAL_NAN);
+    validate_isnan( 0,   PAL_NAN);
+    validate_isnan( 1,   PAL_NAN);
+    
+    validate_isnan(PAL_NAN, PAL_NAN);
 
     PAL_Terminate();
     return PASS;
index f554acf..e6e36e6 100644 (file)
 **          negative infinity.  Makes sure that calling ceil on NaN returns 
 **          NaN
 **
-**
 **==========================================================================*/
 
 #include <palsuite.h>
 
-typedef struct
-{
-    double value;
-    double ceilVal;
-} testCase;
-
-typedef struct
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this 
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN     sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF  log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
 {
-    INT64 value;
-    INT64 ceilVal;
-} extremeCase;
-
-#define INT64_TO_DOUBLE(a) (*(double*)&a)
-
-int __cdecl main(int argc, char *argv[])
+    double value;     /* value to test the function with */
+    double expected;  /* expected result */
+    double variance;  /* maximum delta between the expected and actual result */
+};
+
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
 {
-    INT64 NaN = I64(0x7ff8000000000000);
-    double value;
-    double ceilVal;
-    double ret;
-    int i;
-
-    testCase testCases[] =
-    {
-        {2.8, 3},
-        {-2.8, -2},
-        {5.5, 6},
-        {-5.5, -5},
-        {3, 3},
-        {-3, -3},
-        {0, 0},
-    };
-    extremeCase extremeCases[] =
-    {
-        /* Positive Infinity */
-        {I64(0x7ff0000000000000), I64(0x7ff0000000000000)},
-        /* Negative Infinitey */
-        {I64(0xfff0000000000000), I64(0xfff0000000000000)},   
-        /* Smallest possible +value */
-        {I64(0x0000000000000001), I64(0x3FF0000000000000)},   
-        /* Smallest possible -value */
-        {I64(0x8000000000000001), I64(0x8000000000000000)},   
-    };
-
+    double result = ceil(value);
 
     /*
-     * Initialize the PAL and return FAIL if this fails
+     * The test is valid when the difference between result
+     * and expected is less than or equal to variance
      */
-    if (0 != (PAL_Initialize(argc, argv)))
+    double delta = fabs(result - expected);
+
+    if (delta > variance)
     {
-        return FAIL;
+        Fail("ceil(%g) returned %20.17g when it should have returned %20.17g",
+             value, result, expected);
     }
+}
 
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+    double result = ceil(value);
 
-    for (i=0; i<sizeof(testCases) / sizeof(testCase); i++)
+    if (!_isnan(result))
     {
-        ret = ceil(testCases[i].value);
-
-        if (ret != testCases[i].ceilVal)
-        {
-            Fail("Expected ceil(%g) to return %g, got %g\n", 
-                testCases[i].value, testCases[i].ceilVal, ret);
-        }
+        Fail("ceil(%g) returned %20.17g when it should have returned %20.17g",
+             value, result, PAL_NAN);
     }
-    
-    for (i=0; i<sizeof(extremeCases) / sizeof(extremeCase); i++)
-    {
-        value = INT64_TO_DOUBLE(extremeCases[i].value);
-        ceilVal = INT64_TO_DOUBLE(extremeCases[i].ceilVal);
+}
 
-        ret = ceil(value);
+/**
+ * main
+ * 
+ * executable entry point
+ */
+int __cdecl main(int argc, char *argv[])
+{
+    struct test tests[] = 
+    {
+        /* value                   expected           variance */
+        {  0.31830988618379067,    1,                 PAL_EPSILON * 10 },     // value:  1 / pi
+        {  0.43429448190325183,    1,                 PAL_EPSILON * 10 },     // value:  log10(e)
+        {  0.63661977236758134,    1,                 PAL_EPSILON * 10 },     // value:  2 / pi
+        {  0.69314718055994531,    1,                 PAL_EPSILON * 10 },     // value:  ln(2)
+        {  0.70710678118654752,    1,                 PAL_EPSILON * 10 },     // value:  1 / sqrt(2)
+        {  0.78539816339744831,    1,                 PAL_EPSILON * 10 },     // value:  pi / 4
+        {  1.1283791670955126,     2,                 PAL_EPSILON * 10 },     // value:  2 / sqrt(pi)
+        {  1.4142135623730950,     2,                 PAL_EPSILON * 10 },     // value:  sqrt(2)
+        {  1.4426950408889634,     2,                 PAL_EPSILON * 10 },     // value:  log2(e)
+        {  1.5707963267948966,     2,                 PAL_EPSILON * 10 },     // value:  pi / 2
+        {  2.3025850929940457,     3,                 PAL_EPSILON * 10 },     // value:  ln(10)
+        {  2.7182818284590452,     3,                 PAL_EPSILON * 10 },     // value:  e
+        {  3.1415926535897932,     4,                 PAL_EPSILON * 10 },     // value:  pi
+        {  PAL_POSINF,             PAL_POSINF,        0 }
+    };
 
-        if (ret != ceilVal)
-        {
-            Fail("Expected ceil(%g) to return %g, got %I64X\n", 
-                value, ceilVal, ret);
-        }
+    /* PAL initialization */
+    if (PAL_Initialize(argc, argv) != 0)
+    {
+        return FAIL;
     }
-
-    /* Test how ceil handles NaN */
-    if (!_isnan(ceil(INT64_TO_DOUBLE(NaN))))
+    
+    validate( 0,    0, PAL_EPSILON);
+    validate(-0.0,  0, PAL_EPSILON);
+    
+    validate( 1,    1, PAL_EPSILON * 10);
+    validate(-1.0, -1, PAL_EPSILON * 10);
+    
+    for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
     {
-        Fail("Passing NaN to ceil did not return NaN!\n");
+        validate( tests[i].value, tests[i].expected,     tests[i].variance);
+        validate(-tests[i].value, 1 - tests[i].expected, tests[i].variance);
     }
+    
+    validate_isnan(PAL_NAN);
 
     PAL_Terminate();
     return PASS;
 }
-
index 9dbc8c6..8c1c730 100644 (file)
 **               PAL_Terminate
 **               Fail
 **               fabs
-** 
-
 **
 **===========================================================================*/
 
 #include <palsuite.h>
 
-#define DELTA 0.0000001 /* Error acceptance level to the 7th decimal */
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this 
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN     sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF  log(0.0)
 
 /**
  * Helper test structure
  */
 struct test
 {
-    double value;   /* value to test the function with */
-    double result;  /* expected result */
+    double value;     /* value to test the function with */
+    double expected;  /* expected result */
+    double variance;  /* maximum delta between the expected and actual result */
 };
 
 /**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+    double result = cos(value);
+
+    /*
+     * The test is valid when the difference between result
+     * and expected is less than or equal to variance
+     */
+    double delta = fabs(result - expected);
+
+    if (delta > variance)
+    {
+        Fail("cos(%g) returned %20.17g when it should have returned %20.17g",
+             value, result, expected);
+    }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+    double result = cos(value);
+
+    if (!_isnan(result))
+    {
+        Fail("cos(%g) returned %20.17g when it should have returned %20.17g",
+             value, result, PAL_NAN);
+    }
+}
+
+/**
  * main
  * 
  * executable entry point
  */
-INT __cdecl main(INT argc, CHAR **argv)
+int __cdecl main(int argc, char **argv)
 {
-    double pi = 3.1415926535;
-    int i;
-
     struct test tests[] = 
     {
-        /* Value        test result */
-        { 0,                1 },
-        { pi/2.0,           0 },
-        { pi,              -1 },
-        { (3.0*pi) / 2.0,   0 },
-        { 2.0 * pi,         1 },
-        { 5.0*pi/2.0,       0 },
-        { 3.0*pi,          -1 },
-        { (7.0*pi) / 2.0,   0 },
-        { 4.0 * pi,         1 },
-        { 1.7e-12,          1 },
-        { 1.7e+12,          0.1745850 }
+        /* value                   expected                variance */
+        {  0,                      1,                      PAL_EPSILON * 10 },
+        {  0.31830988618379067,    0.94976571538163866,    PAL_EPSILON },       // value:  1 / pi
+        {  0.43429448190325183,    0.90716712923909839,    PAL_EPSILON },       // value:  log10(e)
+        {  0.63661977236758134,    0.80410982822879171,    PAL_EPSILON },       // value:  2 / pi
+        {  0.69314718055994531,    0.76923890136397213,    PAL_EPSILON },       // value:  ln(2)
+        {  0.70710678118654752,    0.76024459707563015,    PAL_EPSILON },       // value:  1 / sqrt(2)
+        {  0.78539816339744831,    0.70710678118654752,    PAL_EPSILON },       // value:  pi / 4,         expected:  1 / sqrt(2)
+        {  1,                      0.54030230586813972,    PAL_EPSILON },
+        {  1.1283791670955126,     0.42812514788535792,    PAL_EPSILON },       // value:  2 / sqrt(pi)
+        {  1.4142135623730950,     0.15594369476537447,    PAL_EPSILON },       // value:  sqrt(2)
+        {  1.4426950408889634,     0.12775121753523991,    PAL_EPSILON },       // value:  log2(e)
+        {  1.5707963267948966,     0,                      PAL_EPSILON },       // value:  pi / 2
+        {  2.3025850929940457,    -0.66820151019031295,    PAL_EPSILON },       // value:  ln(10)
+        {  2.7182818284590452,    -0.91173391478696510,    PAL_EPSILON },       // value:  e
+        {  3.1415926535897932,    -1,                      PAL_EPSILON * 10 },  // value:  pi
     };
 
-
     /* PAL initialization */
-    if( PAL_Initialize(argc, argv) != 0 )
+    if (PAL_Initialize(argc, argv) != 0)
     {
-           return (FAIL);
+        return FAIL;
     }
 
-    for( i = 0; i < sizeof(tests) / sizeof(struct test); i++)
+    for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
     {
-        double result;
-        double testDelta;
-
-        result = cos( tests[i].value );
-
-        /* The test is valid when the difference between the */
-        /* result and the expectation is less than DELTA */
-        testDelta = fabs( result - tests[i].result );
-        if( testDelta >= DELTA )
-        {
-            Fail( "cos(%g) returned %20.10g"
-                  " when it should have returned %20.10g",
-                  tests[i].value,
-                  result, 
-                  tests[i].result );
-        }
+        validate( tests[i].value, tests[i].expected, tests[i].variance);
+        validate(-tests[i].value, tests[i].expected, tests[i].variance);
     }
+    
+    validate_isnan(PAL_NEGINF);
+    validate_isnan(PAL_NAN);
+    validate_isnan(PAL_POSINF);
 
     PAL_Terminate();
     return PASS;
 }
-
-
index ed5fee3..9e57b7f 100644 (file)
@@ -11,6 +11,3 @@ EXE1 = test1
 Description
 = Passes to cos() a series of angle value, checking that
 = each one return the correct value.
-
-
-
index a0fb67b..40c2fca 100644 (file)
 ** 
 ** Dependencies: PAL_Initialize
 **               PAL_Terminate
-**                              Fail
+**               Fail
 **               fabs
-** 
-
 **
 **===========================================================================*/
 
 #include <palsuite.h>
 
-#define DELTA 0.0000001 /* Error acceptance level to the 7th decimal */
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this 
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN     sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF  log(0.0)
 
 /**
  * Helper test structure
  */
 struct test
 {
-    double value;   /* value to test the function with */
-    double result;  /* expected result */
+    double value;      /* value to test the function with */
+    double expected;  /* expected result */
+    double variance;  /* maximum delta between the expected and actual result */
 };
 
 /**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+    double result = cosh(value);
+
+    /*
+     * The test is valid when the difference between result
+     * and expected is less than or equal to variance
+     */
+    double delta = fabs(result - expected);
+
+    if (delta > variance)
+    {
+        Fail("cosh(%g) returned %20.17g when it should have returned %20.17g",
+             value, result, expected);
+    }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning PAL_NAN
+ */
+void __cdecl validate_isnan(double value)
+{
+    double result = cosh(value);
+
+    if (!_isnan(result))
+    {
+        Fail("cosh(%g) returned %20.17g when it should have returned %20.17g",
+             value, result, PAL_NAN);
+    }
+}
+
+/**
  * main
  * 
  * executable entry point
  */
-INT __cdecl main(INT argc, CHAR **argv)
+int __cdecl main(int argc, char **argv)
 {
-    double pi = 3.1415926535;
-    int i;
-
     struct test tests[] = 
     {
-        /* Value        test result */
-        { 0,                1 },
-        { pi/2.0,           2.5091785 },
-        { pi,               11.5919533 },
-        { (3.0*pi) / 2.0,   55.6633809 },
-        { 2.0 * pi,         267.7467614 },
-        { 5.0*pi/2.0,       1287.9854421 },
-        { 3.0*pi,           6195.8239426 },
-        { (7.0*pi) / 2.0,   29804.8707455 },
-        { 4.0 * pi,         143375.6565186 }
+        /* value                   expected               variance */
+        {  0,                      1,                     PAL_EPSILON * 10 },
+        {  0.31830988618379067,    1.0510897883672876,    PAL_EPSILON * 10 },   // value:  1 / pi
+        {  0.43429448190325183,    1.0957974645564909,    PAL_EPSILON * 10 },   // value:  log10(e)
+        {  0.63661977236758134,    1.2095794864199787,    PAL_EPSILON * 10 },   // value:  2 / pi
+        {  0.69314718055994531,    1.25,                  PAL_EPSILON * 10 },   // value:  ln(2)
+        {  0.70710678118654752,    1.2605918365213561,    PAL_EPSILON * 10 },   // value:  1 / sqrt(2)
+        {  0.78539816339744831,    1.3246090892520058,    PAL_EPSILON * 10 },   // value:  pi / 4
+        {  1,                      1.5430806348152438,    PAL_EPSILON * 10 },
+        {  1.1283791670955126,     1.7071001431069344,    PAL_EPSILON * 10 },   // value:  2 / sqrt(pi)
+        {  1.4142135623730950,     2.1781835566085709,    PAL_EPSILON * 10 },   // value:  sqrt(2)
+        {  1.4426950408889634,     2.2341880974508023,    PAL_EPSILON * 10 },   // value:  log2(e)
+        {  1.5707963267948966,     2.5091784786580568,    PAL_EPSILON * 10 },   // value:  pi / 2
+        {  2.3025850929940457,     5.05,                  PAL_EPSILON * 10 },   // value:  ln(10)
+        {  2.7182818284590452,     7.6101251386622884,    PAL_EPSILON * 10 },   // value:  e
+        {  3.1415926535897932,     11.591953275521521,    PAL_EPSILON * 100 },  // value:  pi
+        {  PAL_POSINF,             PAL_POSINF,            0 },
     };
 
-
     /* PAL initialization */
-    if( PAL_Initialize(argc, argv) != 0 )
+    if (PAL_Initialize(argc, argv) != 0)
     {
-           return (FAIL);
+        return FAIL;
     }
 
-    for( i = 0; i < sizeof(tests) / sizeof(struct test); i++)
+    for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
     {
-        double result;
-        double testDelta;
-
-
-        result = cosh( tests[i].value );
-
-        /*
-         * The test is valid when the difference between the
-         * result and the expectation is less than DELTA
-         */
-        testDelta = fabs( result - tests[i].result );
-        if( testDelta >= DELTA )
-        {
-            Fail( "cosh(%g) returned %g"
-                  " when it should have returned %g",
-                  tests[i].value,
-                  result, 
-                  tests[i].result );
-        }
+        validate( tests[i].value, tests[i].expected, tests[i].variance);
+        validate(-tests[i].value, tests[i].expected, tests[i].variance);
     }
+    
+    validate_isnan(PAL_NAN);
 
     PAL_Terminate();
     return PASS;
 }
-
-
-
-
-
-
-
-
-
-
-
-
-
index 39f932a..1315122 100644 (file)
@@ -11,6 +11,3 @@ EXE1 = test1
 Description
 = Passes to cosh() a series of angle value, checking that
 = each one return to correct value.
-
-
-
index 1962ade..5e1ef7f 100644 (file)
@@ -1,6 +1,3 @@
 cmake_minimum_required(VERSION 2.8.12.2)
 
 add_subdirectory(test1)
-add_subdirectory(test2)
-add_subdirectory(test3)
-
index 67de564..20e071a 100644 (file)
 **
 ** Purpose: Tests exp with a normal set of values.
 **
-**
 **===================================================================*/
 
 #include <palsuite.h>
 
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this 
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN     sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF  log(0.0)
+
+/**
+ * Helper test structure
+ */
 struct test
 {
-    double value;
-    double result;
-    double delta;
+    double value;     /* value to test the function with */
+    double expected;  /* expected result */
+    double variance;  /* maximum delta between the expected and actual result */
 };
 
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+    double result = exp(value);
+
+    /*
+     * The test is valid when the difference between result
+     * and expected is less than or equal to variance
+     */
+    double delta = fabs(result - expected);
 
-int __cdecl main(int argc, char **argv)
-{    
-    double value;
-    double testDelta;
-    int i;
+    if (delta > variance)
+    {
+        Fail("exp(%g) returned %20.17g when it should have returned %20.17g",
+             value, result, expected);
+    }
+}
 
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+    double result = exp(value);
+
+    if (!_isnan(result))
+    {
+        Fail("exp(%g) returned %20.17g when it should have returned %20.17g",
+             value, result, PAL_NAN);
+    }
+}
+
+/**
+ * main
+ * 
+ * executable entry point
+ */
+int __cdecl main(int argc, char **argv)
+{
     struct test tests[] = 
     {
-        {0, 1, 1e-7},
-        {0.5, 1.64872127, 1e-7},
-        {-0.5, 0.60653066, 1e-7},
-        {1, 2.71828183, 1e-7},
-        {-1, 0.367879441, 1e-7},
-        {10, 2.202646579481e+004, 1e-4},
-        {-10, 4.53999298e-005, 1e-13},
-
-        {600, 3.7730203009299397e+260, 1e+252},
-        {-600, 2.6503965530043108e-261, 1e-269}
+        /* value                   expected                 variance */
+        { PAL_NEGINF,              0,                       PAL_EPSILON },
+        { -3.1415926535897932,     0.043213918263772250,    PAL_EPSILON / 10 },   // value: -(pi)
+        { -2.7182818284590452,     0.065988035845312537,    PAL_EPSILON / 10 },   // value: -(e)
+        { -2.3025850929940457,     0.1,                     PAL_EPSILON },        // value: -(ln(10))
+        { -1.5707963267948966,     0.20787957635076191,     PAL_EPSILON },        // value: -(pi / 2)
+        { -1.4426950408889634,     0.23629008834452270,     PAL_EPSILON },        // value: -(log2(e))
+        { -1.4142135623730950,     0.24311673443421421,     PAL_EPSILON },        // value: -(sqrt(2))
+        { -1.1283791670955126,     0.32355726390307110,     PAL_EPSILON },        // value: -(2 / sqrt(pi))
+        { -1,                      0.36787944117144232,     PAL_EPSILON },        // value: -(1)
+        { -0.78539816339744831,    0.45593812776599624,     PAL_EPSILON },        // value: -(pi / 4)
+        { -0.70710678118654752,    0.49306869139523979,     PAL_EPSILON },        // value: -(1 / sqrt(2))
+        { -0.69314718055994531,    0.5,                     PAL_EPSILON },        // value: -(ln(2))
+        { -0.63661977236758134,    0.52907780826773535,     PAL_EPSILON },        // value: -(2 / pi)
+        { -0.43429448190325183,    0.64772148514180065,     PAL_EPSILON },        // value: -(log10(e))
+        { -0.31830988618379067,    0.72737734929521647,     PAL_EPSILON },        // value: -(1 / pi)
+        {  0,                      1,                       PAL_EPSILON * 10 },
+        {  0.31830988618379067,    1.3748022274393586,      PAL_EPSILON * 10 },   // value:  1 / pi
+        {  0.43429448190325183,    1.5438734439711811,      PAL_EPSILON * 10 },   // value:  log10(e)
+        {  0.63661977236758134,    1.8900811645722220,      PAL_EPSILON * 10 },   // value:  2 / pi
+        {  0.69314718055994531,    2,                       PAL_EPSILON * 10 },   // value:  ln(2)
+        {  0.70710678118654752,    2.0281149816474725,      PAL_EPSILON * 10 },   // value:  1 / sqrt(2)
+        {  0.78539816339744831,    2.1932800507380155,      PAL_EPSILON * 10 },   // value:  pi / 4
+        {  1,                      2.7182818284590452,      PAL_EPSILON * 10 },   //                           expected: e
+        {  1.1283791670955126,     3.0906430223107976,      PAL_EPSILON * 10 },   // value:  2 / sqrt(pi)
+        {  1.4142135623730950,     4.1132503787829275,      PAL_EPSILON * 10 },   // value:  sqrt(2)
+        {  1.4426950408889634,     4.2320861065570819,      PAL_EPSILON * 10 },   // value:  log2(e)
+        {  1.5707963267948966,     4.8104773809653517,      PAL_EPSILON * 10 },   // value:  pi / 2
+        {  2.3025850929940457,     10,                      PAL_EPSILON * 100 },  // value:  ln(10)
+        {  2.7182818284590452,     15.154262241479264,      PAL_EPSILON * 100 },  // value:  e
+        {  3.1415926535897932,     23.140692632779269,      PAL_EPSILON * 100 },  // value:  pi
+        {  PAL_POSINF,             PAL_POSINF,              0 },
     };
 
-
     if (PAL_Initialize(argc, argv) != 0)
     {
-           return FAIL;
+        return FAIL;
     }
 
-    for( i = 0; i < sizeof(tests) / sizeof(struct test); i++)
+    for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
     {
-        value = exp(tests[i].value);
-
-        testDelta = fabs(value - tests[i].result);
-        if( testDelta >= tests[i].delta )
-        {
-            Fail("exp(%g) returned %g when it should have returned %g\n",
-                    tests[i].value, value, tests[i].result);
-        }    
+        validate(tests[i].value, tests[i].expected, tests[i].variance);
     }
 
+    validate_isnan(PAL_NAN);
+
     PAL_Terminate();
     return PASS;
 }
diff --git a/src/pal/tests/palsuite/c_runtime/exp/test2/test2.c b/src/pal/tests/palsuite/c_runtime/exp/test2/test2.c
deleted file mode 100644 (file)
index 5cfaa78..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-// 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.
-
-/*=====================================================================
-**
-** Source:  test1.c
-**
-** Purpose: Tests that exp handles underflows, overflows, and NaNs
-**          corectly.
-**
-**
-**===================================================================*/
-
-#include <palsuite.h>
-
-int __cdecl main(int argc, char **argv)
-{
-    double zero = 0.0;
-    double PosInf = 1.0 / zero;
-    double NaN = 0.0 / zero;
-    // Force 'value' to be converted to a double to avoid
-    // using the internal precision of the FPU for comparisons.
-    volatile double value;
-
-    if (PAL_Initialize(argc, argv) != 0)
-    {
-           return FAIL;
-    }
-
-    /* Test overflows give PosInf */
-    value = exp(800.0);
-    if (value != PosInf)
-    {
-        Fail( "exp(%g) returned %g when it should have returned %g\n",
-                    800.0, value, PosInf);
-    }
-
-    value = exp(PosInf);
-    if (value != PosInf)
-    {
-        Fail( "exp(%g) returned %g when it should have returned %g\n",
-            PosInf, value, PosInf);
-    }
-
-    /* Test underflows give 0 */
-    value = exp(-800);
-    if (value != 0)
-    {
-        Fail( "exp(%g) returned %g when it should have returned %g\n",
-                    -800.0, value, 0.0);
-    }    
-
-    /* Test that a NaN as input gives a NaN */
-    value = exp(NaN);
-    if (_isnan(value) == 0)
-    {
-        Fail( "exp( NaN ) returned %g when it should have returned NaN\n", 
-            value);
-    }
-
-    PAL_Terminate();
-    return PASS;
-}
diff --git a/src/pal/tests/palsuite/c_runtime/exp/test3/test3.c b/src/pal/tests/palsuite/c_runtime/exp/test3/test3.c
deleted file mode 100644 (file)
index 0efd15e..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-// 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.
-
-/*=============================================================================
-**
-** Source: test3.c
-**
-** Purpose: Test to ensure that exp returns correct values.
-** 
-** Dependencies: PAL_Initialize
-**               PAL_Terminate
-**                              Fail
-**               fabs
-**               _finite
-**               _isnan
-** 
-
-**
-**===========================================================================*/
-
-#include <palsuite.h>
-
-#define DELTA 0.0000001  /* Error acceptance level to the 7th decimal */
-
-/**
- * Helper test structure
- */
-struct test
-{
-    double value;   /* value to test the function with */
-    double result;  /* expected result */
-};
-
-/**
- * main
- * 
- * executable entry point
- */
-INT __cdecl main(INT argc, CHAR **argv)
-{
-    int i;
-    double result;
-
-    struct test tests[] = 
-    {
-        /* Value        test result  */
-        { 0.100000000000, 1.105170918076 },
-        { 1.000000000000, 2.718281828459 },
-        { 2.400000000000, 11.023176380642 },
-        { 3.750000000000, 42.521082000063 },
-        { 7.630000000000, 2059.050019837344 },
-        { 10.000000000000, 22026.465794806718 },
-        { 13.260000000000, 573779.238840227250 },
-        { 18.100000000000, 72565488.372322351000 },
-        { 25.000000000000, 72004899337.385880000000 },
-        { 29.310000000000, 5360079912775.353500000000 }
-    };
-
-    double infinite[] =
-    {
-        2215.8, 20554.1
-    };
-
-
-    /* PAL initialization */
-    if( PAL_Initialize(argc, argv) != 0 )
-    {
-           return (FAIL);
-    }
-
-    for( i = 0; i < sizeof(tests) / sizeof(struct test); i++)
-    {
-        double testDelta;
-        double allowedDelta;
-
-        result = exp( tests[i].value );
-
-        /* The test is valid when the difference between the */
-        /* result and the expectation is less than DELTA */
-        allowedDelta = (tests[i].value > 1) ? 1 : DELTA;
-        testDelta = fabs( result - tests[i].result );
-        if( testDelta >= allowedDelta )
-        {
-            Fail( "exp(%g) returned %20.10g"
-                  " when it should have returned %20.10g\n",
-                  tests[i].value,
-                  result, 
-                  tests[i].result );
-        }
-    }
-
-    for( i = 0; i < sizeof(infinite) / sizeof(double); i++)
-    {
-        result = exp( infinite[i] );
-
-        /* The test is valid when the function returns an infinite result */
-        if( _finite( result ) )
-        {
-            Fail( "exp(%g) returned %20.10g"
-                  " when it should have returned 1.#INF00000000",
-                  infinite[i],
-                  result );
-        }
-    }
-
-    PAL_Terminate();
-    return PASS;
-}
index cd8c0be..0a74d5c 100644 (file)
 ** 
 ** Dependencies: PAL_Initialize
 **               PAL_Terminate
-**                              Fail
-** 
-
+**               Fail
 **
 **===========================================================================*/
 
 #include <palsuite.h>
 
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this 
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN     sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF  log(0.0)
+
 /**
  * Helper test structure
  */
 struct test
 {
-    double value;  // param 1
-    double result; // expected result
+    double value;     /* value to test the function with */
+    double expected;  /* expected result */
+    double variance;  /* maximum delta between the expected and actual result */
 };
 
 /**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+    double result = fabs(value);
+
+    /*
+     * The test is valid when the difference between result
+     * and expected is less than or equal to variance
+     */
+    double delta = fabs(result - expected);
+
+    if (delta > variance)
+    {
+        Fail("fabs(%g) returned %20.17g when it should have returned %20.17g",
+             value, result, expected);
+    }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+    double result = fabs(value);
+
+    if (!_isnan(result))
+    {
+        Fail("fabs(%g) returned %20.17g when it should have returned %20.17g",
+             value, result, PAL_NAN);
+    }
+}
+
+/**
  * main
  * 
  * executable entry point
  */
 INT __cdecl main(INT argc, CHAR **argv)
 {
-    int i;
-
     struct test tests[] = 
     {
-      // param 1       result
-        { 3,           3 },
-        { -10,         10 },
-        { 0,           0 },
-        { 1.7e308,     1.7e308 },
-        { -1.7e308,    1.7e308 },
-        { 4.94e-324,   4.94e-324 },
-        { -4.94e-324,  4.94e-324 }
+        /* value                   expected                variance */
+        { PAL_NEGINF,              PAL_POSINF,             0 },
+        { -3.1415926535897932,     3.1415926535897932,     PAL_EPSILON * 10 },  // value: -(pi)              expected:  pi
+        { -2.7182818284590452,     2.7182818284590452,     PAL_EPSILON * 10 },  // value: -(e)               expected:  e
+        { -2.3025850929940457,     2.3025850929940457,     PAL_EPSILON * 10 },  // value: -(ln(10))          expected:  ln(10)
+        { -1.5707963267948966,     1.5707963267948966,     PAL_EPSILON * 10 },  // value: -(pi / 2)          expected:  pi / 2
+        { -1.4426950408889634,     1.4426950408889634,     PAL_EPSILON * 10 },  // value: -(log2(e))         expected:  log2(e)
+        { -1.4142135623730950,     1.4142135623730950,     PAL_EPSILON * 10 },  // value: -(sqrt(2))         expected:  sqrt(2)
+        { -1.1283791670955126,     1.1283791670955126,     PAL_EPSILON * 10 },  // value: -(2 / sqrt(pi))    expected:  2 / sqrt(pi)
+        { -1,                      1,                      PAL_EPSILON * 10 },
+        { -0.78539816339744831,    0.78539816339744831,    PAL_EPSILON },       // value: -(pi / 4)          expected:  pi / 4
+        { -0.70710678118654752,    0.70710678118654752,    PAL_EPSILON },       // value: -(1 / sqrt(2))     expected:  1 / sqrt(2)
+        { -0.69314718055994531,    0.69314718055994531,    PAL_EPSILON },       // value: -(ln(2))           expected:  ln(2)
+        { -0.63661977236758134,    0.63661977236758134,    PAL_EPSILON },       // value: -(2 / pi)          expected:  2 / pi
+        { -0.43429448190325183,    0.43429448190325183,    PAL_EPSILON },       // value: -(log10(e))        expected:  log10(e)
+        { -0.31830988618379067,    0.31830988618379067,    PAL_EPSILON },       // value: -(1 / pi)          expected:  1 / pi
+        { -0.0,                    0,                      PAL_EPSILON },
     };
 
 
     // PAL initialization
-    if( PAL_Initialize(argc, argv) != 0 )
+    if (PAL_Initialize(argc, argv) != 0)
     {
-           return FAIL;
+        return FAIL;
     }
 
-    for( i = 0; i < sizeof(tests) / sizeof(struct test); i++ )
+    for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
     {
-        double result;
-
-        result = fabs( tests[i].value );
-
-        if( result != tests[i].result )
-        {
-            Fail( "fabs(%f) returned %f"
-                  " when it should have returned %f",
-                  tests[i].value,
-                  result, 
-                  tests[i].result );
-        }
+        validate( tests[i].value, tests[i].expected, tests[i].variance);
+        validate(-tests[i].value, tests[i].expected, tests[i].variance);
     }
+    
+    validate_isnan(PAL_NAN);
 
     PAL_Terminate();
     return PASS;
 }
-
-
-
-
-
-
-
-
-
-
-
-
-
index a15d54e..d5b2321 100644 (file)
@@ -11,6 +11,3 @@ EXE1 = test1
 Description
 = Passes to fabs() a series of values, checking that
 = each one return to correct value.
-
-
-
diff --git a/src/pal/tests/palsuite/c_runtime/fabsf/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fabsf/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5e1ef7f
--- /dev/null
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
@@ -3,16 +3,16 @@ cmake_minimum_required(VERSION 2.8.12.2)
 set(CMAKE_INCLUDE_CURRENT_DIR ON)
 
 set(SOURCES
-  test2.c
+  test1.c
 )
 
-add_executable(paltest_exp_test2
+add_executable(paltest_fabsf_test1
   ${SOURCES}
 )
 
-add_dependencies(paltest_exp_test2 coreclrpal)
+add_dependencies(paltest_fabsf_test1 coreclrpal)
 
-target_link_libraries(paltest_exp_test2
+target_link_libraries(paltest_fabsf_test1
   pthread
   m
   coreclrpal
diff --git a/src/pal/tests/palsuite/c_runtime/fabsf/test1/test1.c b/src/pal/tests/palsuite/c_runtime/fabsf/test1/test1.c
new file mode 100644 (file)
index 0000000..0b02072
--- /dev/null
@@ -0,0 +1,130 @@
+// 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.
+
+/*=============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test to ensure that fabsf return the correct values
+** 
+** Dependencies: PAL_Initialize
+**               PAL_Terminate
+**               Fail
+**
+**===========================================================================*/
+
+#include <palsuite.h>
+
+// binary32 (float) has a machine epsilon of 2^-23 (approx. 1.19e-07). However, this 
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-21 (approx. 4.76e-07) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (6-9 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxx will use PAL_EPSILON
+// for the variance, while an expected result in the format of 0.0xxxxxxxxx will use
+// PAL_EPSILON / 10 and and expected result in the format of x.xxxxxx will use PAL_EPSILON * 10.
+#define PAL_EPSILON 4.76837158e-07
+                    
+
+#define PAL_NAN     sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF  log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
+{
+    float value;     /* value to test the function with */
+    float expected;  /* expected result */
+    float variance;  /* maximum delta between the expected and actual result */
+};
+
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(float value, float expected, float variance)
+{
+    float result = fabsf(value);
+
+    /*
+     * The test is valid when the difference between result
+     * and expected is less than or equal to variance
+     */
+    float delta = fabsf(result - expected);
+
+    if (delta > variance)
+    {
+        Fail("fabsf(%g) returned %10.9g when it should have returned %10.9g",
+             value, result, expected);
+    }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(float value)
+{
+    float result = fabsf(value);
+
+    if (!_isnan(result))
+    {
+        Fail("fabsf(%g) returned %10.9g when it should have returned %10.9g",
+             value, result, PAL_NAN);
+    }
+}
+
+/**
+ * main
+ * 
+ * executable entry point
+ */
+INT __cdecl main(INT argc, CHAR **argv)
+{
+    struct test tests[] = 
+    {
+        /* value            expected           variance */
+        { PAL_NEGINF,       PAL_POSINF,        0 },
+        { -3.14159265f,     3.14159265f,       PAL_EPSILON * 10 },    // value: -(pi)              expected:  pi
+        { -2.71828183f,     2.71828183f,       PAL_EPSILON * 10 },    // value: -(e)               expected:  e
+        { -2.30258509f,     2.30258509f,       PAL_EPSILON * 10 },    // value: -(ln(10))          expected:  ln(10)
+        { -1.57079633f,     1.57079633f,       PAL_EPSILON * 10 },    // value: -(pi / 2)          expected:  pi / 2
+        { -1.44269504f,     1.44269504f,       PAL_EPSILON * 10 },    // value: -(log2(e))         expected:  log2(e)
+        { -1.41421356f,     1.41421356f,       PAL_EPSILON * 10 },    // value: -(sqrt(2))         expected:  sqrt(2)
+        { -1.12837917f,     1.12837917f,       PAL_EPSILON * 10 },    // value: -(2 / sqrt(pi))    expected:  2 / sqrt(pi)
+        { -1,               1,                 PAL_EPSILON * 10 },
+        { -0.785398163f,    0.785398163f,      PAL_EPSILON },         // value: -(pi / 4)          expected:  pi / 4
+        { -0.707106781f,    0.707106781f,      PAL_EPSILON },         // value: -(1 / sqrt(2))     expected:  1 / sqrt(2)
+        { -0.693147181f,    0.693147181f,      PAL_EPSILON },         // value: -(ln(2))           expected:  ln(2)
+        { -0.636619772f,    0.636619772f,      PAL_EPSILON },         // value: -(2 / pi)          expected:  2 / pi
+        { -0.434294482f,    0.434294482f,      PAL_EPSILON },         // value: -(log10(e))        expected:  log10(e)
+        { -0.318309886f,    0.318309886f,      PAL_EPSILON },         // value: -(1 / pi)          expected:  1 / pi
+        { -0.0f,            0,                 PAL_EPSILON },
+    };
+
+
+    // PAL initialization
+    if (PAL_Initialize(argc, argv) != 0)
+    {
+        return FAIL;
+    }
+
+    for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
+    {
+        validate( tests[i].value, tests[i].expected, tests[i].variance);
+        validate(-tests[i].value, tests[i].expected, tests[i].variance);
+    }
+    
+    validate_isnan(PAL_NAN);
+
+    PAL_Terminate();
+    return PASS;
+}
@@ -4,9 +4,10 @@
 
 Version = 1.0
 Section = C Runtime
-Function = exp
-Name = Test #2 for exp
-Type = DEFAULT
-EXE1 = test2
+Function = fabsf
+Name = Positive Test for fabsf
+TYPE = DEFAULT
+EXE1 = test1
 Description
-=Tests that exp handles underflows, overflows, and NaNs correctly.
+= Passes to fabsf() a series of values, checking that
+= each one return to correct value.
index b576334..dba3209 100644 (file)
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
-/*=============================================================================
+/*============================================================================
 **
-** Source: test1.c
+** Source:  test1.c
 **
-** Purpose: Test to ensure that floor return the correct values
-** 
-** Dependencies: PAL_Initialize
-**               PAL_Terminate
-**                              Fail
-** 
-
+** Purpose: Tests floor with simple positive and negative values.  Also tests 
+**          extreme cases like extremely small values and positive and 
+**          negative infinity.  Makes sure that calling floor on NaN returns 
+**          NaN
 **
-**===========================================================================*/
+**==========================================================================*/
 
 #include <palsuite.h>
 
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this 
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN     sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF  log(0.0)
+
 /**
  * Helper test structure
  */
 struct test
 {
-    double value; // floor param 1
-    double result; // expected result
+    double value;     /* value to test the function with */
+    double expected;  /* expected result */
+    double variance;  /* maximum delta between the expected and actual result */
 };
 
 /**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+    double result = floor(value);
+
+    /*
+     * The test is valid when the difference between result
+     * and expected is less than or equal to variance
+     */
+    double delta = fabs(result - expected);
+
+    if (delta > variance)
+    {
+        Fail("floor(%g) returned %20.17g when it should have returned %20.17g",
+             value, result, expected);
+    }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+    double result = floor(value);
+
+    if (!_isnan(result))
+    {
+        Fail("floor(%g) returned %20.17g when it should have returned %20.17g",
+             value, result, PAL_NAN);
+    }
+}
+
+/**
  * main
  * 
  * executable entry point
  */
-INT __cdecl main(INT argc, CHAR **argv)
+int __cdecl main(int argc, char *argv[])
 {
-    int i;
-
     struct test tests[] = 
     {
-      // param 1         result
-        { 3,                3 },
-        { -10,            -10 },
-        { 0,                0 },
-        { 1.7e308,          1.7e308 },
-        { -1.7e308,        -1.7e308 },
-        { 4.94e-324,        0 },
-        { -4.94e-324,      -1 },
-        { 1234.1234,     1234 },
-        { -1234.1234,   -1235 },
-        {-0,                0 }
+        /* value                   expected           variance */
+        {  0.31830988618379067,    0,                 PAL_EPSILON },        // value:  1 / pi
+        {  0.43429448190325183,    0,                 PAL_EPSILON },        // value:  log10(e)
+        {  0.63661977236758134,    0,                 PAL_EPSILON },        // value:  2 / pi
+        {  0.69314718055994531,    0,                 PAL_EPSILON },        // value:  ln(2)
+        {  0.70710678118654752,    0,                 PAL_EPSILON },        // value:  1 / sqrt(2)
+        {  0.78539816339744831,    0,                 PAL_EPSILON },        // value:  pi / 4
+        {  1.1283791670955126,     1,                 PAL_EPSILON * 10 },   // value:  2 / sqrt(pi)
+        {  1.4142135623730950,     1,                 PAL_EPSILON * 10 },   // value:  sqrt(2)
+        {  1.4426950408889634,     1,                 PAL_EPSILON * 10 },   // value:  log2(e)
+        {  1.5707963267948966,     1,                 PAL_EPSILON * 10 },   // value:  pi / 2
+        {  2.3025850929940457,     2,                 PAL_EPSILON * 10 },   // value:  ln(10)
+        {  2.7182818284590452,     2,                 PAL_EPSILON * 10 },   // value:  e
+        {  3.1415926535897932,     3,                 PAL_EPSILON * 10 },   // value:  pi
+        {  PAL_POSINF,             PAL_POSINF,        0 }
     };
 
-
-    // PAL initialization
-    if( PAL_Initialize(argc, argv) != 0 )
+    /* PAL initialization */
+    if (PAL_Initialize(argc, argv) != 0)
     {
-           return FAIL;
+        return FAIL;
     }
-
-    for( i = 0; i < sizeof(tests) / sizeof(struct test); i++)
+    
+    validate( 0,    0, PAL_EPSILON);
+    validate(-0.0,  0, PAL_EPSILON);
+    
+    validate( 1,    1, PAL_EPSILON * 10);
+    validate(-1.0, -1, PAL_EPSILON * 10);
+
+    for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
     {
-        double result;
-
-        result = floor( tests[i].value );
-
-        if( result != tests[i].result )
-        {
-            Fail( "floor(%f) returned %f"
-                  " when it should have returned %f",
-                  tests[i].value,
-                  result, 
-                  tests[i].result );
-        }
+        validate( tests[i].value,  tests[i].expected,       tests[i].variance);
+        validate(-tests[i].value, -(tests[i].expected + 1), tests[i].variance);
     }
+    
+    validate_isnan(PAL_NAN);
 
     PAL_Terminate();
     return PASS;
 }
-
-
-
-
-
-
-
-
-
-
-
-
-
index 8aa8437..90543ea 100644 (file)
@@ -11,6 +11,3 @@ EXE1 = test1
 Description
 = Passes to floor() a series of value, checking that
 = each one return to correct value.
-
-
-
index d415371..fd69ca5 100644 (file)
 ** 
 ** Dependencies: PAL_Initialize
 **               PAL_Terminate
-**                              Fail
+**               Fail
 **               fabs
-** 
-
 **
 **===========================================================================*/
 
 #include <palsuite.h>
 
-#define DELTA 0.0000001 //Error acceptance level to the 7th decimal
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this 
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN     sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF  log(0.0)
 
 /**
  * Helper test structure
  */
 struct test
 {
-    double valueX; // fmod param 1
-    double valueY; // fmod param 2
-    double result; // expected result
+    double numerator;    /* second component of the value to test the function with */
+    double denominator;  /* first component of the value to test the function with */
+    double expected;     /* expected result */
+    double variance;     /* maximum delta between the expected and actual result */
 };
 
 /**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double numerator, double denominator, double expected, double variance)
+{
+    double result = fmod(numerator, denominator);
+
+    /*
+     * The test is valid when the difference between result
+     * and expected is less than or equal to variance
+     */
+    double delta = fabs(result - expected);
+
+    if (delta > variance)
+    {
+        Fail("fmod(%g, %g) returned %20.17g when it should have returned %20.17g",
+             numerator, denominator, result, expected);
+    }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double numerator, double denominator)
+{
+    double result = fmod(numerator, denominator);
+
+    if (!_isnan(result))
+    {
+        Fail("fmod(%g, %g) returned %20.17g when it should have returned %20.17g",
+             numerator, denominator, result, PAL_NAN);
+    }
+}
+
+/**
  * main
  * 
  * executable entry point
  */
 INT __cdecl main(INT argc, CHAR **argv)
 {
-    int i;
-
     struct test tests[] = 
     {
-      // param 1    param 2     result
-        { 3,        2,          1 },
-        { -10,      3,         -1 },
-        { 1,        0.0,        0 },
-        { 1.7e308,  -1.7e308,   0 },
-        { 100,      -1.1234,    0.017400 },
-        { -100,     -1.1234,    -0.017400},
-        { 0,        0,          0 },
-        {-0,        1,          0 },
-        {-0,        -0,         0 }
+        /* numerator               denominator             expected                 variance */
+        {  0,                      PAL_POSINF,             0,                       PAL_EPSILON },
+        {  0.31296179620778659,    0.94976571538163866,    0.31296179620778658,     PAL_EPSILON },
+        {  0.42077048331375735,    0.90716712923909839,    0.42077048331375733,     PAL_EPSILON },
+        {  0.59448076852482208,    0.80410982822879171,    0.59448076852482212,     PAL_EPSILON },
+        {  0.63896127631363480,    0.76923890136397213,    0.63896127631363475,     PAL_EPSILON },
+        {  0.64963693908006244,    0.76024459707563015,    0.64963693908006248,     PAL_EPSILON },
+        {  0.70710678118654752,    0.70710678118654752,    0,                       PAL_EPSILON },
+        {  1,                      1,                      0,                       PAL_EPSILON },
+        {  0.84147098480789651,    0.54030230586813972,    0.30116867893975674,     PAL_EPSILON },
+        {  0.90371945743584630,    0.42812514788535792,    0.047469161665130377,    PAL_EPSILON / 10 },
+        {  0.98776594599273553,    0.15594369476537447,    0.052103777400488605,    PAL_EPSILON / 10 },
+        {  0.99180624439366372,    0.12775121753523991,    0.097547721646984359,    PAL_EPSILON / 10 },
+        {  0.74398033695749319,   -0.66820151019031295,    0.075778826767180285,    PAL_EPSILON / 10 },
+        {  0.41078129050290870,   -0.91173391478696510,    0.41078129050290868,     PAL_EPSILON },
+        {  0,                     -1,                      0,                       PAL_EPSILON },
+        {  1,                      PAL_POSINF,             1,                       PAL_EPSILON * 10 },
     };
 
 
     // PAL initialization
-    if( PAL_Initialize(argc, argv) != 0 )
+    if (PAL_Initialize(argc, argv) != 0)
     {
-           return FAIL;
+        return FAIL;
     }
 
-    for( i = 0; i < sizeof(tests) / sizeof(struct test); i++ )
+    for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
     {
-        double result;
-        double testDelta;
-
-        result = fmod( tests[i].valueX, tests[i].valueY );
-
-        // The test is valid when the difference between the
-        // result and the expectation is less than DELTA
-        testDelta = fabs( result - tests[i].result );
-        if( testDelta >= DELTA )
-        {
-            Fail( "fmod(%f, %f) returned %f"
-                  " when it should have returned %f",
-                  tests[i].valueX,
-                  tests[i].valueY,
-                  result, 
-                  tests[i].result );
-        }
+        validate( tests[i].numerator,  tests[i].denominator,  tests[i].expected, tests[i].variance);
+        validate(-tests[i].numerator,  tests[i].denominator, -tests[i].expected, tests[i].variance);
+        validate( tests[i].numerator, -tests[i].denominator,  tests[i].expected, tests[i].variance);
+        validate(-tests[i].numerator, -tests[i].denominator, -tests[i].expected, tests[i].variance);
     }
 
+    validate_isnan( 0,    0);
+    validate_isnan(-0.0,  0);
+    validate_isnan( 0,   -0.0);
+    validate_isnan(-0.0, -0.0);
+    
+    validate_isnan( 1,    0);
+    validate_isnan(-1.0,  0);
+    validate_isnan( 1,   -0.0);
+    validate_isnan(-1.0, -0.0);
+    
+    validate_isnan(PAL_POSINF,  PAL_POSINF);
+    validate_isnan(PAL_NEGINF,  PAL_POSINF);
+    validate_isnan(PAL_POSINF, PAL_NEGINF);
+    validate_isnan(PAL_NEGINF, PAL_NEGINF);
+    
+    validate_isnan(PAL_POSINF,  0);
+    validate_isnan(PAL_NEGINF,  0);
+    validate_isnan(PAL_POSINF, -0.0);
+    validate_isnan(PAL_NEGINF, -0.0);
+    
+    validate_isnan(PAL_POSINF,  1);
+    validate_isnan(PAL_NEGINF,  1);
+    validate_isnan(PAL_POSINF, -1.0);
+    validate_isnan(PAL_NEGINF, -1.0);
+    
     PAL_Terminate();
     return PASS;
 }
-
-
-
-
-
-
-
-
-
-
-
-
-
index 850daf0..0a81fd8 100644 (file)
@@ -11,6 +11,3 @@ EXE1 = test1
 Description
 = Passes to fmod() a series of values, checking that
 = each one return to correct value.
-
-
-
diff --git a/src/pal/tests/palsuite/c_runtime/fmodf/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fmodf/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5e1ef7f
--- /dev/null
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
@@ -3,16 +3,16 @@ cmake_minimum_required(VERSION 2.8.12.2)
 set(CMAKE_INCLUDE_CURRENT_DIR ON)
 
 set(SOURCES
-  test2.c
+  test1.c
 )
 
-add_executable(paltest_pow_test2
+add_executable(paltest_fmodf_test1
   ${SOURCES}
 )
 
-add_dependencies(paltest_pow_test2 coreclrpal)
+add_dependencies(paltest_fmodf_test1 coreclrpal)
 
-target_link_libraries(paltest_pow_test2
+target_link_libraries(paltest_fmodf_test1
   pthread
   m
   coreclrpal
diff --git a/src/pal/tests/palsuite/c_runtime/fmodf/test1/test1.c b/src/pal/tests/palsuite/c_runtime/fmodf/test1/test1.c
new file mode 100644 (file)
index 0000000..31b45d3
--- /dev/null
@@ -0,0 +1,156 @@
+// 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.
+
+/*=============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test to ensure that fmodf return the correct values
+** 
+** Dependencies: PAL_Initialize
+**               PAL_Terminate
+**               Fail
+**               fabsf
+**
+**===========================================================================*/
+
+#include <palsuite.h>
+
+// binary32 (float) has a machine epsilon of 2^-23 (approx. 1.19e-07). However, this 
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-21 (approx. 4.76e-07) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (6-9 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxx will use PAL_EPSILON
+// for the variance, while an expected result in the format of 0.0xxxxxxxxx will use
+// PAL_EPSILON / 10 and and expected result in the format of x.xxxxxx will use PAL_EPSILON * 10.
+#define PAL_EPSILON 4.76837158e-07
+
+#define PAL_NAN     sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF  log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
+{
+    float numerator;    /* second component of the value to test the function with */
+    float denominator;  /* first component of the value to test the function with */
+    float expected;     /* expected result */
+    float variance;     /* maximum delta between the expected and actual result */
+};
+
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(float numerator, float denominator, float expected, float variance)
+{
+    float result = fmodf(numerator, denominator);
+
+    /*
+     * The test is valid when the difference between result
+     * and expected is less than or equal to variance
+     */
+    float delta = fabsf(result - expected);
+
+    if (delta > variance)
+    {
+        Fail("fmodf(%g, %g) returned %10.9g when it should have returned %10.9g",
+             numerator, denominator, result, expected);
+    }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(float numerator, float denominator)
+{
+    float result = fmodf(numerator, denominator);
+
+    if (!_isnan(result))
+    {
+        Fail("fmodf(%g, %g) returned %10.9g when it should have returned %10.9g",
+             numerator, denominator, result, PAL_NAN);
+    }
+}
+
+/**
+ * main
+ * 
+ * executable entry point
+ */
+INT __cdecl main(INT argc, CHAR **argv)
+{
+    struct test tests[] = 
+    {
+        /* numerator        denominator        expected          variance */
+        {  0,               PAL_POSINF,        0,                PAL_EPSILON },
+        {  0.312961796f,    0.949765715f,      0.312961796f,     PAL_EPSILON },
+        {  0.420770483f,    0.907167129f,      0.420770483f,     PAL_EPSILON },
+        {  0.594480769f,    0.804109828f,      0.594480769f,     PAL_EPSILON },
+        {  0.638961276f,    0.769238901f,      0.638961276f,     PAL_EPSILON },
+        {  0.649636939f,    0.760244597f,      0.649636939f,     PAL_EPSILON },
+        {  0.707106781f,    0.707106781f,      0,                PAL_EPSILON },
+        {  1,               1,                 0,                PAL_EPSILON },
+        {  0.841470985f,    0.540302306f,      0.301168679f,     PAL_EPSILON },
+        {  0.903719457f,    0.428125148f,      0.0474691617f,    PAL_EPSILON / 10 },
+        {  0.987765946f,    0.155943695f,      0.0521037774f,    PAL_EPSILON / 10 },
+        {  0.991806244f,    0.127751218f,      0.0975477216f,    PAL_EPSILON / 10 },
+        {  0.743980337f,   -0.668201510f,      0.0757788268f,    PAL_EPSILON / 10 },
+        {  0.410781291f,   -0.911733915f,      0.410781291f,     PAL_EPSILON },
+        {  0,              -1,                 0,                PAL_EPSILON },
+        {  1,               PAL_POSINF,        1,                PAL_EPSILON * 10 },
+    };
+
+
+    // PAL initialization
+    if (PAL_Initialize(argc, argv) != 0)
+    {
+        return FAIL;
+    }
+
+    for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
+    {
+        validate( tests[i].numerator,  tests[i].denominator,  tests[i].expected, tests[i].variance);
+        validate(-tests[i].numerator,  tests[i].denominator, -tests[i].expected, tests[i].variance);
+        validate( tests[i].numerator, -tests[i].denominator,  tests[i].expected, tests[i].variance);
+        validate(-tests[i].numerator, -tests[i].denominator, -tests[i].expected, tests[i].variance);
+    }
+
+    validate_isnan( 0,     0);
+    validate_isnan(-0.0f,  0);
+    validate_isnan( 0,    -0.0f);
+    validate_isnan(-0.0f, -0.0f);
+    
+    validate_isnan( 1,     0);
+    validate_isnan(-1,     0);
+    validate_isnan( 1,    -0.0f);
+    validate_isnan(-1,    -0.0f);
+    
+    validate_isnan(PAL_POSINF, PAL_POSINF);
+    validate_isnan(PAL_NEGINF, PAL_POSINF);
+    validate_isnan(PAL_POSINF, PAL_NEGINF);
+    validate_isnan(PAL_NEGINF, PAL_NEGINF);
+    
+    validate_isnan(PAL_POSINF,  0);
+    validate_isnan(PAL_NEGINF,  0);
+    validate_isnan(PAL_POSINF, -0.0f);
+    validate_isnan(PAL_NEGINF, -0.0f);
+    
+    validate_isnan(PAL_POSINF,  1);
+    validate_isnan(PAL_NEGINF,  1);
+    validate_isnan(PAL_POSINF, -1);
+    validate_isnan(PAL_NEGINF, -1);
+    
+    PAL_Terminate();
+    return PASS;
+}
@@ -4,11 +4,10 @@
 
 Version = 1.0
 Section = C Runtime
-Function = pow
-Name = Positive Test for pow
+Function = fmodf
+Name = Positive Test for fmodf
 TYPE = DEFAULT
-EXE1 = test3
+EXE1 = test1
 Description
-= Passes a series of values to the pow() function,
-= checking each for the expected result. Also checks
-= for proper handling of out-of-range values.
+= Passes to fmodf() a series of values, checking that
+= each one return to correct value.
index 0328bda..eea592d 100644 (file)
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
-/*=============================================================================
+/*=====================================================================
 **
-** Source: test1.c
+** Source:  test1.c
 **
-** Purpose: Test to ensure that log returns correct values.
-** 
-** Dependencies: PAL_Initialize
-**               PAL_Terminate
-**                              Fail
-**               fabs
-**               _finite
-**               _isnan
-** 
-
+** Purpose: Tests log with a normal set of values.
 **
-**===========================================================================*/
+**===================================================================*/
 
 #include <palsuite.h>
 
-#define DELTA 0.0000001 /* Error acceptance level to the 7th decimal */
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this 
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN     sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF  log(0.0)
 
 /**
  * Helper test structure
  */
 struct test
 {
-    double value;   /* value to test the function with */
-    double result;  /* expected result */
+    double value;     /* value to test the function with */
+    double expected;  /* expected result */
+    double variance;  /* maximum delta between the expected and actual result */
 };
 
 /**
- * main
- * 
- * executable entry point
+ * validate
+ *
+ * test validation function
  */
-INT __cdecl main(INT argc, CHAR **argv)
+void __cdecl validate(double value, double expected, double variance)
 {
-    int i;
-    double result;
+    double result = log(value);
 
-    struct test tests[] = 
-    {
-        /* Value               test result */
-        { 4.812768944365,     1.571272582596 },
-        { 25.873592333750,    3.253222847545 },
-        { 30.301828058718,    3.411208042666 },
-        { 53.752250740074,    3.984385540365 },
-        { 65.282143620106,    4.178718547435 },
-        { 74.843592638936,    4.315400504515 },
-        { 92.446668904691,    4.526631925866 },
-        { 99.832148197882,    4.603490257677 },
-        { 1830.360576189459,  7.512268262595 },
-        { 6524.430494094669,  8.783308947783 },
-        { 12456.186254463331, 9.429972666394 },
-        { 14183.841639454329, 9.559858682961 },
-        { 18221.999603259377, 9.810384912501 },
-        { 20792.917264320811, 9.942367691562 },
-        { 26488.001312295906, 10.184447128770 },
-        { 29724.154423657950, 10.299715274515 },
-        { 27899211.434430983, 17.144108982393 },
-        { 55048606.214117862, 17.823727102268 },
-        { 66659312.564470351, 18.015105318226 },
-        { 113314373.84325695, 18.545676583294 },
-        { 201366015.49641407, 19.120634782682 },
-        { 311568417.23368025, 19.557129510064 },
-        { 486835298.54176462, 20.003436427833 },
-    };
+    /*
+     * The test is valid when the difference between result
+     * and expected is less than or equal to variance
+     */
+    double delta = fabs(result - expected);
 
-    double indefinite[] =
+    if (delta > variance)
     {
-        -864278.51, -1000.2, -2
-    };
+        Fail("log(%g) returned %20.17g when it should have returned %20.17g",
+             value, result, expected);
+    }
+}
 
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+    double result = log(value);
 
-    /* PAL initialization */
-    if( PAL_Initialize(argc, argv) != 0 )
+    if (!_isnan(result))
     {
-           return (FAIL);
+        Fail("log(%g) returned %20.17g when it should have returned %20.17g",
+             value, result, PAL_NAN);
     }
+}
 
-    for( i = 0; i < sizeof(tests) / sizeof(struct test); i++)
+/**
+ * main
+ * 
+ * executable entry point
+ */
+int __cdecl main(int argc, char **argv)
+{
+    struct test tests[] = 
     {
-        double testDelta;
-
-        result = log( tests[i].value );
-
-        /* 
-         * The test is valid when the difference between the
-         * result and the expectation is less than DELTA
-         */
-        testDelta = fabs( result - tests[i].result );
-        if( testDelta >= DELTA )
-        {
-            Fail( "log(%g) returned %20.10f"
-                  " when it should have returned %20.10f",
-                  tests[i].value,
-                  result, 
-                  tests[i].result );
-        }
-    }
+        /* value                       expected               variance */
+        {  0,                          PAL_NEGINF,            0 },
+        {  0.043213918263772250,      -3.1415926535897932,    PAL_EPSILON * 10 },   // expected: -(pi)
+        {  0.065988035845312537,      -2.7182818284590452,    PAL_EPSILON * 10 },   // expected: -(e)
+        {  0.1,                       -2.3025850929940457,    PAL_EPSILON * 10 },   // expected: -(ln(10))
+        {  0.20787957635076191,       -1.5707963267948966,    PAL_EPSILON * 10 },   // expected: -(pi / 2)
+        {  0.23629008834452270,       -1.4426950408889634,    PAL_EPSILON * 10 },   // expected: -(log2(e))
+        {  0.24311673443421421,       -1.4142135623730950,    PAL_EPSILON * 10 },   // expected: -(sqrt(2))
+        {  0.32355726390307110,       -1.1283791670955126,    PAL_EPSILON * 10 },   // expected: -(2 / sqrt(pi))
+        {  0.36787944117144232,       -1,                     PAL_EPSILON * 10 },   // expected: -(1)
+        {  0.45593812776599624,       -0.78539816339744831,   PAL_EPSILON },        // expected: -(pi / 4)
+        {  0.49306869139523979,       -0.70710678118654752,   PAL_EPSILON },        // expected: -(1 / sqrt(2))
+        {  0.5,                       -0.69314718055994531,   PAL_EPSILON },        // expected: -(ln(2))
+        {  0.52907780826773535,       -0.63661977236758134,   PAL_EPSILON },        // expected: -(2 / pi)
+        {  0.64772148514180065,       -0.43429448190325183,   PAL_EPSILON },        // expected: -(log10(e))
+        {  0.72737734929521647,       -0.31830988618379067,   PAL_EPSILON },        // expected: -(1 / pi)
+        {  1,                          0,                     PAL_EPSILON },
+        {  1.3748022274393586,         0.31830988618379067,   PAL_EPSILON },        // expected:  1 / pi
+        {  1.5438734439711811,         0.43429448190325183,   PAL_EPSILON },        // expected:  log10(e)
+        {  1.8900811645722220,         0.63661977236758134,   PAL_EPSILON },        // expected:  2 / pi
+        {  2,                          0.69314718055994531,   PAL_EPSILON },        // expected:  ln(2)
+        {  2.0281149816474725,         0.70710678118654752,   PAL_EPSILON },        // expected:  1 / sqrt(2)
+        {  2.1932800507380155,         0.78539816339744831,   PAL_EPSILON },        // expected:  pi / 4
+        {  2.7182818284590452,         1,                     PAL_EPSILON * 10 },   //                               value: e
+        {  3.0906430223107976,         1.1283791670955126,    PAL_EPSILON * 10 },   // expected:  2 / sqrt(pi)
+        {  4.1132503787829275,         1.4142135623730950,    PAL_EPSILON * 10 },   // expected:  sqrt(2)
+        {  4.2320861065570819,         1.4426950408889634,    PAL_EPSILON * 10 },   // expected:  log2(e)
+        {  4.8104773809653517,         1.5707963267948966,    PAL_EPSILON * 10 },   // expected:  pi / 2
+        {  10,                         2.3025850929940457,    PAL_EPSILON * 10 },   // expected:  ln(10)
+        {  15.154262241479264,         2.7182818284590452,    PAL_EPSILON * 10 },   // expected:  e
+        {  23.140692632779269,         3.1415926535897932,    PAL_EPSILON * 10 },   // expected:  pi
+        {  PAL_POSINF,                 PAL_POSINF,            0 },
+    };
+
 
-    for( i = 0; i < sizeof(indefinite) / sizeof(double); i++)
+    if (PAL_Initialize(argc, argv) != 0)
     {
-        result = log( indefinite[i] );
-
-        /* The test is valid when the function returns a defined result */
-        if( ! _isnan( result ) )
-        {
-            Fail( "log(%g) returned %20.10f"
-                  " when it should have returned -1.#IND00000000",
-                  indefinite[i],
-                  result );
-        }
+        return FAIL;
     }
 
-    /* log(0) is a special case */
-    result = log( 0.0 );
-    if( _finite( result ) )
+    for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
     {
-            Fail( "log(%g) returned %20.10f"
-                  " when it should have returned -1.#INF00000000",
-                  0.0,
-                  result );
+        validate(tests[i].value, tests[i].expected, tests[i].variance);
     }
+    
+    validate_isnan(PAL_NEGINF);
+    validate_isnan(PAL_NAN);
 
     PAL_Terminate();
     return PASS;
index b27ea23..6b984f6 100644 (file)
@@ -12,6 +12,3 @@ Description
 = Passes a series of values to the log() function,
 = checking each for the expected result. Also checks
 = for proper handling of out-of-range values.
-
-
-
index 519db31..13711a7 100644 (file)
 **
 ** Source: test1.c
 **
-** Purpose: Test to ensure that log returns correct values.
+** Purpose: Test to ensure that log10 returns correct values.
 ** 
 ** Dependencies: PAL_Initialize
 **               PAL_Terminate
-**                              Fail
+**               Fail
 **               fabs
-**               _finite
 **               _isnan
 ** 
-
-**
 **===========================================================================*/
 
 #include <palsuite.h>
 
-#define DELTA 0.0000001 /*Error acceptance level to the 7th decimal */
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this 
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN     sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF  log(0.0)
 
 /**
  * Helper test structure
  */
 struct test
 {
-    double value;   /* value to test the function with */
-    double result;  /* expected result */
+    double value;     /* value to test the function with */
+    double expected;  /* expected result */
+    double variance;  /* maximum delta between the expected and actual result */
 };
 
 /**
- * main
- * 
- * executable entry point
+ * validate
+ *
+ * test validation function
  */
-INT __cdecl main(INT argc, CHAR **argv)
+void __cdecl validate(double value, double expected, double variance)
 {
-    int i;
-    double result;
+    double result = log10(value);
 
-    struct test tests[] = 
-    {
-        /* Value        test result */
-        { 6.704916531877, 0.826393375779 },
-        { 15.823847163305, 1.199312079583 },
-        { 21.658986175115, 1.335638124087 },
-        { 34.134952848903, 1.533199307291 },
-        { 42.857142857143, 1.632023214705 },
-        { 57.573168126469, 1.760220128395 },
-        { 67.363505966369, 1.828424682147 },
-        { 75.649281289102, 1.878804806336 },
-        { 99.877925962096, 1.999469515332 },
-        { 1706.203161717582, 3.232030742400 },
-        { 3016.598101748711, 3.479517453423 },
-        { 4017.596636860256, 3.603966331820 },
-        { 5462.646626178777, 3.737403107294 },
-        { 7199.790368358409, 3.857319851544 },
-        { 13577.991882076480, 4.132835544685 },
-        { 19235.535721915341, 4.284104286189 },
-        { 24904.989593188267, 4.396286364594 },
-        { 10690368.906277657000, 7.028992692224 },
-        { 40653667.728385270000, 7.609099733260 },
-        { 71100035.987914667000, 7.851869820552 },
-        { 111208971.628284560000, 8.046139824759 },
-        { 172499991.153172400000, 8.236789077136 },
-        { 244361677.392925830000, 8.388033097635 },
-        { 292552744.803003010000, 8.466204177125 },
-        { 317831243.774193530000, 8.502196587433 },
-        { 501815331.063020770000, 8.700543925401 },
-    };
+    /*
+     * The test is valid when the difference between result
+     * and expected is less than or equal to variance
+     */
+    double delta = fabs(result - expected);
 
-    double indefinite[] =
+    if (delta > variance)
     {
-        -864278.51, -1000.2, -2
-    };
+        Fail("log10(%g) returned %20.17g when it should have returned %20.17g",
+             value, result, expected);
+    }
+}
 
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+    double result = log10(value);
 
-    /* PAL initialization */
-    if( PAL_Initialize(argc, argv) != 0 )
+    if (!_isnan(result))
     {
-           return (FAIL);
+        Fail("log10(%g) returned %20.17g when it should have returned %20.17g",
+             value, result, PAL_NAN);
     }
+}
 
-    for( i = 0; i < sizeof(tests) / sizeof(struct test); i++)
+/**
+ * main
+ * 
+ * executable entry point
+ */
+int __cdecl main(int argc, char **argv)
+{
+    struct test tests[] = 
     {
-        double testDelta;
-
-        result = log10( tests[i].value );
-
-        /*
-         * The test is valid when the difference between the
-         * result and the expectation is less than DELTA
-         */
-        testDelta = fabs( result - tests[i].result );
-        if( testDelta >= DELTA )
-        {
-            Fail( "log10(%g) returned %20.10f"
-                  " when it should have returned %20.10f",
-                  tests[i].value,
-                  result, 
-                  tests[i].result );
-        }
-    }
+        /* value                       expected               variance */
+        {  0,                          PAL_NEGINF,            0 },
+        {  0.00072178415907472774,    -3.1415926535897932,    PAL_EPSILON * 10 },   // expected: -(pi)
+        {  0.0019130141022243176,     -2.7182818284590452,    PAL_EPSILON * 10 },   // expected: -(e)
+        {  0.0049821282964407206,     -2.3025850929940457,    PAL_EPSILON * 10 },   // expected: -(ln(10))
+        {  0.026866041001136132,      -1.5707963267948966,    PAL_EPSILON * 10 },   // expected: -(pi / 2)
+        {  0.036083192820787210,      -1.4426950408889634,    PAL_EPSILON * 10 },   // expected: -(log2(e))
+        {  0.038528884700322026,      -1.4142135623730950,    PAL_EPSILON * 10 },   // expected: -(sqrt(2))
+        {  0.074408205860642723,      -1.1283791670955126,    PAL_EPSILON * 10 },   // expected: -(2 / sqrt(pi))
+        {  0.1,                       -1,                     PAL_EPSILON * 10 },   // expected: -(1)
+        {  0.16390863613957665,       -0.78539816339744831,   PAL_EPSILON },        // expected: -(pi / 4)
+        {  0.19628775993505562,       -0.70710678118654752,   PAL_EPSILON },        // expected: -(1 / sqrt(2))
+        {  0.20269956628651730,       -0.69314718055994531,   PAL_EPSILON },        // expected: -(ln(2))
+        {  0.23087676451600055,       -0.63661977236758134,   PAL_EPSILON },        // expected: -(2 / pi)
+        {  0.36787944117144232,       -0.43429448190325183,   PAL_EPSILON },        // expected: -(log10(e))
+        {  0.48049637305186868,       -0.31830988618379067,   PAL_EPSILON },        // expected: -(1 / pi)
+        {  1,                          0,                     PAL_EPSILON },
+        {  2.0811811619898573,         0.31830988618379067,   PAL_EPSILON },        // expected:  1 / pi
+        {  2.7182818284590452,         0.43429448190325183,   PAL_EPSILON },        // expected:  log10(e)           value: e
+        {  4.3313150290214525,         0.63661977236758134,   PAL_EPSILON },        // expected:  2 / pi
+        {  4.9334096679145963,         0.69314718055994531,   PAL_EPSILON },        // expected:  ln(2)
+        {  5.0945611704512962,         0.70710678118654752,   PAL_EPSILON },        // expected:  1 / sqrt(2)
+        {  6.1009598002416937,         0.78539816339744831,   PAL_EPSILON },        // expected:  pi / 4
+        {  10,                         1,                     PAL_EPSILON * 10 },
+        {  13.439377934644400,         1.1283791670955126,    PAL_EPSILON * 10 },   // expected:  2 / sqrt(pi)
+        {  25.954553519470081,         1.4142135623730950,    PAL_EPSILON * 10 },   // expected:  sqrt(2)
+        {  27.713733786437790,         1.4426950408889634,    PAL_EPSILON * 10 },   // expected:  log2(e)
+        {  37.221710484165167,         1.5707963267948966,    PAL_EPSILON * 10 },   // expected:  pi / 2
+        {  200.71743249053009,         2.3025850929940457,    PAL_EPSILON * 10 },   // expected:  ln(10)
+        {  522.73529967043665,         2.7182818284590452,    PAL_EPSILON * 10 },   // expected:  e
+        {  1385.4557313670111,         3.1415926535897932,    PAL_EPSILON * 10 },   // expected:  pi
+        {  PAL_POSINF,                 PAL_POSINF,            0 },
+    };
+
 
-    for( i = 0; i < sizeof(indefinite) / sizeof(double); i++)
+    if (PAL_Initialize(argc, argv) != 0)
     {
-        result = log10( indefinite[i] );
-
-        /* The test is valid when the function returns a defined result */
-        if( ! _isnan( result ) )
-        {
-            Fail( "log10(%g) returned %20.10f"
-                  " when it should have returned -1.#IND00000000",
-                  indefinite[i],
-                  result );
-        }
+        return FAIL;
     }
 
-    /* log(0) is a special case */
-    result = log10( 0.0 );
-    if( _finite( result ) )
+    for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
     {
-            Fail( "log10(%g) returned %20.10f"
-                  " when it should have returned -1.#INF00000000",
-                  0.0,
-                  result );
+        validate(tests[i].value, tests[i].expected, tests[i].variance);
     }
+    
+    validate_isnan(PAL_NEGINF);
+    validate_isnan(PAL_NAN);
 
     PAL_Terminate();
     return PASS;
index 59ab43d..389d079 100644 (file)
 ** 
 ** Dependencies: PAL_Initialize
 **               PAL_Terminate
-**                              Fail
+**               Fail
 **               fabs
-** 
-
 **
 **===========================================================================*/
 
 #include <palsuite.h>
 
-#define DELTA 0.0000001 //Error acceptance level to the 7th decimal
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this 
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN     sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF  log(0.0)
 
 /**
  * Helper test structure
  */
 struct test
 {
-    double value;   // fmodf param 1
-    double result1; // expected result (fractional portion)
-    double result2; // expected result (integer portion)
+    double value;             /* value to test the function with */
+    double expected;          /* expected result */   
+    double variance;          /* maximum delta between the expected and actual result */
+    double expected_intpart;  /* expected result */
+    double variance_intpart;  /* maximum delta between the expected and actual result */
 };
 
 /**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance, double expected_intpart, double variance_intpart)
+{
+    double result_intpart;
+    double result = modf(value, &result_intpart);
+
+    /*
+     * The test is valid when the difference between result
+     * and expected is less than or equal to variance
+     */
+    double delta = fabs(result - expected);
+    double delta_intpart = fabs(result_intpart - expected_intpart);
+
+    if ((delta > variance) || (delta_intpart > variance_intpart))
+    {
+        Fail("modf(%g) returned %20.17g with an intpart of %20.17g when it should have returned %20.17g with an intpart of %20.17g",
+             value, result, result_intpart, expected, expected_intpart);
+    }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+    double result_intpart;
+    double result = modf(value, &result_intpart);
+
+    if (!_isnan(result) || !_isnan(result_intpart))
+    {
+        Fail("modf(%g) returned %20.17g with an intpart of %20.17g when it should have returned %20.17g with an intpart of %20.17g",
+             value, result, result_intpart, PAL_NAN, PAL_NAN);
+    }
+}
+
+/**
  * main
  * 
  * executable entry point
  */
-INT __cdecl main(INT argc, CHAR **argv)
+int __cdecl main(int argc, char **argv)
 {
-    INT i;
-
     struct test tests[] = 
     {
-      // param 1   fractional   integer
-        { 3,        0,          3  },
-        { -10,      0,         -10 },
-        { 1.1234,   0.1234,     1 },
-        { -1.1234,  -0.1234,    -1 },
-        { 1.7e308,  0,          1.7e308 },
-        { -1.7e308, 0,         -1.7e308 },
-        { 1.7e-30,  1.7e-30,    0 },
-        { 0,        0,          0 }
+        /* value                   expected                variance         expected_intpart     variance_intpart */
+        {  0,                      0,                      PAL_EPSILON,         0,                   PAL_EPSILON },
+        {  0.31830988618379067,    0.31830988618379067,    PAL_EPSILON,         0,                   PAL_EPSILON },       // value:  1 / pi
+        {  0.43429448190325183,    0.43429448190325183,    PAL_EPSILON,         0,                   PAL_EPSILON },       // value:  log10(e)
+        {  0.63661977236758134,    0.63661977236758134,    PAL_EPSILON,         0,                   PAL_EPSILON },       // value:  2 / pi
+        {  0.69314718055994531,    0.69314718055994531,    PAL_EPSILON,         0,                   PAL_EPSILON },       // value:  ln(2)
+        {  0.70710678118654752,    0.70710678118654752,    PAL_EPSILON,         0,                   PAL_EPSILON },       // value:  1 / sqrt(2)
+        {  0.78539816339744831,    0.78539816339744831,    PAL_EPSILON,         0,                   PAL_EPSILON },       // value:  pi / 4
+        {  1,                      0,                      PAL_EPSILON,         1,                   PAL_EPSILON * 10 },
+        {  1.1283791670955126,     0.1283791670955126,     PAL_EPSILON,         1,                   PAL_EPSILON * 10 },  // value:  2 / sqrt(pi)
+        {  1.4142135623730950,     0.4142135623730950,     PAL_EPSILON,         1,                   PAL_EPSILON * 10 },  // value:  sqrt(2)
+        {  1.4426950408889634,     0.4426950408889634,     PAL_EPSILON,         1,                   PAL_EPSILON * 10 },  // value:  log2(e)
+        {  1.5707963267948966,     0.5707963267948966,     PAL_EPSILON,         1,                   PAL_EPSILON * 10 },  // value:  pi / 2
+        {  2.3025850929940457,     0.3025850929940457,     PAL_EPSILON,         2,                   PAL_EPSILON * 10 },  // value:  ln(10)
+        {  2.7182818284590452,     0.7182818284590452,     PAL_EPSILON,         2,                   PAL_EPSILON * 10 },  // value:  e
+        {  3.1415926535897932,     0.1415926535897932,     PAL_EPSILON,         3,                   PAL_EPSILON * 10 },  // value:  pi
+        {  PAL_POSINF,             0,                      PAL_EPSILON,         PAL_POSINF,          0 }
+        
     };
 
-
-    // PAL initialization
-    if( PAL_Initialize(argc, argv) != 0 )
+    /* PAL initialization */
+    if (PAL_Initialize(argc, argv) != 0)
     {
-           return FAIL;
+        return FAIL;
     }
 
-    for( i = 0; i < sizeof(tests) / sizeof(struct test); i++ )
+    for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
     {
-        double fractionalResult;
-        double integerResult;
-        double testDelta;
-
-        fractionalResult = modf( tests[i].value, &integerResult );
-
-        // The test is valid when the difference between the
-        // result and the expectation is less than DELTA
-        
-        testDelta = fabs( fractionalResult - tests[i].result1 );
-
-        if( (testDelta >= DELTA) ||
-            (integerResult != tests[i].result2) )
-
-        {
-            Fail( "ERROR: "
-                  "modf(%f) returned "
-                  "fraction=%20.20f and integer=%20.20f "
-                  "when it should have returned "
-                  "fraction=%20.20f and integer=%20.20f ",
-                  tests[i].value,
-                  fractionalResult,
-                  integerResult, 
-                  tests[i].result1,
-                  tests[i].result2 );
-        }
+        validate( tests[i].value,  tests[i].expected, tests[i].variance,  tests[i].expected_intpart, tests[i].variance_intpart);
+        validate(-tests[i].value, -tests[i].expected, tests[i].variance, -tests[i].expected_intpart, tests[i].variance_intpart);
     }
 
+    validate_isnan(PAL_NAN);
+
     PAL_Terminate();
     return PASS;
 }
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/pal/tests/palsuite/c_runtime/modff/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/modff/CMakeLists.txt
new file mode 100644 (file)
index 0000000..f6aa0cb
--- /dev/null
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
@@ -3,16 +3,16 @@ cmake_minimum_required(VERSION 2.8.12.2)
 set(CMAKE_INCLUDE_CURRENT_DIR ON)
 
 set(SOURCES
-  test3.c
+  test1.c
 )
 
-add_executable(paltest_exp_test3
+add_executable(paltest_modff_test1
   ${SOURCES}
 )
 
-add_dependencies(paltest_exp_test3 coreclrpal)
+add_dependencies(paltest_modff_test1 coreclrpal)
 
-target_link_libraries(paltest_exp_test3
+target_link_libraries(paltest_modff_test1
   pthread
   m
   coreclrpal
diff --git a/src/pal/tests/palsuite/c_runtime/modff/test1/test1.c b/src/pal/tests/palsuite/c_runtime/modff/test1/test1.c
new file mode 100644 (file)
index 0000000..6b7a50b
--- /dev/null
@@ -0,0 +1,135 @@
+// 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.
+
+/*=============================================================================
+**
+** Source: test1.c (modf)
+**
+** Purpose: Test to ensure that modf return the correct values
+** 
+** Dependencies: PAL_Initialize
+**               PAL_Terminate
+**               Fail
+**               fabs
+**
+**===========================================================================*/
+
+#include <palsuite.h>
+
+// binary32 (float) has a machine epsilon of 2^-23 (approx. 1.19e-07). However, this 
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-21 (approx. 4.76e-07) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (6-9 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxx will use PAL_EPSILON
+// for the variance, while an expected result in the format of 0.0xxxxxxxxx will use
+// PAL_EPSILON / 10 and and expected result in the format of x.xxxxxx will use PAL_EPSILON * 10.
+#define PAL_EPSILON 4.76837158e-07
+
+#define PAL_NAN     sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF  log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
+{
+    float value;             /* value to test the function with */
+    float expected;          /* expected result */   
+    float variance;          /* maximum delta between the expected and actual result */
+    float expected_intpart;  /* expected result */
+    float variance_intpart;  /* maximum delta between the expected and actual result */
+};
+
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(float value, float expected, float variance, float expected_intpart, float variance_intpart)
+{
+    float result_intpart;
+    float result = modff(value, &result_intpart);
+
+    /*
+     * The test is valid when the difference between result
+     * and expected is less than or equal to variance
+     */
+    float delta = fabsf(result - expected);
+    float delta_intpart = fabsf(result_intpart - expected_intpart);
+
+    if ((delta > variance) || (delta_intpart > variance_intpart))
+    {
+        Fail("modff(%g) returned %10.9g with an intpart of %10.9g when it should have returned %10.9g with an intpart of %10.9g",
+             value, result, result_intpart, expected, expected_intpart);
+    }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(float value)
+{
+    float result_intpart;
+    float result = modff(value, &result_intpart);
+
+    if (!_isnan(result) || !_isnan(result_intpart))
+    {
+        Fail("modff(%g) returned %10.9g with an intpart of %10.9g when it should have returned %10.9g with an intpart of %10.9g",
+             value, result, result_intpart, PAL_NAN, PAL_NAN);
+    }
+}
+
+/**
+ * main
+ * 
+ * executable entry point
+ */
+int __cdecl main(int argc, char **argv)
+{
+    struct test tests[] = 
+    {
+        /* value              expected         variance    expected_intpart    variance_intpart */
+        {  0,                 0,               PAL_EPSILON,    0,                  PAL_EPSILON },
+        {  0.318309886f,      0.318309886f,    PAL_EPSILON,    0,                  PAL_EPSILON },       // value:  1 / pi
+        {  0.434294482f,      0.434294482f,    PAL_EPSILON,    0,                  PAL_EPSILON },       // value:  log10(e)
+        {  0.636619772f,      0.636619772f,    PAL_EPSILON,    0,                  PAL_EPSILON },       // value:  2 / pi
+        {  0.693147181f,      0.693147181f,    PAL_EPSILON,    0,                  PAL_EPSILON },       // value:  ln(2)
+        {  0.707106781f,      0.707106781f,    PAL_EPSILON,    0,                  PAL_EPSILON },       // value:  1 / sqrt(2)
+        {  0.785398163f,      0.785398163f,    PAL_EPSILON,    0,                  PAL_EPSILON },       // value:  pi / 4
+        {  1,                 0,               PAL_EPSILON,    1,                  PAL_EPSILON * 10 },
+        {  1.12837917f,       0.128379167f,    PAL_EPSILON,    1,                  PAL_EPSILON * 10 },  // value:  2 / sqrt(pi)
+        {  1.41421356f,       0.414213562f,    PAL_EPSILON,    1,                  PAL_EPSILON * 10 },  // value:  sqrt(2)
+        {  1.44269504f,       0.442695041f,    PAL_EPSILON,    1,                  PAL_EPSILON * 10 },  // value:  log2(e)
+        {  1.57079633f,       0.570796327f,    PAL_EPSILON,    1,                  PAL_EPSILON * 10 },  // value:  pi / 2
+        {  2.30258509f,       0.302585093f,    PAL_EPSILON,    2,                  PAL_EPSILON * 10 },  // value:  ln(10)
+        {  2.71828183f,       0.718281828f,    PAL_EPSILON,    2,                  PAL_EPSILON * 10 },  // value:  e
+        {  3.14159265f,       0.141592654f,    PAL_EPSILON,    3,                  PAL_EPSILON * 10 },  // value:  pi
+        {  PAL_POSINF,        0,               PAL_EPSILON,    PAL_POSINF,         0 }
+        
+    };
+
+    /* PAL initialization */
+    if (PAL_Initialize(argc, argv) != 0)
+    {
+        return FAIL;
+    }
+
+    for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
+    {
+        validate( tests[i].value,  tests[i].expected, tests[i].variance,  tests[i].expected_intpart, tests[i].variance_intpart);
+        validate(-tests[i].value, -tests[i].expected, tests[i].variance, -tests[i].expected_intpart, tests[i].variance_intpart);
+    }
+
+    validate_isnan(PAL_NAN);
+
+    PAL_Terminate();
+    return PASS;
+}
@@ -4,14 +4,10 @@
 
 Version = 1.0
 Section = C Runtime
-Function = exp
-Name = Positive Test for exp
+Function = modff
+Name = Positive Test for modff
 TYPE = DEFAULT
-EXE1 = test3
+EXE1 = test1
 Description
-= Passes a series of values to the exp() function,
-= checking each for the expected result. Also checks
-= for proper handling of out-of-range values.
-
-
-
+= Passes to modff() a series of values, checking that
+= each one return to correct value.
index 1962ade..5e1ef7f 100644 (file)
@@ -1,6 +1,3 @@
 cmake_minimum_required(VERSION 2.8.12.2)
 
 add_subdirectory(test1)
-add_subdirectory(test2)
-add_subdirectory(test3)
-
index 2462ba4..690ae94 100644 (file)
 **
 ** Source:  test1.c
 **
-** Purpose:  Call the pow function with various values, 
-**           to test specified valid input and boundaries.
-**
+** Purpose: Tests that atan2 returns correct values for a subset of values.
+**          Tests with positive and negative values of x and y to ensure
+**          atan2 is returning results from the correct quadrant.
 **
 **===================================================================*/
 
-/* Notes: SCENARIO                                             CASE
-          - Both number and exponent may be non-integers         1
-          - Exponent may be negative                             2
-          - If number anything and exponent is 0, returns 1      3 
-          - If number is 0 and exponent is positive, returns 0   4
-          - Number may be negative with integer exponents        5
-          - Other valid input returns the usual valid output     6
-          - See test2 for infinite and nan input/output cases    
-*/
-
 #include <palsuite.h>
 
-/* Error acceptance level to the 7th decimal */   
-#define DELTA 0.0000001
-
-struct testCase
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this 
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN     sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF  log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
 {
-    double Number;
-    double Exponent;
-    double CorrectValue;
+    double x;         /* first component of the value to test the function with */
+    double y;         /* second component of the value to test the function with */
+    double expected;  /* expected result */
+    double variance;  /* maximum delta between the expected and actual result */
 };
 
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double x, double y, double expected, double variance)
+{
+    double result = pow(x, y);
+
+    /*
+     * The test is valid when the difference between result
+     * and expected is less than or equal to variance
+     */
+    double delta = fabs(result - expected);
+
+    if (delta > variance)
+    {
+        Fail("pow(%g, %g) returned %20.17g when it should have returned %20.17g",
+             x, y, result, expected);
+    }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double x, double y)
+{
+    double result = pow(x, y);
+
+    if (!_isnan(result))
+    {
+        Fail("pow(%g, %g) returned %20.17g when it should have returned %20.17g",
+             x, y, result, PAL_NAN);
+    }
+}
+
+/**
+ * main
+ * 
+ * executable entry point
+ */
 int __cdecl main(int argc, char **argv)
 {
-    double result=0;
-    double testDelta=99999;
-    int i=0;
-
-    struct testCase testCases[] =                            /* CASE  */
-        {
-            {0,           0,       1                      }, /* 3  */
-            {0.0,         0.0,     1                      }, /* 3  */
-            {-0,          0,       1                      }, /* 3  */
-            {-0,          -0,      1                      }, /* 3  */
-            {2,           0,       1                      }, /* 3  */
-            {2,           0.0,     1                      }, /* 3  */
-            {2,           -0.0,    1                      }, /* 3  */
-            {42.3124234,  0,       1                      }, /* 3  */
-            {-2,          -0.0,    1                      }, /* 3  */
-            {-3.33132,    -0.0,    1                      }, /* 3  */
-            {-999990,     0,       1                      }, /* 3  */
-            {9999.9999,   0.0,     1                      }, /* 3  */
-            {-9999.9999,  0.0,     1                      }, /* 3  */
-            {0,           1,       0                      }, /* 4  */ 
-            {0.0,         2,       0                      }, /* 4  */ 
-            {0.0,         3,       0                      }, /* 4  */ 
-            {-0,          9.99999, 0                      }, /* 4  */ 
-            {2,           2,       4                      }, /* 6  */ 
-            {2,           -2,      0.25                   }, /* 6  */
-            {6.25,        2.5,     97.65625               }, /* 6  */
-            {12345.12345, 9.99999, 
-             82207881573997179707867981634171194834944.0  }, /* 6  */
-            {12345,       75,
-             7.2749844621476552703935675020036e+306       }, /* 6  */
-            {-2.012,      2,       4.048144               }, /* 6  */
-            {2,           1,       2                      }, /* 6  */
-            {8,           1,       8                      }, /* 6  */
-            {MAXLONG,     1,       MAXLONG                }, /* 6  */
-            {4.321,       1,       4.321                  }, /* 6  */
-            {-4.321,      1,      -4.321                  }  /* 6  */
-        };
-    if (0 != (PAL_Initialize(argc, argv)))
+    struct test tests[] = 
+    {
+        /* x                       y                       expected                   variance */
+        { PAL_NEGINF,              PAL_NEGINF,             0,                         PAL_EPSILON },
+        { PAL_NEGINF,              PAL_POSINF,             PAL_POSINF,                0 },
+
+        {  -10,                    PAL_NEGINF,             0,                         PAL_EPSILON },
+        {  -10,                   -1,                     -0.1,                       PAL_EPSILON },
+        {  -10,                    0,                      1,                         PAL_EPSILON * 10 },
+        {  -10,                    1,                     -10,                        PAL_EPSILON * 100 },
+        {  -10,                    PAL_POSINF,             PAL_POSINF,                0 },
+
+        {  -2.7182818284590452,    PAL_NEGINF,             0,                         PAL_EPSILON },          // x: -(e)
+        {  -2.7182818284590452,   -1,                     -0.36787944117144232,       PAL_EPSILON },          // x: -(e)
+        {  -2.7182818284590452,    0,                      1,                         PAL_EPSILON * 10 },     // x: -(e)
+        {  -2.7182818284590452,    1,                     -2.7182818284590452,        PAL_EPSILON * 10 },     // x: -(e)                       expected: e
+        {  -2.7182818284590452,    PAL_POSINF,             PAL_POSINF,                0 },                    // x: -(e)
+        
+        { -0.0,                   -0.0,                    1,                         PAL_EPSILON * 10 },
+        { -0.0,                    0,                      1,                         PAL_EPSILON * 10 },
+
+        {  0,                     -0.0,                    1,                         PAL_EPSILON * 10 },
+        {  0,                      0,                      1,                         PAL_EPSILON * 10 },
+
+        {  2.7182818284590452,     PAL_NEGINF,             0,                         PAL_EPSILON },
+        {  2.7182818284590452,    -3.1415926535897932,     0.043213918263772250,      PAL_EPSILON / 10 },     // x: e     y: -(pi)
+        {  2.7182818284590452,    -2.7182818284590452,     0.065988035845312537,      PAL_EPSILON / 10 },     // x: e     y: -(e)
+        {  2.7182818284590452,    -2.3025850929940457,     0.1,                       PAL_EPSILON },          // x: e     y: -(ln(10))
+        {  2.7182818284590452,    -1.5707963267948966,     0.20787957635076191,       PAL_EPSILON },          // x: e     y: -(pi / 2)
+        {  2.7182818284590452,    -1.4426950408889634,     0.23629008834452270,       PAL_EPSILON },          // x: e     y: -(log2(e))
+        {  2.7182818284590452,    -1.4142135623730950,     0.24311673443421421,       PAL_EPSILON },          // x: e     y: -(sqrt(2))
+        {  2.7182818284590452,    -1.1283791670955126,     0.32355726390307110,       PAL_EPSILON },          // x: e     y: -(2 / sqrt(pi))
+        {  2.7182818284590452,    -1,                      0.36787944117144232,       PAL_EPSILON },          // x: e     y: -(1)
+        {  2.7182818284590452,    -0.78539816339744831,    0.45593812776599624,       PAL_EPSILON },          // x: e     y: -(pi / 4)
+        {  2.7182818284590452,    -0.70710678118654752,    0.49306869139523979,       PAL_EPSILON },          // x: e     y: -(1 / sqrt(2))
+        {  2.7182818284590452,    -0.69314718055994531,    0.5,                       PAL_EPSILON },          // x: e     y: -(ln(2))
+        {  2.7182818284590452,    -0.63661977236758134,    0.52907780826773535,       PAL_EPSILON },          // x: e     y: -(2 / pi)
+        {  2.7182818284590452,    -0.43429448190325183,    0.64772148514180065,       PAL_EPSILON },          // x: e     y: -(log10(e))
+        {  2.7182818284590452,    -0.31830988618379067,    0.72737734929521647,       PAL_EPSILON },          // x: e     y: -(1 / pi)
+        {  2.7182818284590452,     0,                      1,                         PAL_EPSILON * 10 },     // x: e
+        {  2.7182818284590452,     0.31830988618379067,    1.3748022274393586,        PAL_EPSILON * 10 },     // x: e     y:  1 / pi
+        {  2.7182818284590452,     0.43429448190325183,    1.5438734439711811,        PAL_EPSILON * 10 },     // x: e     y:  log10(e)
+        {  2.7182818284590452,     0.63661977236758134,    1.8900811645722220,        PAL_EPSILON * 10 },     // x: e     y:  2 / pi
+        {  2.7182818284590452,     0.69314718055994531,    2,                         PAL_EPSILON * 10 },     // x: e     y:  ln(2)
+        {  2.7182818284590452,     0.70710678118654752,    2.0281149816474725,        PAL_EPSILON * 10 },     // x: e     y:  1 / sqrt(2)
+        {  2.7182818284590452,     0.78539816339744831,    2.1932800507380155,        PAL_EPSILON * 10 },     // x: e     y:  pi / 4
+        {  2.7182818284590452,     1,                      2.7182818284590452,        PAL_EPSILON * 10 },     // x: e                         expected: e
+        {  2.7182818284590452,     1.1283791670955126,     3.0906430223107976,        PAL_EPSILON * 10 },     // x: e     y:  2 / sqrt(pi)
+        {  2.7182818284590452,     1.4142135623730950,     4.1132503787829275,        PAL_EPSILON * 10 },     // x: e     y:  sqrt(2)
+        {  2.7182818284590452,     1.4426950408889634,     4.2320861065570819,        PAL_EPSILON * 10 },     // x: e     y:  log2(e)
+        {  2.7182818284590452,     1.5707963267948966,     4.8104773809653517,        PAL_EPSILON * 10 },     // x: e     y:  pi / 2
+        {  2.7182818284590452,     2.3025850929940457,     10,                        PAL_EPSILON * 100 },    // x: e     y:  ln(10)
+        {  2.7182818284590452,     2.7182818284590452,     15.154262241479264,        PAL_EPSILON * 100 },    // x: e     y:  e
+        {  2.7182818284590452,     3.1415926535897932,     23.140692632779269,        PAL_EPSILON * 100 },    // x: e     y:  pi
+        {  2.7182818284590452,     PAL_POSINF,             PAL_POSINF,                0 },                    // x: e
+        
+        {  10,                     PAL_NEGINF,             0,                         0 },
+        {  10,                    -3.1415926535897932,     0.00072178415907472774,    PAL_EPSILON / 1000 },   //          y: -(pi)
+        {  10,                    -2.7182818284590452,     0.0019130141022243176,     PAL_EPSILON / 100 },    //          y: -(e)
+        {  10,                    -2.3025850929940457,     0.0049821282964407206,     PAL_EPSILON / 100 },    //          y: -(ln(10))
+        {  10,                    -1.5707963267948966,     0.026866041001136132,      PAL_EPSILON / 10 },     //          y: -(pi / 2)
+        {  10,                    -1.4426950408889634,     0.036083192820787210,      PAL_EPSILON / 10 },     //          y: -(log2(e))
+        {  10,                    -1.4142135623730950,     0.038528884700322026,      PAL_EPSILON / 10 },     //          y: -(sqrt(2))
+        {  10,                    -1.1283791670955126,     0.074408205860642723,      PAL_EPSILON / 10 },     //          y: -(2 / sqrt(pi))
+        {  10,                    -1,                      0.1,                       PAL_EPSILON },          //          y: -(1)
+        {  10,                    -0.78539816339744831,    0.16390863613957665,       PAL_EPSILON },          //          y: -(pi / 4)
+        {  10,                    -0.70710678118654752,    0.19628775993505562,       PAL_EPSILON },          //          y: -(1 / sqrt(2))
+        {  10,                    -0.69314718055994531,    0.20269956628651730,       PAL_EPSILON },          //          y: -(ln(2))
+        {  10,                    -0.63661977236758134,    0.23087676451600055,       PAL_EPSILON },          //          y: -(2 / pi)
+        {  10,                    -0.43429448190325183,    0.36787944117144232,       PAL_EPSILON },          //          y: -(log10(e))
+        {  10,                    -0.31830988618379067,    0.48049637305186868,       PAL_EPSILON },          //          y: -(1 / pi)
+        {  10,                     0,                      1,                         PAL_EPSILON * 10 },
+        {  10,                     0.31830988618379067,    2.0811811619898573,        PAL_EPSILON * 10 },     //          y:  1 / pi
+        {  10,                     0.43429448190325183,    2.7182818284590452,        PAL_EPSILON * 10 },     //          y:  log10(e)           expected: e
+        {  10,                     0.63661977236758134,    4.3313150290214525,        PAL_EPSILON * 10 },     //          y:  2 / pi
+        {  10,                     0.69314718055994531,    4.9334096679145963,        PAL_EPSILON * 10 },     //          y:  ln(2)
+        {  10,                     0.70710678118654752,    5.0945611704512962,        PAL_EPSILON * 10 },     //          y:  1 / sqrt(2)
+        {  10,                     0.78539816339744831,    6.1009598002416937,        PAL_EPSILON * 10 },     //          y:  pi / 4
+        {  10,                     1,                      10,                        PAL_EPSILON * 100 },
+        {  10,                     1.1283791670955126,     13.439377934644400,        PAL_EPSILON * 100 },    //          y:  2 / sqrt(pi)
+        {  10,                     1.4142135623730950,     25.954553519470081,        PAL_EPSILON * 100 },    //          y:  sqrt(2)
+        {  10,                     1.4426950408889634,     27.713733786437790,        PAL_EPSILON * 100 },    //          y:  log2(e)
+        {  10,                     1.5707963267948966,     37.221710484165167,        PAL_EPSILON * 100 },    //          y:  pi / 2
+        {  10,                     2.3025850929940457,     200.71743249053009,        PAL_EPSILON * 1000 },   //          y:  ln(10)
+        {  10,                     2.7182818284590452,     522.73529967043665,        PAL_EPSILON * 1000 },   //          y:  e
+        {  10,                     3.1415926535897932,     1385.4557313670111,        PAL_EPSILON * 10000 },  //          y:  pi
+        {  10,                     PAL_POSINF,             PAL_POSINF,                0 },
+        
+        {  PAL_POSINF,             PAL_NEGINF,             0,                         PAL_EPSILON },
+        {  PAL_POSINF,             PAL_POSINF,             PAL_POSINF,                0 },
+    };
+
+    if (PAL_Initialize(argc, argv) != 0)
     {
         return FAIL;
     }
 
-    /* Loop through each case. Call pow on each value and check the 
-       result.
-    */
-    for(i = 0; i < sizeof(testCases) / sizeof(struct testCase); i++)
+    for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
     {
-        result = pow(testCases[i].Number, testCases[i].Exponent);
-        testDelta = fabs(result - testCases[i].CorrectValue);
-
-        if ( testDelta >= DELTA )
-        {
-            Fail("ERROR: pow took the '%f' to the exponent '%f' "
-                 "to be %f instead of %f.\n", 
-                 testCases[i].Number, 
-                 testCases[i].Exponent, 
-                 result, 
-                 testCases[i].CorrectValue);
-        }
+        validate(tests[i].x, tests[i].y, tests[i].expected, tests[i].variance);
     }
 
+    validate_isnan(-10, -1.5707963267948966);                                                                 //          y: -(pi / 2)
+    validate_isnan(-10, -0.78539816339744828);                                                                //          y: -(pi / 4)
+    validate_isnan(-10,  0.78539816339744828);                                                                //          y:   pi / 4
+    validate_isnan(-10,  1.5707963267948966);                                                                 //          y:   pi / 2
+    
+    validate_isnan(-2.7182818284590452, -1.5707963267948966);                                                 // x: -(e)  y: -(pi / 2)
+    validate_isnan(-2.7182818284590452, -0.78539816339744828);                                                // x: -(e)  y: -(pi / 4)
+    validate_isnan(-2.7182818284590452,  0.78539816339744828);                                                // x: -(e)  y:   pi / 4
+    validate_isnan(-2.7182818284590452,  1.5707963267948966);                                                 // x: -(e)  y:   pi / 2
+    
+    validate_isnan(PAL_NEGINF, PAL_NAN);
+    validate_isnan(PAL_NAN,    PAL_NEGINF);
+    
+    validate_isnan(PAL_POSINF, PAL_NAN);
+    validate_isnan(PAL_NAN,    PAL_POSINF);
+    
+    validate_isnan(PAL_NAN, PAL_NAN);
+
     PAL_Terminate();
     return PASS;
 }
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/pal/tests/palsuite/c_runtime/pow/test2/test2.c b/src/pal/tests/palsuite/c_runtime/pow/test2/test2.c
deleted file mode 100644 (file)
index 5d713c5..0000000
+++ /dev/null
@@ -1,214 +0,0 @@
-// 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.
-
-/*=====================================================================
-**
-** Source:  test2.c
-**
-** Purpose:  Call the pow function with various values, 
-**           to test special in/out values.
-**
-**
-**===================================================================*/
-
-/* Notes: The following table summarizes expected results:
-          NUMBER       EXPONENT            RETURNS   CASE
-          PosInf       > 0                 PosInf     1 
-          PosInf       < 0                 0          2
-          NegInf       > 0 (even int)      PosInf     3
-          NegInf       > 0 (odd int)       NegInf     4
-          NegInf       < 0 (odd int)       0          5
-          NegInf       < 0 (even int)      0          6
-          |num| > 1    PosInf              PosInf     7
-          |num| < 1    PosInf              0          8
-          |num| > 1    NegInf              0          9
-          |num| < 1    NegInf              PosInf    10
-          +1           PosInf              NaN       11
-          +1           NegInf              NaN       12
-          < 0          non-int             NaN       13
-          0            < 0 (odd int)       NegInf    14
-          0            < 0 (even int)      PosInf    15
-          Large        Large               PosInf    16
-          -Large       Large               NegInf    17
-          Large        -Large              0         18
-          -Large       -Large              0         19
-*/
-
-#include <palsuite.h>
-
-struct testCase
-{
-    double Number;
-    double Exponent;
-};
-
-int __cdecl main(int argc, char **argv)
-{
-    double zero = 0.0;
-    double PosInf = 1.0 / zero;
-    double NegInf = -1.0 / zero;
-    double NaN = 0.0 / zero;
-    volatile double result=0;
-    int i=0;
-
-    struct testCase retPosInf[] =
-        {                                              /* CASE */
-            {PosInf,         .3123                },   /*  1   */
-            {PosInf,         3123                 },   /*  1   */
-            {PosInf,         31.23                },   /*  1   */
-            {NegInf,         2                    },   /*  3   */
-            {NegInf,         3576                 },   /*  3   */
-            {1.1,            PosInf               },   /*  7   */
-            {6.2315,         PosInf               },   /*  7   */
-            {423511,         PosInf               },   /*  7   */
-            {-1.1,           PosInf               },   /*  7   */
-            {-6.2315,        PosInf               },   /*  7   */
-            {-423511,        PosInf               },   /*  7   */
-            {0.1234,         NegInf               },   /* 10   */
-            {-0.134,         NegInf               },   /* 10   */
-            {0.1234,         NegInf               },   /* 10   */
-            {0,              -1                   },   /* 14   */
-            {0,              -3                   },   /* 14   */
-            {0,              -1324391351          },   /* 14   */
-            {0,              -2                   },   /* 15   */
-            {0,              -35798               },   /* 15   */
-            {MAXLONG,       MAXLONG               }    /* 16   */
-        };
-
-    struct testCase retNegInf[] =
-        {
-            {NegInf,         1                    },   /*  4   */
-            {NegInf,         1324391315           },   /*  4   */
-            {-(MAXLONG),     MAXLONG              }    /* 17   */
-        };
-
-    struct testCase retNaN[] =
-        {
-            {1,              PosInf               },   /*  11  */
-            {1,              NegInf               },   /*  12  */
-            {-1,             -0.1                 },   /*  13  */
-            {-0.1,           -0.1                 },   /*  13  */
-            {-1324391351,    -0.1                 },   /*  13  */
-            {-3124.391351,   -0.1                 },   /*  13  */
-            {-1,             0.1                  },   /*  13  */
-            {-0.1,           0.1                  },   /*  13  */
-            {-1324391351,    0.1                  },   /*  13  */
-            {-3124.391351,   0.1                  }    /*  13  */
-        };
-
-    struct testCase retZero[] =
-        {
-            {PosInf,         -0.323               },   /*  2   */
-            {PosInf,         -1                   },   /*  2   */
-            {PosInf,         -1324391351          },   /*  2   */
-            {PosInf,         -3124.391351         },   /*  2   */
-            {NegInf,         -1                   },   /*  5   */
-            {NegInf,         -3                   },   /*  5   */
-            {NegInf,         -1324391351          },   /*  5   */
-            {NegInf,         -2                   },   /*  6   */
-            {NegInf,         -4                   },   /*  6   */
-            {NegInf,         -1243913514          },   /*  6   */
-            {0.132,          PosInf               },   /*  8   */
-            {-0.132,         PosInf               },   /*  8   */
-            {1.1,            NegInf               },   /*  9   */
-            {-1.1,           NegInf               },   /*  9   */
-            {2,              NegInf               },   /*  9   */
-            {3,              NegInf               },   /*  9   */
-            {-1324391353,    NegInf               },   /*  9   */
-            {1324391354,     NegInf               },   /*  9   */
-            {-31.24391353,   NegInf               },   /*  9   */
-            {31.24391353,    NegInf               },   /*  9   */
-            {MAXLONG,       -(MAXLONG)            },   /* 18   */
-            {-(MAXLONG),    -(MAXLONG)            }    /* 19   */
-        };
-
-
-    if (0 != (PAL_Initialize(argc, argv)))
-    {
-        return FAIL;
-    }
-
-    /* Loop through each case. Call pow on each number/exponent pair 
-       and check the result.
-    */
-    /* First those test cases returning positive infinity.          */
-    for(i = 0; i < sizeof(retPosInf) / sizeof(struct testCase); i++)
-    {
-        result = pow(retPosInf[i].Number, retPosInf[i].Exponent);
-
-        if ( result != PosInf )
-        {
-            Fail("ERROR: pow took '%f' to the exponent '%f' "
-                 "to be %f instead of %f.\n", 
-                 retPosInf[i].Number, 
-                 retPosInf[i].Exponent, 
-                 result, 
-                 PosInf);
-        }
-    }
-
-    /* First those test cases returning negative infinity.          */
-    for(i = 0; i < sizeof(retNegInf) / sizeof(struct testCase); i++)
-    {
-        result = pow(retNegInf[i].Number, retNegInf[i].Exponent);
-
-        if ( result != NegInf )
-        {
-            Fail("ERROR: pow took '%f' to the exponent '%f' "
-                 "to be %f instead of %f.\n", 
-                 retNegInf[i].Number, 
-                 retNegInf[i].Exponent, 
-                 result, 
-                 NegInf);
-        }
-    }
-
-    /* First those test cases returning non-numbers.          */
-    for(i = 0; i < sizeof(retNaN) / sizeof(struct testCase); i++)
-    {
-        result = pow(retNaN[i].Number, retNaN[i].Exponent);
-
-        if ( ! _isnan(result) )
-        {
-            Fail("ERROR: pow took '%f' to the exponent '%f' "
-                 "to be %f instead of %f.\n", 
-                 retNaN[i].Number, 
-                 retNaN[i].Exponent, 
-                 result, 
-                 NaN);
-        }
-    }
-
-    /* First those test cases returning zero.          */
-    for(i = 0; i < sizeof(retZero) / sizeof(struct testCase); i++)
-    {
-        result = pow(retZero[i].Number, retZero[i].Exponent);
-
-        if ( result != 0)
-        {
-            Fail("ERROR: pow took '%f' to the exponent '%f' "
-                 "to be %f instead of %f.\n", 
-                 retZero[i].Number, 
-                 retZero[i].Exponent, 
-                 result, 
-                 0.0);
-        }
-    }
-
-    PAL_Terminate();
-    return PASS;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/pal/tests/palsuite/c_runtime/pow/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/pow/test2/testinfo.dat
deleted file mode 100644 (file)
index 205baa8..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-# 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.
-
-Version = 1.0
-Section = C Runtime
-Function = pow
-Name = Call pow with special input and output.
-TYPE = DEFAULT
-EXE1 = test2
-Description
-= Call the pow function with special input values or with
-= values that produce special output such as non-numbers
-= infinity or negative infinity.
-
diff --git a/src/pal/tests/palsuite/c_runtime/pow/test3/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/pow/test3/CMakeLists.txt
deleted file mode 100644 (file)
index 414c3ba..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-cmake_minimum_required(VERSION 2.8.12.2)
-
-set(CMAKE_INCLUDE_CURRENT_DIR ON)
-
-set(SOURCES
-  test3.c
-)
-
-add_executable(paltest_pow_test3
-  ${SOURCES}
-)
-
-add_dependencies(paltest_pow_test3 coreclrpal)
-
-target_link_libraries(paltest_pow_test3
-  pthread
-  m
-  coreclrpal
-)
diff --git a/src/pal/tests/palsuite/c_runtime/pow/test3/test3.c b/src/pal/tests/palsuite/c_runtime/pow/test3/test3.c
deleted file mode 100644 (file)
index d01710b..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-// 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.
-
-/*=============================================================================
-**
-** Source: test3.c
-**
-** Purpose: Test to ensure that pow returns correct values.
-** 
-** Dependencies: PAL_Initialize
-**               PAL_Terminate
-**                              Fail
-**               fabs
-**               _finite
-**               _isnan
-** 
-
-**
-**===========================================================================*/
-
-#include <palsuite.h>
-
-#define DELTA 0.0000001  /* Error acceptance level to the 7th decimal */
-
-/**
- * Helper test structure
- */
-struct test1
-{
-    double value;       /* value to test the function with */
-    double exponent;    /* exponent to test */
-    double result;      /* expected result */
-};
-
-struct test2
-{
-    double value;       /* value to test the function with */
-    double exponent;    /* exponent to test */
-};
-
-
-/**
- * main
- * 
- * executable entry point
- */
-int __cdecl main(int argc, char **argv)
-{
-    int i;
-    double result;
-
-    struct test1 tests[] = 
-    {
-        /* Value        test result */
-        { 0.0, 0.0, 1.0 },
-        { 4.2, 0.0, 1.0 },
-        { 2.0, 3.0, 8.0 },
-        { 0.1, 3.25, 0.000562341325 },
-        { 1.0, 4.0, 1.000000000000 },
-        { 2.4, -6.8, 0.002597547849 },
-        { 3.75, 10.4, 933093.543524607670 },
-        { 7.63, -4.521, 0.000102354411 },
-        { 10, 5, 100000.000000000000 },
-        { 13.26, -2.11, 0.004279895490 },
-        { 18.1, 3.763, 54031.183101303657 },
-        { 25, 4.0001, 390750.757575723810 },
-        { 29.31, -5.997, 0.000000001593 }
-    };
-
-    struct test2 infinite[] =
-    {
-        { 0.0, -2.5 },
-        { 0.0, -1 }
-    };
-
-
-    /* PAL initialization */
-    if( PAL_Initialize(argc, argv) != 0 )
-    {
-           return (FAIL);
-    }
-
-    for( i = 0; i < sizeof(tests) / sizeof(struct test1); i++)
-    {
-        double testDelta;
-
-        result = pow( tests[i].value, tests[i].exponent );
-
-        /* The test is valid when the difference between the */
-        /* result and the expectation is less than DELTA */
-        testDelta = fabs( result - tests[i].result );
-        if( testDelta >= DELTA )
-        {
-            Fail( "pow(%g,%g) returned %20.10g"
-                  " when it should have returned %20.10g\n",
-                  tests[i].value,
-                  tests[i].exponent,
-                  result, 
-                  tests[i].result );
-        }
-    }
-
-    for( i = 0; i < sizeof(infinite) / sizeof(struct test2); i++)
-    {
-        result = pow( infinite[i].value, infinite[i].exponent );
-
-        /* The test is valid when the function returns an infinite result */
-        if( _finite( result ) )
-        {
-            Fail( "pow(%g,%g) returned %20.10g"
-                  " when it should have returned 1.#INF00000000",
-                  infinite[i].value,
-                  infinite[i].exponent,
-                  result );
-        }
-    }
-
-    PAL_Terminate();
-    return PASS;
-}
index 701856b..bec58d4 100644 (file)
 ** 
 ** Dependencies: PAL_Initialize
 **               PAL_Terminate
-**                              Fail
+**               Fail
 **               fabs
-** 
-
 **
 **===========================================================================*/
 
 #include <palsuite.h>
 
-#define DELTA 0.0000001 /* Error acceptance level to the 7th decimal */
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this 
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN     sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF  log(0.0)
 
 /**
  * Helper test structure
  */
 struct test
 {
-    double value;   /* value to test the function with */
-    double result;  /* expected result */
+    double value;     /* value to test the function with */
+    double expected;  /* expected result */
+    double variance;  /* maximum delta between the expected and actual result */
 };
 
 /**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+    double result = sin(value);
+
+    /*
+     * The test is valid when the difference between result
+     * and expected is less than or equal to variance
+     */
+    double delta = fabs(result - expected);
+
+    if (delta > variance)
+    {
+        Fail("sin(%g) returned %20.17g when it should have returned %20.17g",
+             value, result, expected);
+    }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+    double result = sin(value);
+
+    if (!_isnan(result))
+    {
+        Fail("sin(%g) returned %20.17g when it should have returned %20.17g",
+             value, result, PAL_NAN);
+    }
+}
+
+/**
  * main
  * 
  * executable entry point
  */
-INT __cdecl main(INT argc, CHAR **argv)
+int __cdecl main(int argc, char **argv)
 {
-    double pi = 3.1415926535;
-    int i;
-
     struct test tests[] = 
     {
-        /* Value        test result */
-        { 0,                0 },
-        { pi/2.0,           1 },
-        { pi,               0 },
-        { (3.0*pi) / 2.0,  -1 },
-        { 2.0 * pi,         0 },
-        { 5.0*pi/2.0,       1 },
-        { 3.0*pi,           0 },
-        { (7.0*pi) / 2.0,  -1 },
-        { 4.0 * pi,         0 }
+        /* value                   expected                variance */
+        {  0,                      0,                      PAL_EPSILON },
+        {  0.31830988618379067,    0.31296179620778659,    PAL_EPSILON },       // value:  1 / pi
+        {  0.43429448190325183,    0.42077048331375735,    PAL_EPSILON },       // value:  log10(e)
+        {  0.63661977236758134,    0.59448076852482208,    PAL_EPSILON },       // value:  2 / pi
+        {  0.69314718055994531,    0.63896127631363480,    PAL_EPSILON },       // value:  ln(2)
+        {  0.70710678118654752,    0.64963693908006244,    PAL_EPSILON },       // value:  1 / sqrt(2)
+        {  0.78539816339744831,    0.70710678118654752,    PAL_EPSILON },       // value:  pi / 4,         expected: 1 / sqrt(2)
+        {  1,                      0.84147098480789651,    PAL_EPSILON },
+        {  1.1283791670955126,     0.90371945743584630,    PAL_EPSILON },       // value:  2 / sqrt(pi)
+        {  1.4142135623730950,     0.98776594599273553,    PAL_EPSILON },       // value:  sqrt(2)
+        {  1.4426950408889634,     0.99180624439366372,    PAL_EPSILON },       // value:  log2(e)
+        {  1.5707963267948966,     1,                      PAL_EPSILON * 10 },  // value:  pi / 2
+        {  2.3025850929940457,     0.74398033695749319,    PAL_EPSILON },       // value:  ln(10)
+        {  2.7182818284590452,     0.41078129050290870,    PAL_EPSILON },       // value:  e
+        {  3.1415926535897932,     0,                      PAL_EPSILON },       // value:  pi
     };
 
-
     /* PAL initialization */
-    if( PAL_Initialize(argc, argv) != 0 )
+    if (PAL_Initialize(argc, argv) != 0)
     {
-           return (FAIL);
+        return FAIL;
     }
 
-    for( i = 0; i < sizeof(tests) / sizeof(struct test); i++)
+    for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
     {
-        double result;
-        double testDelta;
-
-
-        result = sin( tests[i].value );
-
-        /*
-         * The test is valid when the difference between the
-         * result and the expectation is less than DELTA
-         */
-        testDelta = fabs( result - tests[i].result );
-        if( testDelta >= DELTA )
-        {
-            Fail( "sin(%g) returned %g"
-                  " when it should have returned %g",
-                  tests[i].value,
-                  result, 
-                  tests[i].result );
-        }
+        validate( tests[i].value,  tests[i].expected, tests[i].variance);
+        validate(-tests[i].value, -tests[i].expected, tests[i].variance);
     }
+    
+    validate_isnan(PAL_NEGINF);
+    validate_isnan(PAL_NAN);
+    validate_isnan(PAL_POSINF);
 
     PAL_Terminate();
     return PASS;
 }
-
-
-
-
-
-
-
-
-
-
-
-
-
index 05c49d6..57eae6b 100644 (file)
@@ -11,6 +11,3 @@ EXE1 = test1
 Description
 = Passes to sin() a series of angle value, checking that
 = each one return to correct value.
-
-
-
index c4cc54e..e790b16 100644 (file)
 ** 
 ** Dependencies: PAL_Initialize
 **               PAL_Terminate
-**                              Fail
+**               Fail
 **               fabs
-** 
-
 **
 **===========================================================================*/
 
 #include <palsuite.h>
 
-#define DELTA 0.0000001 /*Error acceptance level to the 7th decimal */
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this 
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN     sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF  log(0.0)
 
 /**
  * Helper test structure
  */
 struct test
 {
-    double value;   /* value to test the function with */
-    double result;  /* expected result */
+    double value;     /* value to test the function with */
+    double expected;  /* expected result */
+    double variance;  /* maximum delta between the expected and actual result */
 };
 
 /**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+    double result = sinh(value);
+
+    /*
+     * The test is valid when the difference between result
+     * and expected is less than or equal to variance
+     */
+    double delta = fabs(result - expected);
+
+    if (delta > variance)
+    {
+        Fail("sinh(%g) returned %20.17g when it should have returned %20.17g",
+             value, result, expected);
+    }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+    double result = sinh(value);
+
+    if (!_isnan(result))
+    {
+        Fail("sinh(%g) returned %20.17g when it should have returned %20.17g",
+             value, result, PAL_NAN);
+    }
+}
+
+/**
  * main
  * 
  * executable entry point
  */
-INT __cdecl main(INT argc, CHAR **argv)
+int __cdecl main(int argc, char **argv)
 {
-    double pi = 3.1415926535;
-    int i;
-
     struct test tests[] = 
     {
-        /* Value        test result */
-        { 0,                0 },
-        { pi/2.0,           2.3012989 },
-        { pi,               11.5487394 },
-        { (3.0*pi) / 2.0,   55.6543976 },
-        { 2.0 * pi,         267.7448940 },
-        { 5.0*pi/2.0,       1287.9850539 },
-        { 3.0*pi,           6195.8238619 },
-        { (7.0*pi) / 2.0,   29804.8707287 },
-        { 4.0 * pi,         143375.6565151 }
+        /* value                   expected                variance */
+        {  0,                      0,                      PAL_EPSILON },
+        {  0.31830988618379067,    0.32371243907207108,    PAL_EPSILON },           // value:  1 / pi
+        {  0.43429448190325183,    0.44807597941469025,    PAL_EPSILON },           // value:  log10(e)
+        {  0.63661977236758134,    0.68050167815224332,    PAL_EPSILON },           // value:  2 / pi
+        {  0.69314718055994531,    0.75,                   PAL_EPSILON },           // value:  ln(2)
+        {  0.70710678118654752,    0.76752314512611633,    PAL_EPSILON },           // value:  1 / sqrt(2)
+        {  0.78539816339744831,    0.86867096148600961,    PAL_EPSILON },           // value:  pi / 4
+        {  1,                      1.1752011936438015,     PAL_EPSILON * 10 },
+        {  1.1283791670955126,     1.3835428792038633,     PAL_EPSILON * 10 },      // value:  2 / sqrt(pi)
+        {  1.4142135623730950,     1.9350668221743567,     PAL_EPSILON * 10 },      // value:  sqrt(2)
+        {  1.4426950408889634,     1.9978980091062796,     PAL_EPSILON * 10 },      // value:  log2(e)
+        {  1.5707963267948966,     2.3012989023072949,     PAL_EPSILON * 10 },      // value:  pi / 2
+        {  2.3025850929940457,     4.95,                   PAL_EPSILON * 10 },      // value:  ln(10)
+        {  2.7182818284590452,     7.5441371028169758,     PAL_EPSILON * 10 },      // value:  e
+        {  3.1415926535897932,     11.548739357257748,     PAL_EPSILON * 100 },     // value:  pi
+        {  PAL_POSINF,             PAL_POSINF,             0 },
     };
 
-
     /* PAL initialization */
-    if( PAL_Initialize(argc, argv) != 0 )
+    if (PAL_Initialize(argc, argv) != 0)
     {
-           return (FAIL);
+        return FAIL;
     }
 
-    for( i = 0; i < sizeof(tests) / sizeof(struct test); i++)
+    for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
     {
-        double result;
-        double testDelta;
-
-
-        result = sinh( tests[i].value );
-
-        /*
-         * The test is valid when the difference between the
-         * result and the expectation is less than DELTA
-         */
-        testDelta = fabs( result - tests[i].result );
-        if( testDelta >= DELTA )
-        {
-            Fail( "sinh(%g) returned %g"
-                  " when it should have returned %g",
-                  tests[i].value,
-                  result, 
-                  tests[i].result );
-        }
+        validate( tests[i].value,  tests[i].expected, tests[i].variance);
+        validate(-tests[i].value, -tests[i].expected, tests[i].variance);
     }
+    
+    validate_isnan(PAL_NAN);
 
     PAL_Terminate();
     return PASS;
 }
-
-
-
-
-
-
-
-
-
-
-
-
-
index ecffb06..f7aee40 100644 (file)
@@ -11,6 +11,3 @@ EXE1 = test1
 Description
 = Passes to sinh() a series of angle value, checking that
 = each one return to correct value.
-
-
-
index 028dc2c..62d2251 100644 (file)
 **
 **===================================================================*/
 
-/* Note: Calling sqrt on anything negative gives indefinite results. */
-
 #include <palsuite.h>
 
-struct testCase
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this 
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN     sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF  log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
 {
-    double Value;
-    double CorrectValue;
+    double value;     /* value to test the function with */
+    double expected;  /* expected result */
+    double variance;  /* maximum delta between the expected and actual result */
 };
 
-int __cdecl main(int argc, char **argv)
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
 {
-    double delta;
-    double result=0;
-    int i=0;
+    double result = sqrt(value);
 
-    struct testCase testCases[] =
-        {
-            {100,  10},
-            {6.25, 2.5},
-            {0,    0},
-            {1.7e+308, 1.3038404810405297e+154} /* Max Double value */
-        };
+    /*
+     * The test is valid when the difference between result
+     * and expected is less than or equal to variance
+     */
+    double delta = fabs(result - expected);
 
-    if (0 != (PAL_Initialize(argc, argv)))
+    if (delta > variance)
     {
-        return FAIL;
+        Fail("sqrt(%g) returned %20.17g when it should have returned %20.17g",
+             value, result, expected);
     }
+}
 
-    /* Loop through each case. Call sqrt on each value and check the 
-       result.
-    */
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+    double result = sqrt(value);
+
+    if (!_isnan(result))
+    {
+        Fail("sqrt(%g) returned %20.17g when it should have returned %20.17g",
+             value, result, PAL_NAN);
+    }
+}
 
-    for(i = 0; i < sizeof(testCases) / sizeof(struct testCase); i++)
+int __cdecl main(int argc, char **argv)
+{
+    struct test tests[] = 
     {
-        result = sqrt(testCases[i].Value);
-        delta = pow(10, log10(testCases[i].Value) - 7);
+        /* value                   expected                variance */
+        {  0.31830988618379067,    0.56418958354775629,    PAL_EPSILON },       // value:  1 / pi
+        {  0.43429448190325183,    0.65901022898226081,    PAL_EPSILON },       // value:  log10(e)
+        {  0.63661977236758134,    0.79788456080286536,    PAL_EPSILON },       // value:  2 / pi
+        {  0.69314718055994531,    0.83255461115769776,    PAL_EPSILON },       // value:  ln(2)
+        {  0.70710678118654752,    0.84089641525371454,    PAL_EPSILON },       // value:  1 / sqrt(2)
+        {  0.78539816339744831,    0.88622692545275801,    PAL_EPSILON },       // value:  pi / 4
+        {  1,                      1,                      PAL_EPSILON * 10 },
+        {  1.1283791670955126,     1.0622519320271969,     PAL_EPSILON * 10 },  // value:  2 / sqrt(pi)
+        {  1.4142135623730950,     1.1892071150027211,     PAL_EPSILON * 10 },  // value:  sqrt(2)
+        {  1.4426950408889634,     1.2011224087864498,     PAL_EPSILON * 10 },  // value:  log2(e)
+        {  1.5707963267948966,     1.2533141373155003,     PAL_EPSILON * 10 },  // value:  pi / 2
+        {  2.3025850929940457,     1.5174271293851464,     PAL_EPSILON * 10 },  // value:  ln(10)
+        {  2.7182818284590452,     1.6487212707001281,     PAL_EPSILON * 10 },  // value:  e
+        {  3.1415926535897932,     1.7724538509055160,     PAL_EPSILON * 10 },  // value:  pi
+    };
+
+    /* PAL initialization */
+    if (PAL_Initialize(argc, argv) != 0)
+    {
+        return FAIL;
+    }
+    
+    validate(-0.0, -0.0, PAL_EPSILON);
+    validate( 0.0,  0.0, PAL_EPSILON);
 
-        if (fabs(testCases[i].CorrectValue - result) > delta)
-        {
-            Fail("ERROR: sqrt took the square root of '%f' to be '%f' "
-                 "instead of %f.\n", 
-                 testCases[i].Value, 
-                 result, 
-                 testCases[i].CorrectValue);
-        }
+    for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
+    {
+        validate(tests[i].value, tests[i].expected, tests[i].variance);
+        validate_isnan(-tests[i].value);
     }
+    
+    validate_isnan(PAL_NAN);
 
     PAL_Terminate();
     return PASS;
 }
-
-
-
-
-
-
-
-
-
-
-
-
-
index f30daca..443e5da 100644 (file)
 ** 
 ** Dependencies: PAL_Initialize
 **               PAL_Terminate
-**                              Fail
+**               Fail
 **               fabs
-** 
-
 **
 **===========================================================================*/
 
 #include <palsuite.h>
 
-#define DELTA 0.0000001 /*Error acceptance level to the 7th decimal */
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this 
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN     sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF  log(0.0)
 
 /**
  * Helper test structure
  */
 struct test
 {
-    double value;   /* value to test the function with */
-    double result;  /* expected result */
+    double value;     /* value to test the function with */
+    double expected;  /* expected result */
+    double variance;  /* maximum delta between the expected and actual result */
 };
 
 /**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+    double result = tan(value);
+
+    /*
+     * The test is valid when the difference between result
+     * and expected is less than or equal to variance
+     */
+    double delta = fabs(result - expected);
+
+    if (delta > variance)
+    {
+        Fail("tan(%g) returned %20.17g when it should have returned %20.17g",
+             value, result, expected);
+    }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+    double result = tan(value);
+
+    if (!_isnan(result))
+    {
+        Fail("tan(%g) returned %20.17g when it should have returned %20.17g",
+             value, result, PAL_NAN);
+    }
+}
+
+/**
  * main
  * 
  * executable entry point
  */
-INT __cdecl main(INT argc, CHAR **argv)
+int __cdecl main(int argc, char **argv)
 {
-    int i;
-
     struct test tests[] = 
     {
-        /* Value        test result */
-        { 0.001,          0.001 },
-        { 0.05,           0.050041708 },
-        { 0.5,            0.54630249 },
-        { 1,              1.557407725 },
-        { 2,             -2.185039863 },
-        { 3,             -0.142546543 },
-        { 4,              1.157821282 }
+        /* value                   expected                variance */
+        {  0,                      0,                      PAL_EPSILON },
+        {  0.31830988618379067,    0.32951473309607836,    PAL_EPSILON },       // value:  1 / pi
+        {  0.43429448190325183,    0.46382906716062964,    PAL_EPSILON },       // value:  log10(e)
+        {  0.63661977236758134,    0.73930295048660405,    PAL_EPSILON },       // value:  2 / pi
+        {  0.69314718055994531,    0.83064087786078395,    PAL_EPSILON },       // value:  ln(2)
+        {  0.70710678118654752,    0.85451043200960189,    PAL_EPSILON },       // value:  1 / sqrt(2)
+        {  0.78539816339744831,    1,                      PAL_EPSILON * 10 },  // value:  pi / 4
+        {  1,                      1.5574077246549022,     PAL_EPSILON * 10 },
+        {  1.1283791670955126,     2.1108768356626451,     PAL_EPSILON * 10 },  // value:  2 / sqrt(pi)
+        {  1.4142135623730950,     6.3341191670421916,     PAL_EPSILON * 10 },  // value:  sqrt(2)
+        {  1.4426950408889634,     7.7635756709721848,     PAL_EPSILON * 10 },  // value:  log2(e)
+    // SEE BELOW -- {  1.5707963267948966,     PAL_POSINF,             0 },                 // value:  pi / 2
+        {  2.3025850929940457,    -1.1134071468135374,     PAL_EPSILON * 10 },  // value:  ln(10)
+        {  2.7182818284590452,    -0.45054953406980750,    PAL_EPSILON },       // value:  e
+        {  3.1415926535897932,     0,                      PAL_EPSILON },       // value:  pi
     };
 
-
     /* PAL initialization */
-    if( PAL_Initialize(argc, argv) != 0 )
+    if (PAL_Initialize(argc, argv) != 0)
     {
-           return (FAIL);
+        return FAIL;
     }
 
-    for( i = 0; i < sizeof(tests) / sizeof(struct test); i++)
+    for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
     {
-        double result;
-        double testDelta;
-
-
-        result = tan( tests[i].value );
-
-        /*
-         * The test is valid when the difference between the
-         * result and the expectation is less than DELTA
-         */
-        testDelta = fabs( result - tests[i].result );
-        if( testDelta >= DELTA )
-        {
-            Fail( "tan(%g) returned %g"
-                  " when it should have returned %g",
-                  tests[i].value,
-                  result, 
-                  tests[i].result );
-        }
+        validate( tests[i].value,  tests[i].expected, tests[i].variance);
+        validate(-tests[i].value, -tests[i].expected, tests[i].variance);
     }
+    
+    // -- SPECIAL CASE --
+    // Normally, tan(pi / 2) would return PAL_POSINF (atan2(PAL_POSINF) does return (pi / 2)).
+    // However, it seems instead (on all supported systems), we get a different number entirely.
+    validate( 1.5707963267948966,  16331239353195370.0, 0);
+    validate(-1.5707963267948966, -16331239353195370.0, 0);
+    
+    validate_isnan(PAL_NEGINF);
+    validate_isnan(PAL_NAN);
+    validate_isnan(PAL_POSINF);
 
     PAL_Terminate();
     return PASS;
 }
-
-
-
-
-
-
-
-
-
-
-
-
-
index 26546d3..05d6cfe 100644 (file)
@@ -11,6 +11,3 @@ EXE1 = test1
 Description
 = Passes to tan() a series of angle value, checking that
 = each one return to correct value.
-
-
-
index f3452e8..3b8f879 100644 (file)
 ** 
 ** Dependencies: PAL_Initialize
 **               PAL_Terminate
-**                              Fail
+**               Fail
 **               fabs
-** 
-
 **
 **===========================================================================*/
 
 #include <palsuite.h>
 
-#define DELTA 0.0000001 /* Error acceptance level to the 7th decimal */
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this 
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN     sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF  log(0.0)
 
 /**
  * Helper test structure
  */
 struct test
 {
-    double value;   /* value to test the function with */
-    double result;  /* expected result */
+    double value;     /* value to test the function with */
+    double expected;  /* expected result */
+    double variance;  /* maximum delta between the expected and actual result */
 };
 
 /**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+    double result = tanh(value);
+
+    /*
+     * The test is valid when the difference between result
+     * and expected is less than or equal to variance
+     */
+    double delta = fabs(result - expected);
+
+    if (delta > variance)
+    {
+        Fail("tanh(%g) returned %20.17g when it should have returned %20.17g",
+             value, result, expected);
+    }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+    double result = tanh(value);
+
+    if (!_isnan(result))
+    {
+        Fail("tanh(%g) returned %20.17g when it should have returned %20.17g",
+             value, result, PAL_NAN);
+    }
+}
+
+/**
  * main
  * 
  * executable entry point
  */
-INT __cdecl main(INT argc, CHAR **argv)
+int __cdecl main(int argc, char **argv)
 {
-    double pi = 3.1415926535;
-    int i;
-
     struct test tests[] = 
     {
-        /* Value        test result */
-        { 0,                0 },
-        { pi/2.0,           0.9171523 },
-        { pi,               0.9962721 },
-        { (3.0*pi) / 2.0,   0.9998386 },
-        { 2.0 * pi,         0.9999930 },
-        { 5.0*pi/2.0,       0.9999997 },
-        { 3.0*pi,           1 },
-        { (7.0*pi) / 2.0,   1 },
-        { 4.0 * pi,         1 }
+        /* value                   expected                variance */
+        {  0,                      0,                      PAL_EPSILON },
+        {  0.31830988618379067,    0.30797791269089433,    PAL_EPSILON },       // value:  1 / pi
+        {  0.43429448190325183,    0.40890401183401433,    PAL_EPSILON },       // value:  log10(e)
+        {  0.63661977236758134,    0.56259360033158334,    PAL_EPSILON },       // value:  2 / pi
+        {  0.69314718055994531,    0.6,                    PAL_EPSILON },       // value:  ln(2)
+        {  0.70710678118654752,    0.60885936501391381,    PAL_EPSILON },       // value:  1 / sqrt(2)
+        {  0.78539816339744831,    0.65579420263267244,    PAL_EPSILON },       // value:  pi / 4
+        {  1,                      0.76159415595576489,    PAL_EPSILON },
+        {  1.1283791670955126,     0.81046380599898809,    PAL_EPSILON },       // value:  2 / sqrt(pi)
+        {  1.4142135623730950,     0.88838556158566054,    PAL_EPSILON },       // value:  sqrt(2)
+        {  1.4426950408889634,     0.89423894585503855,    PAL_EPSILON },       // value:  log2(e)
+        {  1.5707963267948966,     0.91715233566727435,    PAL_EPSILON },       // value:  pi / 2
+        {  2.3025850929940457,     0.98019801980198020,    PAL_EPSILON },       // value:  ln(10)
+        {  2.7182818284590452,     0.99132891580059984,    PAL_EPSILON },       // value:  e
+        {  3.1415926535897932,     0.99627207622074994,    PAL_EPSILON },       // value:  pi
+        {  PAL_POSINF,             1,                      PAL_EPSILON * 10 }
     };
 
-
     /* PAL initialization */
-    if( PAL_Initialize(argc, argv) != 0 )
+    if (PAL_Initialize(argc, argv) != 0)
     {
-           return (FAIL);
+        return FAIL;
     }
 
-    for( i = 0; i < sizeof(tests) / sizeof(struct test); i++)
+    for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
     {
-        double result;
-        double testDelta;
-
-
-        result = tanh( tests[i].value );
-
-        /*
-         * The test is valid when the difference between the
-         * result and the expectation is less than DELTA
-         */
-        testDelta = fabs( result - tests[i].result );
-        if( testDelta >= DELTA )
-        {
-            Fail( "tanh(%g) returned %g"
-                  " when it should have returned %g",
-                  tests[i].value,
-                  result, 
-                  tests[i].result );
-        }
+        validate( tests[i].value,  tests[i].expected, tests[i].variance);
+        validate(-tests[i].value, -tests[i].expected, tests[i].variance);
     }
+    
+    validate_isnan(PAL_NAN);
 
     PAL_Terminate();
     return PASS;
 }
-
-
-
-
-
-
-
-
-
-
-
-
-
index 6af765c..1b2bc91 100644 (file)
@@ -11,6 +11,3 @@ EXE1 = test1
 Description
 = Passes to tanh() a series of angle value, checking that
 = each one return to correct value.
-
-
-
index 83cfc4d..d0a76e9 100644 (file)
@@ -15,9 +15,8 @@ c_runtime/errno/test1/paltest_errno_test1
 c_runtime/errno/test2/paltest_errno_test2
 c_runtime/exit/test1/paltest_exit_test1
 c_runtime/exp/test1/paltest_exp_test1
-c_runtime/exp/test2/paltest_exp_test2
-c_runtime/exp/test3/paltest_exp_test3
 c_runtime/fabs/test1/paltest_fabs_test1
+c_runtime/fabsf/test1/paltest_fabsf_test1
 c_runtime/fclose/test1/paltest_fclose_test1
 c_runtime/fclose/test2/paltest_fclose_test2
 c_runtime/fflush/test1/paltest_fflush_test1
@@ -26,6 +25,7 @@ c_runtime/fgets/test2/paltest_fgets_test2
 c_runtime/fgets/test3/paltest_fgets_test3
 c_runtime/floor/test1/paltest_floor_test1
 c_runtime/fmod/test1/paltest_fmod_test1
+c_runtime/fmodf/test1/paltest_fmodf_test1
 c_runtime/fopen/test1/paltest_fopen_test1
 c_runtime/fopen/test2/paltest_fopen_test2
 c_runtime/fopen/test3/paltest_fopen_test3
@@ -102,9 +102,8 @@ c_runtime/memcpy/test1/paltest_memcpy_test1
 c_runtime/memmove/test1/paltest_memmove_test1
 c_runtime/memset/test1/paltest_memset_test1
 c_runtime/modf/test1/paltest_modf_test1
+c_runtime/modff/test1/paltest_modff_test1
 c_runtime/pow/test1/paltest_pow_test1
-c_runtime/pow/test2/paltest_pow_test2
-c_runtime/pow/test3/paltest_pow_test3
 c_runtime/printf/test1/paltest_printf_test1
 c_runtime/printf/test10/paltest_printf_test10
 c_runtime/printf/test11/paltest_printf_test11
index e667714..36b48d6 100644 (file)
@@ -139,9 +139,8 @@ c_runtime/errno/test1,1
 c_runtime/errno/test2,1
 c_runtime/exit/test1,1
 c_runtime/exp/test1,1
-c_runtime/exp/test2,1
-c_runtime/exp/test3,1
 c_runtime/fabs/test1,1
+c_runtime/fabsf/test1,1
 c_runtime/fclose/test1,1
 c_runtime/fclose/test2,1
 c_runtime/feof/test1,1
@@ -153,6 +152,7 @@ c_runtime/fgets/test2,1
 c_runtime/fgets/test3,1
 c_runtime/floor/test1,1
 c_runtime/fmod/test1,1
+c_runtime/fmodf/test1,1
 c_runtime/fopen/test1,1
 c_runtime/fopen/test2,1
 c_runtime/fopen/test3,1
@@ -238,8 +238,6 @@ c_runtime/memmove/test1,1
 c_runtime/memset/test1,1
 c_runtime/modf/test1,1
 c_runtime/pow/test1,1
-c_runtime/pow/test2,1
-c_runtime/pow/test3,1
 c_runtime/printf/test1,1
 c_runtime/printf/test2,1
 c_runtime/printf/test3,1
index 9018520..f004be5 100644 (file)
@@ -916,40 +916,6 @@ NESTED_ENTRY JIT_Stelem_Ref__ArrayStoreCheck_Helper, _TEXT
 NESTED_END JIT_Stelem_Ref__ArrayStoreCheck_Helper, _TEXT
 
 
-; Equivalent of x86's c++ /fp:fast sin/cos/tan helpers, on x64 
-
-; public: static double __fastcall COMDouble::Sin(double)
-LEAF_ENTRY ?Sin@COMDouble@@SANN@Z, _TEXT
-        movsd   qword ptr [rsp + 8h], xmm0
-        fld     qword ptr [rsp + 8h]
-        fsin
-        fstp    qword ptr [rsp + 8h]    
-        movsd   xmm0, qword ptr [rsp + 8h]
-        ret
-LEAF_END ?Sin@COMDouble@@SANN@Z, _TEXT
-
-; public: static double __fastcall COMDouble::Cos(double)
-LEAF_ENTRY ?Cos@COMDouble@@SANN@Z, _TEXT
-        movsd   qword ptr [rsp + 8h], xmm0
-        fld     qword ptr [rsp + 8h]
-        fcos
-        fstp    qword ptr [rsp + 8h]
-        movsd   xmm0, qword ptr [rsp + 8h]
-        ret
-LEAF_END ?Cos@COMDouble@@SANN@Z, _TEXT
-
-; public: static double __fastcall COMDouble::Tan(double)
-LEAF_ENTRY ?Tan@COMDouble@@SANN@Z, _TEXT
-        movsd   qword ptr [rsp + 8h], xmm0
-        fld     qword ptr [rsp + 8h]
-        fptan
-        fstp    st(0)
-        fstp    qword ptr [rsp + 8h]
-        movsd   xmm0, qword ptr [rsp + 8h]
-        ret
-LEAF_END ?Tan@COMDouble@@SANN@Z, _TEXT
-
-
 extern JIT_FailFast:proc
 extern s_gsCookie:qword
 
index dc9c432..8675ddd 100644 (file)
@@ -1234,31 +1234,27 @@ FCFuncStart(gDelegateFuncs)
 FCFuncEnd()
 
 FCFuncStart(gMathFuncs)
-    FCIntrinsic("Sin", COMDouble::Sin, CORINFO_INTRINSIC_Sin)
+    FCIntrinsicSig("Abs", &gsig_SM_Dbl_RetDbl, COMDouble::Abs, CORINFO_INTRINSIC_Abs)
+    FCIntrinsicSig("Abs", &gsig_SM_Flt_RetFlt, COMSingle::Abs, CORINFO_INTRINSIC_Abs)
+    FCIntrinsic("Acos", COMDouble::Acos, CORINFO_INTRINSIC_Acos)
+    FCIntrinsic("Asin", COMDouble::Asin, CORINFO_INTRINSIC_Asin)
+    FCIntrinsic("Atan", COMDouble::Atan, CORINFO_INTRINSIC_Atan)
+    FCIntrinsic("Atan2", COMDouble::Atan2, CORINFO_INTRINSIC_Atan2)
+    FCIntrinsic("Ceiling", COMDouble::Ceil, CORINFO_INTRINSIC_Ceiling)
     FCIntrinsic("Cos", COMDouble::Cos, CORINFO_INTRINSIC_Cos)
-    FCIntrinsic("Sqrt", COMDouble::Sqrt, CORINFO_INTRINSIC_Sqrt)
-    FCIntrinsic("Round", COMDouble::Round, CORINFO_INTRINSIC_Round)
-    FCIntrinsicSig("Abs", &gsig_SM_Flt_RetFlt, COMDouble::AbsFlt, CORINFO_INTRINSIC_Abs)
-    FCIntrinsicSig("Abs", &gsig_SM_Dbl_RetDbl, COMDouble::AbsDbl, CORINFO_INTRINSIC_Abs)
+    FCIntrinsic("Cosh", COMDouble::Cosh, CORINFO_INTRINSIC_Cosh)
     FCIntrinsic("Exp", COMDouble::Exp, CORINFO_INTRINSIC_Exp)
-    FCIntrinsic("Pow", COMDouble::Pow, CORINFO_INTRINSIC_Pow)
-#if defined(_TARGET_X86_)
-    FCUnreferenced FCFuncElement("PowHelperSimple", COMDouble::PowHelperSimple)
-    FCUnreferenced FCFuncElement("PowHelper", COMDouble::PowHelper)
-#endif
-    FCIntrinsic("Tan", COMDouble::Tan, CORINFO_INTRINSIC_Tan)
     FCIntrinsic("Floor", COMDouble::Floor, CORINFO_INTRINSIC_Floor)
     FCFuncElement("Log", COMDouble::Log)
+    FCIntrinsic("Log10", COMDouble::Log10, CORINFO_INTRINSIC_Log10)
+    FCIntrinsic("Pow", COMDouble::Pow, CORINFO_INTRINSIC_Pow)
+    FCIntrinsic("Round", COMDouble::Round, CORINFO_INTRINSIC_Round)
+    FCIntrinsic("Sin", COMDouble::Sin, CORINFO_INTRINSIC_Sin)
     FCIntrinsic("Sinh", COMDouble::Sinh, CORINFO_INTRINSIC_Sinh)
-    FCIntrinsic("Cosh", COMDouble::Cosh, CORINFO_INTRINSIC_Cosh)
+    FCFuncElement("SplitFractionDouble", COMDouble::ModF)
+    FCIntrinsic("Sqrt", COMDouble::Sqrt, CORINFO_INTRINSIC_Sqrt)
+    FCIntrinsic("Tan", COMDouble::Tan, CORINFO_INTRINSIC_Tan)
     FCIntrinsic("Tanh", COMDouble::Tanh, CORINFO_INTRINSIC_Tanh)
-    FCIntrinsic("Acos", COMDouble::Acos, CORINFO_INTRINSIC_Acos)
-    FCIntrinsic("Asin", COMDouble::Asin, CORINFO_INTRINSIC_Asin)
-    FCIntrinsic("Atan", COMDouble::Atan, CORINFO_INTRINSIC_Atan)
-    FCIntrinsic("Atan2", COMDouble::Atan2, CORINFO_INTRINSIC_Atan2)
-    FCIntrinsic("Log10", COMDouble::Log10, CORINFO_INTRINSIC_Log10)
-    FCIntrinsic("Ceiling", COMDouble::Ceil, CORINFO_INTRINSIC_Ceiling)
-    FCFuncElement("SplitFractionDouble", COMDouble::ModFDouble)
 FCFuncEnd()
 
 FCFuncStart(gThreadFuncs)
index 91e2a10..7681028 100644 (file)
@@ -43,7 +43,8 @@
 #include "system.h"
 #include "comutilnative.h"
 #include "comsynchronizable.h"
-#include "floatclass.h"
+#include "floatdouble.h"
+#include "floatsingle.h"
 #include "decimal.h"
 #include "currency.h"
 #include "comdatetime.h"
diff --git a/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/AbsDouble.cs b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/AbsDouble.cs
new file mode 100644 (file)
index 0000000..6429a39
--- /dev/null
@@ -0,0 +1,48 @@
+// 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.
+
+using System;
+using Microsoft.Xunit.Performance;
+
+namespace Functions
+{
+    public static partial class MathTests
+    {
+        // Tests Math.Abs(double) over 5000 iterations for the domain -1, +1
+
+        private const double absDoubleDelta = 0.0004;
+        private const double absDoubleExpectedResult = 2499.9999999999659;
+
+        [Benchmark]
+        public static void AbsDoubleBenchmark()
+        {
+            foreach (var iteration in Benchmark.Iterations)
+            {
+                using (iteration.StartMeasurement())
+                {
+                    AbsDoubleTest();
+                }
+            }
+        }
+
+        public static void AbsDoubleTest()
+        {
+            var result = 0.0; var value = -1.0;
+
+            for (var iteration = 0; iteration < iterations; iteration++)
+            {
+                value += absDoubleDelta;
+                result += Math.Abs(value);
+            }
+
+            var diff = Math.Abs(absDoubleExpectedResult - result);
+
+            if (diff > doubleEpsilon)
+            {
+                throw new Exception($"Expected Result {absDoubleExpectedResult}; Actual Result {result}");
+            }
+        }
+    }
+
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/AcosDouble.cs b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/AcosDouble.cs
new file mode 100644 (file)
index 0000000..3ba2867
--- /dev/null
@@ -0,0 +1,47 @@
+// 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.
+
+using System;
+using Microsoft.Xunit.Performance;
+
+namespace Functions
+{
+    public static partial class MathTests
+    {
+        // Tests Math.Acos(double) over 5000 iterations for the domain -1, +1
+
+        private const double acosDoubleDelta = 0.0004;
+        private const double acosDoubleExpectedResult = 7852.4108380716079;
+
+        [Benchmark]
+        public static void AcosDoubleBenchmark()
+        {
+            foreach (var iteration in Benchmark.Iterations)
+            {
+                using (iteration.StartMeasurement())
+                {
+                    AcosDoubleTest();
+                }
+            }
+        }
+
+        public static void AcosDoubleTest()
+        {
+            var result = 0.0; var value = -1.0;
+
+            for (var iteration = 0; iteration < iterations; iteration++)
+            {
+                value += acosDoubleDelta;
+                result += Math.Acos(value);
+            }
+
+            var diff = Math.Abs(acosDoubleExpectedResult - result);
+
+            if (diff > doubleEpsilon)
+            {
+                throw new Exception($"Expected Result {acosDoubleExpectedResult}; Actual Result {result}");
+            }
+        }
+    }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/AsinDouble.cs b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/AsinDouble.cs
new file mode 100644 (file)
index 0000000..030756c
--- /dev/null
@@ -0,0 +1,47 @@
+// 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.
+
+using System;
+using Microsoft.Xunit.Performance;
+
+namespace Functions
+{
+    public static partial class MathTests
+    {
+        // Tests Math.Asin(double) over 5000 iterations for the domain -1, +1
+
+        private const double asinDoubleDelta = 0.0004;
+        private const double asinDoubleExpectedResult = 1.5707959028763392;
+
+        [Benchmark]
+        public static void AsinDoubleBenchmark()
+        {
+            foreach (var iteration in Benchmark.Iterations)
+            {
+                using (iteration.StartMeasurement())
+                {
+                    AsinDoubleTest();
+                }
+            }
+        }
+
+        public static void AsinDoubleTest()
+        {
+            var result = 0.0; var value = -1.0;
+
+            for (var iteration = 0; iteration < iterations; iteration++)
+            {
+                value += asinDoubleDelta;
+                result += Math.Asin(value);
+            }
+
+            var diff = Math.Abs(asinDoubleExpectedResult - result);
+
+            if (diff > doubleEpsilon)
+            {
+                throw new Exception($"Expected Result {asinDoubleExpectedResult}; Actual Result {result}");
+            }
+        }
+    }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/Atan2Double.cs b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/Atan2Double.cs
new file mode 100644 (file)
index 0000000..82831e6
--- /dev/null
@@ -0,0 +1,48 @@
+// 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.
+
+using System;
+using Microsoft.Xunit.Performance;
+
+namespace Functions
+{
+    public static partial class MathTests
+    {
+        // Tests Math.Atan2(double, double) over 5000 iterations for the domain y: -1, +1; x: +1, -1
+
+        private const double atan2DoubleDeltaX = -0.0004;
+        private const double atan2DoubleDeltaY = 0.0004;
+        private const double atan2DoubleExpectedResult = 3926.99081698702;
+
+        [Benchmark]
+        public static void Atan2DoubleBenchmark()
+        {
+            foreach (var iteration in Benchmark.Iterations)
+            {
+                using (iteration.StartMeasurement())
+                {
+                    Atan2DoubleTest();
+                }
+            }
+        }
+
+        public static void Atan2DoubleTest()
+        {
+            var result = 0.0; var valueX = 1.0; var valueY = -1.0;
+
+            for (var iteration = 0; iteration < iterations; iteration++)
+            {
+                valueX += atan2DoubleDeltaX; valueY += atan2DoubleDeltaY;
+                result += Math.Atan2(valueY, valueX);
+            }
+
+            var diff = Math.Abs(atan2DoubleExpectedResult - result);
+
+            if (diff > doubleEpsilon)
+            {
+                throw new Exception($"Expected Result {atan2DoubleExpectedResult}; Actual Result {result}");
+            }
+        }
+    }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/AtanDouble.cs b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/AtanDouble.cs
new file mode 100644 (file)
index 0000000..ec2ebe3
--- /dev/null
@@ -0,0 +1,47 @@
+// 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.
+
+using System;
+using Microsoft.Xunit.Performance;
+
+namespace Functions
+{
+    public static partial class MathTests
+    {
+        // Tests Math.Atan(double) over 5000 iterations for the domain -1, +1
+
+        private const double atanDoubleDelta = 0.0004;
+        private const double atanDoubleExpectedResult = 0.78539816322061329;
+
+        [Benchmark]
+        public static void AtanDoubleBenchmark()
+        {
+            foreach (var iteration in Benchmark.Iterations)
+            {
+                using (iteration.StartMeasurement())
+                {
+                    AtanDoubleTest();
+                }
+            }
+        }
+
+        public static void AtanDoubleTest()
+        {
+            var result = 0.0; var value = -1.0;
+
+            for (var iteration = 0; iteration < iterations; iteration++)
+            {
+                value += atanDoubleDelta;
+                result += Math.Atan(value);
+            }
+
+            var diff = Math.Abs(atanDoubleExpectedResult - result);
+
+            if (diff > doubleEpsilon)
+            {
+                throw new Exception($"Expected Result {atanDoubleExpectedResult}; Actual Result {result}");
+            }
+        }
+    }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/CeilingDouble.cs b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/CeilingDouble.cs
new file mode 100644 (file)
index 0000000..f822aae
--- /dev/null
@@ -0,0 +1,47 @@
+// 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.
+
+using System;
+using Microsoft.Xunit.Performance;
+
+namespace Functions
+{
+    public static partial class MathTests
+    {
+        // Tests Math.Ceiling(double) over 5000 iterations for the domain -1, +1
+
+        private const double ceilingDoubleDelta = 0.0004;
+        private const double ceilingDoubleExpectedResult = 2500;
+
+        [Benchmark]
+        public static void CeilingDoubleBenchmark()
+        {
+            foreach (var iteration in Benchmark.Iterations)
+            {
+                using (iteration.StartMeasurement())
+                {
+                    CeilingDoubleTest();
+                }
+            }
+        }
+
+        public static void CeilingDoubleTest()
+        {
+            var result = 0.0; var value = -1.0;
+
+            for (var iteration = 0; iteration < iterations; iteration++)
+            {
+                value += ceilingDoubleDelta;
+                result += Math.Ceiling(value);
+            }
+
+            var diff = Math.Abs(ceilingDoubleExpectedResult - result);
+
+            if (diff > doubleEpsilon)
+            {
+                throw new Exception($"Expected Result {ceilingDoubleExpectedResult}; Actual Result {result}");
+            }
+        }
+    }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/CosDouble.cs b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/CosDouble.cs
new file mode 100644 (file)
index 0000000..e95ab5c
--- /dev/null
@@ -0,0 +1,47 @@
+// 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.
+
+using System;
+using Microsoft.Xunit.Performance;
+
+namespace Functions
+{
+    public static partial class MathTests
+    {
+        // Tests Math.Cos(double) over 5000 iterations for the domain 0, PI
+
+        private const double cosDoubleDelta = 0.0006283185307180;
+        private const double cosDoubleExpectedResult = -1.0000000005924159;
+
+        [Benchmark]
+        public static void CosDoubleBenchmark()
+        {
+            foreach (var iteration in Benchmark.Iterations)
+            {
+                using (iteration.StartMeasurement())
+                {
+                    CosDoubleTest();
+                }
+            }
+        }
+
+        public static void CosDoubleTest()
+        {
+            var result = 0.0; var value = 0.0;
+
+            for (var iteration = 0; iteration < iterations; iteration++)
+            {
+                value += cosDoubleDelta;
+                result += Math.Cos(value);
+            }
+
+            var diff = Math.Abs(cosDoubleExpectedResult - result);
+
+            if (diff > doubleEpsilon)
+            {
+                throw new Exception($"Expected Result {cosDoubleExpectedResult}; Actual Result {result}");
+            }
+        }
+    }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/CoshDouble.cs b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/CoshDouble.cs
new file mode 100644 (file)
index 0000000..c8b7fb6
--- /dev/null
@@ -0,0 +1,47 @@
+// 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.
+
+using System;
+using Microsoft.Xunit.Performance;
+
+namespace Functions
+{
+    public static partial class MathTests
+    {
+        // Tests Math.Cosh(double) over 5000 iterations for the domain -1, +1
+
+        private const double coshDoubleDelta = 0.0004;
+        private const double coshDoubleExpectedResult = 5876.0060465657216;
+
+        [Benchmark]
+        public static void CoshDoubleBenchmark()
+        {
+            foreach (var iteration in Benchmark.Iterations)
+            {
+                using (iteration.StartMeasurement())
+                {
+                    CoshDoubleTest();
+                }
+            }
+        }
+
+        public static void CoshDoubleTest()
+        {
+            var result = 0.0; var value = -1.0;
+
+            for (var iteration = 0; iteration < iterations; iteration++)
+            {
+                value += coshDoubleDelta;
+                result += Math.Cosh(value);
+            }
+
+            var diff = Math.Abs(coshDoubleExpectedResult - result);
+
+            if (diff > doubleEpsilon)
+            {
+                throw new Exception($"Expected Result {coshDoubleExpectedResult}; Actual Result {result}");
+            }
+        }
+    }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/ExpDouble.cs b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/ExpDouble.cs
new file mode 100644 (file)
index 0000000..64be839
--- /dev/null
@@ -0,0 +1,47 @@
+// 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.
+
+using System;
+using Microsoft.Xunit.Performance;
+
+namespace Functions
+{
+    public static partial class MathTests
+    {
+        // Tests Math.Exp(double) over 5000 iterations for the domain -1, +1
+
+        private const double expDoubleDelta = 0.0004;
+        private const double expDoubleExpectedResult = 5877.1812477590884;
+
+        [Benchmark]
+        public static void ExpDoubleBenchmark()
+        {
+            foreach (var iteration in Benchmark.Iterations)
+            {
+                using (iteration.StartMeasurement())
+                {
+                    ExpDoubleTest();
+                }
+            }
+        }
+
+        public static void ExpDoubleTest()
+        {
+            var result = 0.0; var value = -1.0;
+
+            for (var iteration = 0; iteration < iterations; iteration++)
+            {
+                value += expDoubleDelta;
+                result += Math.Exp(value);
+            }
+
+            var diff = Math.Abs(expDoubleExpectedResult - result);
+
+            if (diff > doubleEpsilon)
+            {
+                throw new Exception($"Expected Result {expDoubleExpectedResult}; Actual Result {result}");
+            }
+        }
+    }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/FloorDouble.cs b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/FloorDouble.cs
new file mode 100644 (file)
index 0000000..4d4b4f2
--- /dev/null
@@ -0,0 +1,47 @@
+// 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.
+
+using System;
+using Microsoft.Xunit.Performance;
+
+namespace Functions
+{
+    public static partial class MathTests
+    {
+        // Tests Math.Floor(double) over 5000 iterations for the domain -1, +1
+
+        private const double floorDoubleDelta = 0.0004;
+        private const double floorDoubleExpectedResult = -2500;
+
+        [Benchmark]
+        public static void FloorDoubleBenchmark()
+        {
+            foreach (var iteration in Benchmark.Iterations)
+            {
+                using (iteration.StartMeasurement())
+                {
+                    FloorDoubleTest();
+                }
+            }
+        }
+
+        public static void FloorDoubleTest()
+        {
+            var result = 0.0; var value = -1.0;
+
+            for (var iteration = 0; iteration < iterations; iteration++)
+            {
+                value += floorDoubleDelta;
+                result += Math.Floor(value);
+            }
+
+            var diff = Math.Abs(floorDoubleExpectedResult - result);
+
+            if (diff > doubleEpsilon)
+            {
+                throw new Exception($"Expected Result {floorDoubleExpectedResult}; Actual Result {result}");
+            }
+        }
+    }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/Log10Double.cs b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/Log10Double.cs
new file mode 100644 (file)
index 0000000..330d8a7
--- /dev/null
@@ -0,0 +1,47 @@
+// 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.
+
+using System;
+using Microsoft.Xunit.Performance;
+
+namespace Functions
+{
+    public static partial class MathTests
+    {
+        // Tests Math.Log10(double) over 5000 iterations for the domain -1, +1
+
+        private const double log10DoubleDelta = 0.0004;
+        private const double log10DoubleExpectedResult = -664.07384902184072;
+
+        [Benchmark]
+        public static void Log10DoubleBenchmark()
+        {
+            foreach (var iteration in Benchmark.Iterations)
+            {
+                using (iteration.StartMeasurement())
+                {
+                    Log10DoubleTest();
+                }
+            }
+        }
+
+        public static void Log10DoubleTest()
+        {
+            var result = 0.0; var value = 0.0;
+
+            for (var iteration = 0; iteration < iterations; iteration++)
+            {
+                value += log10DoubleDelta;
+                result += Math.Log10(value);
+            }
+
+            var diff = Math.Abs(log10DoubleExpectedResult - result);
+
+            if (diff > doubleEpsilon)
+            {
+                throw new Exception($"Expected Result {log10DoubleExpectedResult}; Actual Result {result}");
+            }
+        }
+    }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/LogDouble.cs b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/LogDouble.cs
new file mode 100644 (file)
index 0000000..bddb84b
--- /dev/null
@@ -0,0 +1,48 @@
+// 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.
+
+using System;
+using Microsoft.Xunit.Performance;
+
+namespace Functions
+{
+    public static partial class MathTests
+    {
+        // Tests Math.Log(double) over 5000 iterations for the domain -1, +1
+
+        private const double logDoubleDelta = 0.0004;
+        private const double logDoubleExpectedResult = -1529.0865454048721;
+
+        [Benchmark]
+        public static void LogDoubleBenchmark()
+        {
+            foreach (var iteration in Benchmark.Iterations)
+            {
+                using (iteration.StartMeasurement())
+                {
+                    LogDoubleTest();
+                }
+            }
+        }
+
+        public static void LogDoubleTest()
+        {
+            var result = 0.0; var value = 0.0;
+
+            for (var iteration = 0; iteration < iterations; iteration++)
+            {
+                value += logDoubleDelta;
+                result += Math.Log(value);
+            }
+
+            var diff = Math.Abs(logDoubleExpectedResult - result);
+
+            if (diff > doubleEpsilon)
+            {
+                throw new Exception($"Expected Result {logDoubleExpectedResult}; Actual Result {result}");
+            }
+        }
+    }
+
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/PowDouble.cs b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/PowDouble.cs
new file mode 100644 (file)
index 0000000..c824807
--- /dev/null
@@ -0,0 +1,48 @@
+// 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.
+
+using System;
+using Microsoft.Xunit.Performance;
+
+namespace Functions
+{
+    public static partial class MathTests
+    {
+        // Tests Math.Pow(double, double) over 5000 iterations for the domain x: +2, +1; y: -2, -1
+
+        private const double powDoubleDeltaX = -0.0004;
+        private const double powDoubleDeltaY = 0.0004;
+        private const double powDoubleExpectedResult = 4659.4627376138733;
+
+        [Benchmark]
+        public static void PowDoubleBenchmark()
+        {
+            foreach (var iteration in Benchmark.Iterations)
+            {
+                using (iteration.StartMeasurement())
+                {
+                    PowDoubleTest();
+                }
+            }
+        }
+
+        public static void PowDoubleTest()
+        {
+            var result = 0.0; var valueX = 2.0; var valueY = -2.0;
+
+            for (var iteration = 0; iteration < iterations; iteration++)
+            {
+                valueX += powDoubleDeltaX; valueY += powDoubleDeltaY;
+                result += Math.Pow(valueX, valueY);
+            }
+
+            var diff = Math.Abs(powDoubleExpectedResult - result);
+
+            if (diff > doubleEpsilon)
+            {
+                throw new Exception($"Expected Result {powDoubleExpectedResult}; Actual Result {result}");
+            }
+        }
+    }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/RoundDouble.cs b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/RoundDouble.cs
new file mode 100644 (file)
index 0000000..9c5dcc9
--- /dev/null
@@ -0,0 +1,47 @@
+// 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.
+
+using System;
+using Microsoft.Xunit.Performance;
+
+namespace Functions
+{
+    public static partial class MathTests
+    {
+        // Tests Math.Round(double) over 5000 iterations for the domain -PI/2, +PI/2
+
+        private const double roundDoubleDelta = 0.0006283185307180;
+        private const double roundDoubleExpectedResult = 2;
+
+        [Benchmark]
+        public static void RoundDoubleBenchmark()
+        {
+            foreach (var iteration in Benchmark.Iterations)
+            {
+                using (iteration.StartMeasurement())
+                {
+                    RoundDoubleTest();
+                }
+            }
+        }
+
+        public static void RoundDoubleTest()
+        {
+            var result = 0.0; var value = -1.5707963267948966;
+
+            for (var iteration = 0; iteration < iterations; iteration++)
+            {
+                value += roundDoubleDelta;
+                result += Math.Round(value);
+            }
+
+            var diff = Math.Abs(roundDoubleExpectedResult - result);
+
+            if (diff > doubleEpsilon)
+            {
+                throw new Exception($"Expected Result {roundDoubleExpectedResult}; Actual Result {result}");
+            }
+        }
+    }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/SinDouble.cs b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/SinDouble.cs
new file mode 100644 (file)
index 0000000..73886aa
--- /dev/null
@@ -0,0 +1,47 @@
+// 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.
+
+using System;
+using Microsoft.Xunit.Performance;
+
+namespace Functions
+{
+    public static partial class MathTests
+    {
+        // Tests Math.Sin(double) over 5000 iterations for the domain -PI/2, +PI/2
+
+        private const double sinDoubleDelta = 0.0006283185307180;
+        private const double sinDoubleExpectedResult = 1.0000000005445053;
+
+        [Benchmark]
+        public static void SinDoubleBenchmark()
+        {
+            foreach (var iteration in Benchmark.Iterations)
+            {
+                using (iteration.StartMeasurement())
+                {
+                    SinDoubleTest();
+                }
+            }
+        }
+
+        public static void SinDoubleTest()
+        {
+            var result = 0.0; var value = -1.5707963267948966;
+
+            for (var iteration = 0; iteration < iterations; iteration++)
+            {
+                value += sinDoubleDelta;
+                result += Math.Sin(value);
+            }
+
+            var diff = Math.Abs(sinDoubleExpectedResult - result);
+
+            if (diff > doubleEpsilon)
+            {
+                throw new Exception($"Expected Result {sinDoubleExpectedResult}; Actual Result {result}");
+            }
+        }
+    }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/SinhDouble.cs b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/SinhDouble.cs
new file mode 100644 (file)
index 0000000..8f79cc9
--- /dev/null
@@ -0,0 +1,47 @@
+// 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.
+
+using System;
+using Microsoft.Xunit.Performance;
+
+namespace Functions
+{
+    public static partial class MathTests
+    {
+        // Tests Math.Sinh(double) over 5000 iterations for the domain -1, +1
+
+        private const double sinhDoubleDelta = 0.0004;
+        private const double sinhDoubleExpectedResult = 1.17520119337903;
+
+        [Benchmark]
+        public static void SinhDoubleBenchmark()
+        {
+            foreach (var iteration in Benchmark.Iterations)
+            {
+                using (iteration.StartMeasurement())
+                {
+                    SinhDoubleTest();
+                }
+            }
+        }
+
+        public static void SinhDoubleTest()
+        {
+            var result = 0.0; var value = -1.0;
+
+            for (var iteration = 0; iteration < iterations; iteration++)
+            {
+                value += sinhDoubleDelta;
+                result += Math.Sinh(value);
+            }
+
+            var diff = Math.Abs(sinhDoubleExpectedResult - result);
+
+            if (diff > doubleEpsilon)
+            {
+                throw new Exception($"Expected Result {sinhDoubleExpectedResult}; Actual Result {result}");
+            }
+        }
+    }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/SqrtDouble.cs b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/SqrtDouble.cs
new file mode 100644 (file)
index 0000000..5d9e554
--- /dev/null
@@ -0,0 +1,47 @@
+// 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.
+
+using System;
+using Microsoft.Xunit.Performance;
+
+namespace Functions
+{
+    public static partial class MathTests
+    {
+        // Tests Math.Sqrt(double) over 5000 iterations for the domain 0, PI
+
+        private const double sqrtDoubleDelta = 0.0006283185307180;
+        private const double sqrtDoubleExpectedResult = 5909.0605337797215;
+
+        [Benchmark]
+        public static void SqrtDoubleBenchmark()
+        {
+            foreach (var iteration in Benchmark.Iterations)
+            {
+                using (iteration.StartMeasurement())
+                {
+                    SqrtDoubleTest();
+                }
+            }
+        }
+
+        public static void SqrtDoubleTest()
+        {
+            var result = 0.0; var value = 0.0;
+
+            for (var iteration = 0; iteration < iterations; iteration++)
+            {
+                value += sqrtDoubleDelta;
+                result += Math.Sqrt(value);
+            }
+
+            var diff = Math.Abs(sqrtDoubleExpectedResult - result);
+
+            if (diff > doubleEpsilon)
+            {
+                throw new Exception($"Expected Result {sqrtDoubleExpectedResult}; Actual Result {result}");
+            }
+        }
+    }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/TanDouble.cs b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/TanDouble.cs
new file mode 100644 (file)
index 0000000..6988c67
--- /dev/null
@@ -0,0 +1,47 @@
+// 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.
+
+using System;
+using Microsoft.Xunit.Performance;
+
+namespace Functions
+{
+    public static partial class MathTests
+    {
+        // Tests Math.Tan(double) over 5000 iterations for the domain -PI/2, +PI/2
+
+        private const double tanDoubleDelta = 0.0004;
+        private const double tanDoubleExpectedResult = 1.5574077243051505;
+
+        [Benchmark]
+        public static void TanDoubleBenchmark()
+        {
+            foreach (var iteration in Benchmark.Iterations)
+            {
+                using (iteration.StartMeasurement())
+                {
+                    TanDoubleTest();
+                }
+            }
+        }
+
+        public static void TanDoubleTest()
+        {
+            var result = 0.0; var value = -1.0;
+
+            for (var iteration = 0; iteration < iterations; iteration++)
+            {
+                value += tanDoubleDelta;
+                result += Math.Tan(value);
+            }
+
+            var diff = Math.Abs(tanDoubleExpectedResult - result);
+
+            if (diff > doubleEpsilon)
+            {
+                throw new Exception($"Expected Result {tanDoubleExpectedResult}; Actual Result {result}");
+            }
+        }
+    }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/TanhDouble.cs b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/TanhDouble.cs
new file mode 100644 (file)
index 0000000..c4809e5
--- /dev/null
@@ -0,0 +1,47 @@
+// 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.
+
+using System;
+using Microsoft.Xunit.Performance;
+
+namespace Functions
+{
+    public static partial class MathTests
+    {
+        // Tests Math.Tanh(double) over 5000 iterations for the domain -1, +1
+
+        private const double tanhDoubleDelta = 0.0004;
+        private const double tanhDoubleExpectedResult = 0.76159415578341827;
+
+        [Benchmark]
+        public static void TanhDoubleBenchmark()
+        {
+            foreach (var iteration in Benchmark.Iterations)
+            {
+                using (iteration.StartMeasurement())
+                {
+                    TanhDoubleTest();
+                }
+            }
+        }
+
+        public static void TanhDoubleTest()
+        {
+            var result = 0.0; var value = -1.0;
+
+            for (var iteration = 0; iteration < iterations; iteration++)
+            {
+                value += tanhDoubleDelta;
+                result += Math.Tanh(value);
+            }
+
+            var diff = Math.Abs(tanhDoubleExpectedResult - result);
+
+            if (diff > doubleEpsilon)
+            {
+                throw new Exception($"Expected Result {tanhDoubleExpectedResult}; Actual Result {result}");
+            }
+        }
+    }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/Math/Functions/Functions.cs b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Functions.cs
new file mode 100644 (file)
index 0000000..8ddc6ad
--- /dev/null
@@ -0,0 +1,158 @@
+// 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.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using Microsoft.Xunit.Performance;
+
+[assembly: OptimizeForBenchmarks]
+[assembly: MeasureInstructionsRetired]
+
+namespace Functions
+{
+    public static class Program
+    {
+#if DEBUG
+        private const int defaultIterations = 1;
+#else
+        private const int defaultIterations = 1000;
+#endif
+
+        private static readonly IDictionary<string, Action> TestList = new Dictionary<string, Action>() {
+            ["absdouble"] = MathTests.AbsDoubleTest,
+            ["abssingle"] = MathTests.AbsSingleTest,
+            ["acosdouble"] = MathTests.AcosDoubleTest,
+            ["asindouble"] = MathTests.AsinDoubleTest,
+            ["atandouble"] = MathTests.AtanDoubleTest,
+            ["atan2double"] = MathTests.Atan2DoubleTest,
+            ["ceilingdouble"] = MathTests.CeilingDoubleTest,
+            ["cosdouble"] = MathTests.CosDoubleTest,
+            ["coshdouble"] = MathTests.CoshDoubleTest,
+            ["expdouble"] = MathTests.ExpDoubleTest,
+            ["floordouble"] = MathTests.FloorDoubleTest,
+            ["logdouble"] = MathTests.LogDoubleTest,
+            ["log10double"] = MathTests.Log10DoubleTest,
+            ["powdouble"] = MathTests.PowDoubleTest,
+            ["rounddouble"] = MathTests.RoundDoubleTest,
+            ["sindouble"] = MathTests.SinDoubleTest,
+            ["sinhdouble"] = MathTests.SinhDoubleTest,
+            ["sqrtdouble"] = MathTests.SqrtDoubleTest,
+            ["tandouble"] = MathTests.TanDoubleTest,
+            ["tanhdouble"] = MathTests.TanhDoubleTest
+        };
+
+        private static int Main(string[] args)
+        {
+            var isPassing = true; var iterations = defaultIterations;
+            ICollection<string> testsToRun = new HashSet<string>();
+
+            try
+            {
+                for (int index = 0; index < args.Length; index++)
+                {
+                    if (args[index].ToLowerInvariant() == "-bench")
+                    {
+                        index++;
+
+                        if ((index >= args.Length) || !int.TryParse(args[index], out iterations))
+                        {
+                            iterations = defaultIterations;
+                        }
+                    }
+                    else if (args[index].ToLowerInvariant() == "all")
+                    {
+                        testsToRun = TestList.Keys;
+                        break;
+                    }
+                    else
+                    {
+                        var testName = args[index].ToLowerInvariant();
+
+                        if (!TestList.ContainsKey(testName))
+                        {
+                            PrintUsage();
+                            break;
+                        }
+
+                        testsToRun.Add(testName);
+                    }
+                }
+
+                if (testsToRun.Count == 0)
+                {
+                    testsToRun = TestList.Keys;
+                }
+
+                foreach (var testToRun in testsToRun)
+                {
+                    Console.WriteLine($"Running {testToRun} test...");
+                    Test(iterations, TestList[testToRun]);
+                }
+            }
+            catch (Exception exception)
+            {
+                Console.WriteLine($"    Error: {exception.Message}");
+                isPassing = false;
+            }
+
+            return isPassing ? 100 : -1;
+        }
+
+        private static void PrintUsage()
+        {
+            Console.WriteLine(@"Usage:
+Functions [name] [-bench #]
+
+  [name]: The name of the function to test. Defaults to 'all'.
+    all");
+
+            foreach (var testName in TestList.Keys)
+            {
+                Console.WriteLine($"  {testName}");
+            }
+
+            Console.WriteLine($@"
+  [-bench #]: The number of iterations. Defaults to {defaultIterations}");
+        }
+
+        private static void Test(int iterations, Action action)
+        {
+            // ****************************************************************
+
+            Console.WriteLine("  Warming up...");
+
+            var startTimestamp = Stopwatch.GetTimestamp();
+
+            action();
+
+            var totalElapsedTime = (Stopwatch.GetTimestamp() - startTimestamp);
+            var totalElapsedTimeInSeconds = (totalElapsedTime / (double)(Stopwatch.Frequency));
+
+            Console.WriteLine($"    Total Time: {totalElapsedTimeInSeconds}");
+
+            // ****************************************************************
+
+            Console.WriteLine($"  Executing {iterations} iterations...");
+
+            totalElapsedTime = 0L;
+
+            for (var iteration = 0; iteration < iterations; iteration++)
+            {
+                startTimestamp = Stopwatch.GetTimestamp();
+
+                action();
+
+                totalElapsedTime += (Stopwatch.GetTimestamp() - startTimestamp);
+            }
+
+            totalElapsedTimeInSeconds = (totalElapsedTime / (double)(Stopwatch.Frequency));
+
+            Console.WriteLine($"    Total Time: {totalElapsedTimeInSeconds} seconds");
+            Console.WriteLine($"    Average Time: {totalElapsedTimeInSeconds / iterations} seconds");
+
+            // ****************************************************************
+        }
+    }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/Math/Functions/Functions.csproj b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Functions.csproj
new file mode 100644 (file)
index 0000000..48fcf72
--- /dev/null
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{C949CB07-60B2-420A-B3CA-59847ED4700B}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <FileAlignment>512</FileAlignment>
+    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\11.0\UITestExtensionPackages</ReferencePath>
+    <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+    <NuGetPackageImportStamp>
+    </NuGetPackageImportStamp>
+  </PropertyGroup>
+  <!-- Default configurations to help VS understand the configurations -->
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+  </PropertyGroup>
+  <ItemGroup>
+    <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+      <Visible>False</Visible>
+    </CodeAnalysisDependentAssemblyPaths>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="$(JitPackagesConfigFileDirectory)benchmark\project.json" />
+  </ItemGroup>
+  <ItemGroup>
+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Double\AbsDouble.cs" />
+    <Compile Include="Single\AbsSingle.cs" />
+    <Compile Include="Double\AcosDouble.cs" />
+    <Compile Include="Double\AsinDouble.cs" />
+    <Compile Include="Double\AtanDouble.cs" />
+    <Compile Include="Double\Atan2Double.cs" />
+    <Compile Include="Double\CeilingDouble.cs" />
+    <Compile Include="Double\CosDouble.cs" />
+    <Compile Include="Double\CoshDouble.cs" />
+    <Compile Include="Double\ExpDouble.cs" />
+    <Compile Include="Double\FloorDouble.cs" />
+    <Compile Include="Functions.cs" />
+    <Compile Include="Double\LogDouble.cs" />
+    <Compile Include="Double\Log10Double.cs" />
+    <Compile Include="MathTests.cs" />
+    <Compile Include="Double\PowDouble.cs" />
+    <Compile Include="Double\RoundDouble.cs" />
+    <Compile Include="Double\SinDouble.cs" />
+    <Compile Include="Double\SinhDouble.cs" />
+    <Compile Include="Double\SqrtDouble.cs" />
+    <Compile Include="Double\TanDouble.cs" />
+    <Compile Include="Double\TanhDouble.cs" />
+  </ItemGroup>
+  <PropertyGroup>
+    <ProjectJson>$(JitPackagesConfigFileDirectory)benchmark\project.json</ProjectJson>
+    <ProjectLockJson>$(JitPackagesConfigFileDirectory)benchmark\project.lock.json</ProjectLockJson>
+  </PropertyGroup>
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+  <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' ">
+  </PropertyGroup>
+</Project>
\ No newline at end of file
diff --git a/tests/src/JIT/Performance/CodeQuality/Math/Functions/MathTests.cs b/tests/src/JIT/Performance/CodeQuality/Math/Functions/MathTests.cs
new file mode 100644 (file)
index 0000000..b738c75
--- /dev/null
@@ -0,0 +1,29 @@
+// 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.
+
+namespace Functions
+{
+    public static partial class MathTests
+    {
+        // double has a machine epsilon of approx: 2.22e-16. However, due to floating-point precision
+        // errors, this is too accurate when aggregating values of a set of iterations. Using the
+        // single-precision machine epsilon as our epsilon should be 'good enough' for the purposes
+        // of the perf testing as it ensures we get the expected value and that it is at least as precise
+        // as we would have computed with the single-precision version of the function (without aggregation).
+        private const double doubleEpsilon = 1.19e-07;
+
+        // 5000 iterations is enough to cover the full domain of inputs for certain functions (such
+        // as Cos, which has a domain of 0 to PI) at reasonable intervals (in the case of Cos, the
+        // interval is PI / 5000 which is 0.0006283185307180). It should also give reasonable coverage
+        // for functions which have a larger domain (such as Atan, which covers the full set of real numbers).
+        private const int iterations = 5000;
+
+        // float has a machine epsilon of approx: 1.19e-07. However, due to floating-point precision
+        // errors, this is too accurate when aggregating values of a set of iterations. Using the
+        // half-precision machine epsilon as our epsilon should be 'good enough' for the purposes
+        // of the perf testing as it ensures we get the expected value and that it is at least as precise
+        // as we would have computed with the half-precision version of the function (without aggregation).
+        private const float singleEpsilon = 9.77e-04f;
+    }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/Math/Functions/Single/AbsSingle.cs b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Single/AbsSingle.cs
new file mode 100644 (file)
index 0000000..6168991
--- /dev/null
@@ -0,0 +1,47 @@
+// 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.
+
+using System;
+using Microsoft.Xunit.Performance;
+
+namespace Functions
+{
+    public static partial class MathTests
+    {
+        // Tests Math.Abs(single) over 5000 iterations for the domain -1, +1
+
+        private const float absSingleDelta = 0.0004f;
+        private const float absSingleExpectedResult = 2500.03125f;
+
+        [Benchmark]
+        public static void AbsSingleBenchmark()
+        {
+            foreach (var iteration in Benchmark.Iterations)
+            {
+                using (iteration.StartMeasurement())
+                {
+                    AbsSingleTest();
+                }
+            }
+        }
+
+        public static void AbsSingleTest()
+        {
+            var result = 0.0f; var value = -1.0f;
+
+            for (var iteration = 0; iteration < iterations; iteration++)
+            {
+                value += absSingleDelta;
+                result += Math.Abs(value);
+            }
+
+            var diff = Math.Abs(absSingleExpectedResult - result);
+
+            if (diff > singleEpsilon)
+            {
+                throw new Exception($"Expected Result {absSingleExpectedResult}; Actual Result {result}");
+            }
+        }
+    }
+}
index f2ee913..7ce79e0 100644 (file)
                 <tags>SIMD,AVX</tags>
             </benchmark>
     </benchmark-suite>
+    <benchmark-suite>
+        <name>Math</name>
+        <benchmark>
+            <name>Functions-AbsDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>absdouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-AbsSingle</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>abssingle -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-AcosDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>acosdouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-AsinDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>asindouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-AtanDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>atandouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-Atan2Double</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>atan2double -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-CeilingDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>ceilingdouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-CosDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>cosdouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-CoshDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>coshdouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-ExpDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>expdouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-FloorDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>floordouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-LogDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>logdouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-Log10Double</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>log10double -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-PowDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>powdouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-RoundDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>rounddouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-SinDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>sindouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-SinhDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>sinhdouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-SqrtDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>sqrtdouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-TanDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>tandouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-TanhDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>tanhdouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+    </benchmark-suite>
 </benchmark-system>
index 66e6318..ebbc2ea 100644 (file)
             <expected-results>100</expected-results>
         </benchmark>
     </benchmark-suite>
+    <benchmark-suite>
+        <name>Math</name>
+        <benchmark>
+            <name>Functions-AbsDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>absdouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-AbsSingle</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>abssingle -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-AcosDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>acosdouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-AsinDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>asindouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-AtanDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>atandouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-Atan2Double</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>atan2double -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-CeilingDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>ceilingdouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-CosDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>cosdouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-CoshDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>coshdouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-ExpDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>expdouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-FloorDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>floordouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-LogDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>logdouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-Log10Double</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>log10double -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-PowDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>powdouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-RoundDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>rounddouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-SinDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>sindouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-SinhDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>sinhdouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-SqrtDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>sqrtdouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-TanDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>tandouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+        <benchmark>
+            <name>Functions-TanhDouble</name>
+            <directory>.\Math\Functions\Functions</directory>
+            <executable>Functions.exe</executable>
+            <args>tanhdouble -bench 1000000</args>
+            <expected-results>100</expected-results>
+        </benchmark>
+    </benchmark-suite>
 </benchmark-system>