From: Tanner Gooding Date: Thu, 2 Jun 2016 01:17:24 +0000 (-0700) Subject: Improvements to System.Math InternalCall code. (#4847) X-Git-Tag: accepted/tizen/base/20180629.140029~4460 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=08786f20e89eb5f518d8d25f3e7f886f69d994ea;p=platform%2Fupstream%2Fcoreclr.git Improvements to System.Math InternalCall code. (#4847) * 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. --- diff --git a/src/classlibnative/float/CMakeLists.txt b/src/classlibnative/float/CMakeLists.txt index 3350df9..7cb7ded 100644 --- a/src/classlibnative/float/CMakeLists.txt +++ b/src/classlibnative/float/CMakeLists.txt @@ -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) diff --git a/src/classlibnative/float/Float.nativeproj b/src/classlibnative/float/Float.nativeproj index 091b8a7..ef7f818 100644 --- a/src/classlibnative/float/Float.nativeproj +++ b/src/classlibnative/float/Float.nativeproj @@ -28,7 +28,8 @@ - + + diff --git a/src/classlibnative/float/floatdouble.cpp b/src/classlibnative/float/floatdouble.cpp new file mode 100644 index 0000000..d9603c0 --- /dev/null +++ b/src/classlibnative/float/floatdouble.cpp @@ -0,0 +1,280 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// +// File: FloatDouble.cpp +// + +#include + +#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 index a8a1afc..0000000 --- a/src/classlibnative/float/floatnative.cpp +++ /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 - -#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 index a2fe17a..0000000 --- a/src/classlibnative/float/floatnative.h +++ /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 index 0000000..dd1bb43 --- /dev/null +++ b/src/classlibnative/float/floatsingle.cpp @@ -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 + +#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 index 831f731..0000000 --- a/src/classlibnative/inc/floatclass.h +++ /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 -#include - -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 index 0000000..16403c1 --- /dev/null +++ b/src/classlibnative/inc/floatdouble.h @@ -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 +#include + +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 index 0000000..6d123ec --- /dev/null +++ b/src/classlibnative/inc/floatsingle.h @@ -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 +#include + +class COMSingle { +public: + FCDECL1(static float, Abs, float x); +}; + +#endif // _FLOATSINGLE_H_ diff --git a/src/jit/utils.cpp b/src/jit/utils.cpp index 37164c9..c8ec69e 100644 --- a/src/jit/utils.cpp +++ b/src/jit/utils.cpp @@ -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); } diff --git a/src/jit/utils.h b/src/jit/utils.h index af9f2db..7d77e76 100644 --- a/src/jit/utils.h +++ b/src/jit/utils.h @@ -575,7 +575,7 @@ public: static unsigned __int64 convertDoubleToUInt64(double d); - static double round(double d); + static double round(double x); }; diff --git a/src/pal/inc/pal.h b/src/pal/inc/pal.h index de683fd..baa11a4 100644 --- a/src/pal/inc/pal.h +++ b/src/pal/inc/pal.h @@ -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 diff --git a/src/pal/src/CMakeLists.txt b/src/pal/src/CMakeLists.txt index 976e609..b61c9cd 100644 --- a/src/pal/src/CMakeLists.txt +++ b/src/pal/src/CMakeLists.txt @@ -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 diff --git a/src/pal/src/cruntime/finite.cpp b/src/pal/src/cruntime/math.cpp similarity index 72% rename from src/pal/src/cruntime/finite.cpp rename to src/pal/src/cruntime/math.cpp index 1777f7d..dd45110 100644 --- a/src/pal/src/cruntime/finite.cpp +++ b/src/pal/src/cruntime/math.cpp @@ -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 #if HAVE_IEEEFP_H #include #endif // HAVE_IEEEFP_H + #include -#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; diff --git a/src/pal/src/include/pal/palinternal.h b/src/pal/src/include/pal/palinternal.h index fdebc8d..7348192 100644 --- a/src/pal/src/include/pal/palinternal.h +++ b/src/pal/src/include/pal/palinternal.h @@ -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 diff --git a/src/pal/tests/palsuite/c_runtime/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/CMakeLists.txt index 5bc2e1e..533454c 100644 --- a/src/pal/tests/palsuite/c_runtime/CMakeLists.txt +++ b/src/pal/tests/palsuite/c_runtime/CMakeLists.txt @@ -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) - diff --git a/src/pal/tests/palsuite/c_runtime/_finite/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_finite/CMakeLists.txt index f6aa0cb..5e1ef7f 100644 --- a/src/pal/tests/palsuite/c_runtime/_finite/CMakeLists.txt +++ b/src/pal/tests/palsuite/c_runtime/_finite/CMakeLists.txt @@ -1,4 +1,3 @@ cmake_minimum_required(VERSION 2.8.12.2) add_subdirectory(test1) - diff --git a/src/pal/tests/palsuite/c_runtime/_finite/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_finite/test1/test1.c index d832a91..c815055 100644 --- a/src/pal/tests/palsuite/c_runtime/_finite/test1/test1.c +++ b/src/pal/tests/palsuite/c_runtime/_finite/test1/test1.c @@ -10,10 +10,8 @@ ** of floating point numbers (NaN, -Infinity, Infinity, ** finite nonzero, unnormalized, 0, and -0) ** -** **==========================================================================*/ - #include /* @@ -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; } - - - - - - - - - diff --git a/src/pal/tests/palsuite/c_runtime/_finite/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_finite/test1/testinfo.dat index cb2c6c3..cec0f8a 100644 --- a/src/pal/tests/palsuite/c_runtime/_finite/test1/testinfo.dat +++ b/src/pal/tests/palsuite/c_runtime/_finite/test1/testinfo.dat @@ -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). diff --git a/src/pal/tests/palsuite/c_runtime/_isnan/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_isnan/CMakeLists.txt index f6aa0cb..5e1ef7f 100644 --- a/src/pal/tests/palsuite/c_runtime/_isnan/CMakeLists.txt +++ b/src/pal/tests/palsuite/c_runtime/_isnan/CMakeLists.txt @@ -1,4 +1,3 @@ cmake_minimum_required(VERSION 2.8.12.2) add_subdirectory(test1) - diff --git a/src/pal/tests/palsuite/c_runtime/_isnan/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_isnan/test1/test1.c index 08664d7..d793c9b 100644 --- a/src/pal/tests/palsuite/c_runtime/_isnan/test1/test1.c +++ b/src/pal/tests/palsuite/c_runtime/_isnan/test1/test1.c @@ -13,103 +13,103 @@ ** the fraction to positive and negative, at which point it should return ** the true value. ** -** **==========================================================================*/ #include -#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; } - diff --git a/src/pal/tests/palsuite/c_runtime/acos/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/acos/CMakeLists.txt index f6aa0cb..5e1ef7f 100644 --- a/src/pal/tests/palsuite/c_runtime/acos/CMakeLists.txt +++ b/src/pal/tests/palsuite/c_runtime/acos/CMakeLists.txt @@ -1,4 +1,3 @@ cmake_minimum_required(VERSION 2.8.12.2) add_subdirectory(test1) - diff --git a/src/pal/tests/palsuite/c_runtime/acos/test1/test1.c b/src/pal/tests/palsuite/c_runtime/acos/test1/test1.c index 6c38859..c6ed069 100644 --- a/src/pal/tests/palsuite/c_runtime/acos/test1/test1.c +++ b/src/pal/tests/palsuite/c_runtime/acos/test1/test1.c @@ -6,117 +6,124 @@ ** ** 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 -/* 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; diff --git a/src/pal/tests/palsuite/c_runtime/acos/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/acos/test1/testinfo.dat index cfa70e7..4b43982 100644 --- a/src/pal/tests/palsuite/c_runtime/acos/test1/testinfo.dat +++ b/src/pal/tests/palsuite/c_runtime/acos/test1/testinfo.dat @@ -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. - - - diff --git a/src/pal/tests/palsuite/c_runtime/asin/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/asin/CMakeLists.txt index f6aa0cb..5e1ef7f 100644 --- a/src/pal/tests/palsuite/c_runtime/asin/CMakeLists.txt +++ b/src/pal/tests/palsuite/c_runtime/asin/CMakeLists.txt @@ -1,4 +1,3 @@ cmake_minimum_required(VERSION 2.8.12.2) add_subdirectory(test1) - diff --git a/src/pal/tests/palsuite/c_runtime/asin/test1/test1.c b/src/pal/tests/palsuite/c_runtime/asin/test1/test1.c index b772cc7..0a63356 100644 --- a/src/pal/tests/palsuite/c_runtime/asin/test1/test1.c +++ b/src/pal/tests/palsuite/c_runtime/asin/test1/test1.c @@ -6,131 +6,141 @@ ** ** 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 +// 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; } - - - - - - - - - - - - - diff --git a/src/pal/tests/palsuite/c_runtime/asin/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/asin/test1/testinfo.dat index da3e0c2..fba9f95 100644 --- a/src/pal/tests/palsuite/c_runtime/asin/test1/testinfo.dat +++ b/src/pal/tests/palsuite/c_runtime/asin/test1/testinfo.dat @@ -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. - - - diff --git a/src/pal/tests/palsuite/c_runtime/atan/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/atan/CMakeLists.txt index f6aa0cb..5e1ef7f 100644 --- a/src/pal/tests/palsuite/c_runtime/atan/CMakeLists.txt +++ b/src/pal/tests/palsuite/c_runtime/atan/CMakeLists.txt @@ -1,4 +1,3 @@ cmake_minimum_required(VERSION 2.8.12.2) add_subdirectory(test1) - diff --git a/src/pal/tests/palsuite/c_runtime/atan/test1/test1.c b/src/pal/tests/palsuite/c_runtime/atan/test1/test1.c index 1f7d89c..6840d46 100644 --- a/src/pal/tests/palsuite/c_runtime/atan/test1/test1.c +++ b/src/pal/tests/palsuite/c_runtime/atan/test1/test1.c @@ -6,110 +6,123 @@ ** ** 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 -#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; } diff --git a/src/pal/tests/palsuite/c_runtime/atan/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/atan/test1/testinfo.dat index 8f18fd5..8a181b8 100644 --- a/src/pal/tests/palsuite/c_runtime/atan/test1/testinfo.dat +++ b/src/pal/tests/palsuite/c_runtime/atan/test1/testinfo.dat @@ -11,6 +11,3 @@ EXE1 = test1 Description = Passes a series of values to the atan() function, = checking each for the expected result. - - - diff --git a/src/pal/tests/palsuite/c_runtime/atan2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/atan2/CMakeLists.txt index f6aa0cb..5e1ef7f 100644 --- a/src/pal/tests/palsuite/c_runtime/atan2/CMakeLists.txt +++ b/src/pal/tests/palsuite/c_runtime/atan2/CMakeLists.txt @@ -1,4 +1,3 @@ cmake_minimum_required(VERSION 2.8.12.2) add_subdirectory(test1) - diff --git a/src/pal/tests/palsuite/c_runtime/atan2/test1/test1.c b/src/pal/tests/palsuite/c_runtime/atan2/test1/test1.c index d28bbb9..15aa8f5 100644 --- a/src/pal/tests/palsuite/c_runtime/atan2/test1/test1.c +++ b/src/pal/tests/palsuite/c_runtime/atan2/test1/test1.c @@ -10,78 +10,138 @@ ** Tests with positive and negative values of x and y to ensure ** atan2 is returning results from the correct quadrant. ** -** **===================================================================*/ #include -#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; diff --git a/src/pal/tests/palsuite/c_runtime/ceil/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/ceil/CMakeLists.txt index f6aa0cb..5e1ef7f 100644 --- a/src/pal/tests/palsuite/c_runtime/ceil/CMakeLists.txt +++ b/src/pal/tests/palsuite/c_runtime/ceil/CMakeLists.txt @@ -1,4 +1,3 @@ cmake_minimum_required(VERSION 2.8.12.2) add_subdirectory(test1) - diff --git a/src/pal/tests/palsuite/c_runtime/ceil/test1/test1.c b/src/pal/tests/palsuite/c_runtime/ceil/test1/test1.c index f554acf..e6e36e6 100644 --- a/src/pal/tests/palsuite/c_runtime/ceil/test1/test1.c +++ b/src/pal/tests/palsuite/c_runtime/ceil/test1/test1.c @@ -11,97 +11,122 @@ ** negative infinity. Makes sure that calling ceil on NaN returns ** NaN ** -** **==========================================================================*/ #include -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 -#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; } - - diff --git a/src/pal/tests/palsuite/c_runtime/cos/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/cos/test1/testinfo.dat index ed5fee3..9e57b7f 100644 --- a/src/pal/tests/palsuite/c_runtime/cos/test1/testinfo.dat +++ b/src/pal/tests/palsuite/c_runtime/cos/test1/testinfo.dat @@ -11,6 +11,3 @@ EXE1 = test1 Description = Passes to cos() a series of angle value, checking that = each one return the correct value. - - - diff --git a/src/pal/tests/palsuite/c_runtime/cosh/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/cosh/CMakeLists.txt index f6aa0cb..5e1ef7f 100644 --- a/src/pal/tests/palsuite/c_runtime/cosh/CMakeLists.txt +++ b/src/pal/tests/palsuite/c_runtime/cosh/CMakeLists.txt @@ -1,4 +1,3 @@ cmake_minimum_required(VERSION 2.8.12.2) add_subdirectory(test1) - diff --git a/src/pal/tests/palsuite/c_runtime/cosh/test1/test1.c b/src/pal/tests/palsuite/c_runtime/cosh/test1/test1.c index a0fb67b..40c2fca 100644 --- a/src/pal/tests/palsuite/c_runtime/cosh/test1/test1.c +++ b/src/pal/tests/palsuite/c_runtime/cosh/test1/test1.c @@ -10,93 +10,121 @@ ** ** Dependencies: PAL_Initialize ** PAL_Terminate -** Fail +** Fail ** fabs -** - ** **===========================================================================*/ #include -#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; } - - - - - - - - - - - - - diff --git a/src/pal/tests/palsuite/c_runtime/cosh/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/cosh/test1/testinfo.dat index 39f932a..1315122 100644 --- a/src/pal/tests/palsuite/c_runtime/cosh/test1/testinfo.dat +++ b/src/pal/tests/palsuite/c_runtime/cosh/test1/testinfo.dat @@ -11,6 +11,3 @@ EXE1 = test1 Description = Passes to cosh() a series of angle value, checking that = each one return to correct value. - - - diff --git a/src/pal/tests/palsuite/c_runtime/exp/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/exp/CMakeLists.txt index 1962ade..5e1ef7f 100644 --- a/src/pal/tests/palsuite/c_runtime/exp/CMakeLists.txt +++ b/src/pal/tests/palsuite/c_runtime/exp/CMakeLists.txt @@ -1,6 +1,3 @@ cmake_minimum_required(VERSION 2.8.12.2) add_subdirectory(test1) -add_subdirectory(test2) -add_subdirectory(test3) - diff --git a/src/pal/tests/palsuite/c_runtime/exp/test1/test1.c b/src/pal/tests/palsuite/c_runtime/exp/test1/test1.c index 67de564..20e071a 100644 --- a/src/pal/tests/palsuite/c_runtime/exp/test1/test1.c +++ b/src/pal/tests/palsuite/c_runtime/exp/test1/test1.c @@ -8,57 +8,131 @@ ** ** Purpose: Tests exp with a normal set of values. ** -** **===================================================================*/ #include +// 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 index 5cfaa78..0000000 --- a/src/pal/tests/palsuite/c_runtime/exp/test2/test2.c +++ /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 - -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 index 0efd15e..0000000 --- a/src/pal/tests/palsuite/c_runtime/exp/test3/test3.c +++ /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 - -#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; -} diff --git a/src/pal/tests/palsuite/c_runtime/fabs/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fabs/CMakeLists.txt index f6aa0cb..5e1ef7f 100644 --- a/src/pal/tests/palsuite/c_runtime/fabs/CMakeLists.txt +++ b/src/pal/tests/palsuite/c_runtime/fabs/CMakeLists.txt @@ -1,4 +1,3 @@ cmake_minimum_required(VERSION 2.8.12.2) add_subdirectory(test1) - diff --git a/src/pal/tests/palsuite/c_runtime/fabs/test1/test1.c b/src/pal/tests/palsuite/c_runtime/fabs/test1/test1.c index cd8c0be..0a74d5c 100644 --- a/src/pal/tests/palsuite/c_runtime/fabs/test1/test1.c +++ b/src/pal/tests/palsuite/c_runtime/fabs/test1/test1.c @@ -10,80 +10,121 @@ ** ** Dependencies: PAL_Initialize ** PAL_Terminate -** Fail -** - +** Fail ** **===========================================================================*/ #include +// 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; } - - - - - - - - - - - - - diff --git a/src/pal/tests/palsuite/c_runtime/fabs/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fabs/test1/testinfo.dat index a15d54e..d5b2321 100644 --- a/src/pal/tests/palsuite/c_runtime/fabs/test1/testinfo.dat +++ b/src/pal/tests/palsuite/c_runtime/fabs/test1/testinfo.dat @@ -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 index 0000000..5e1ef7f --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/fabsf/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +add_subdirectory(test1) diff --git a/src/pal/tests/palsuite/c_runtime/exp/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fabsf/test1/CMakeLists.txt similarity index 50% rename from src/pal/tests/palsuite/c_runtime/exp/test2/CMakeLists.txt rename to src/pal/tests/palsuite/c_runtime/fabsf/test1/CMakeLists.txt index 5e9d291..06512eb 100644 --- a/src/pal/tests/palsuite/c_runtime/exp/test2/CMakeLists.txt +++ b/src/pal/tests/palsuite/c_runtime/fabsf/test1/CMakeLists.txt @@ -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 index 0000000..0b02072 --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/fabsf/test1/test1.c @@ -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 + +// 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; +} diff --git a/src/pal/tests/palsuite/c_runtime/exp/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fabsf/test1/testinfo.dat similarity index 59% rename from src/pal/tests/palsuite/c_runtime/exp/test2/testinfo.dat rename to src/pal/tests/palsuite/c_runtime/fabsf/test1/testinfo.dat index 8799fc3..a927f1e 100644 --- a/src/pal/tests/palsuite/c_runtime/exp/test2/testinfo.dat +++ b/src/pal/tests/palsuite/c_runtime/fabsf/test1/testinfo.dat @@ -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. diff --git a/src/pal/tests/palsuite/c_runtime/floor/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/floor/CMakeLists.txt index f6aa0cb..5e1ef7f 100644 --- a/src/pal/tests/palsuite/c_runtime/floor/CMakeLists.txt +++ b/src/pal/tests/palsuite/c_runtime/floor/CMakeLists.txt @@ -1,4 +1,3 @@ cmake_minimum_required(VERSION 2.8.12.2) add_subdirectory(test1) - diff --git a/src/pal/tests/palsuite/c_runtime/floor/test1/test1.c b/src/pal/tests/palsuite/c_runtime/floor/test1/test1.c index b576334..dba3209 100644 --- a/src/pal/tests/palsuite/c_runtime/floor/test1/test1.c +++ b/src/pal/tests/palsuite/c_runtime/floor/test1/test1.c @@ -2,91 +2,131 @@ // 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 +// 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; } - - - - - - - - - - - - - diff --git a/src/pal/tests/palsuite/c_runtime/floor/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/floor/test1/testinfo.dat index 8aa8437..90543ea 100644 --- a/src/pal/tests/palsuite/c_runtime/floor/test1/testinfo.dat +++ b/src/pal/tests/palsuite/c_runtime/floor/test1/testinfo.dat @@ -11,6 +11,3 @@ EXE1 = test1 Description = Passes to floor() a series of value, checking that = each one return to correct value. - - - diff --git a/src/pal/tests/palsuite/c_runtime/fmod/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fmod/CMakeLists.txt index f6aa0cb..5e1ef7f 100644 --- a/src/pal/tests/palsuite/c_runtime/fmod/CMakeLists.txt +++ b/src/pal/tests/palsuite/c_runtime/fmod/CMakeLists.txt @@ -1,4 +1,3 @@ cmake_minimum_required(VERSION 2.8.12.2) add_subdirectory(test1) - diff --git a/src/pal/tests/palsuite/c_runtime/fmod/test1/test1.c b/src/pal/tests/palsuite/c_runtime/fmod/test1/test1.c index d415371..fd69ca5 100644 --- a/src/pal/tests/palsuite/c_runtime/fmod/test1/test1.c +++ b/src/pal/tests/palsuite/c_runtime/fmod/test1/test1.c @@ -10,91 +10,148 @@ ** ** Dependencies: PAL_Initialize ** PAL_Terminate -** Fail +** Fail ** fabs -** - ** **===========================================================================*/ #include -#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; } - - - - - - - - - - - - - diff --git a/src/pal/tests/palsuite/c_runtime/fmod/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fmod/test1/testinfo.dat index 850daf0..0a81fd8 100644 --- a/src/pal/tests/palsuite/c_runtime/fmod/test1/testinfo.dat +++ b/src/pal/tests/palsuite/c_runtime/fmod/test1/testinfo.dat @@ -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 index 0000000..5e1ef7f --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/fmodf/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +add_subdirectory(test1) diff --git a/src/pal/tests/palsuite/c_runtime/pow/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fmodf/test1/CMakeLists.txt similarity index 50% rename from src/pal/tests/palsuite/c_runtime/pow/test2/CMakeLists.txt rename to src/pal/tests/palsuite/c_runtime/fmodf/test1/CMakeLists.txt index b480b04..d1ea238 100644 --- a/src/pal/tests/palsuite/c_runtime/pow/test2/CMakeLists.txt +++ b/src/pal/tests/palsuite/c_runtime/fmodf/test1/CMakeLists.txt @@ -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 index 0000000..31b45d3 --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/fmodf/test1/test1.c @@ -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 + +// 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; +} diff --git a/src/pal/tests/palsuite/c_runtime/pow/test3/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fmodf/test1/testinfo.dat similarity index 55% rename from src/pal/tests/palsuite/c_runtime/pow/test3/testinfo.dat rename to src/pal/tests/palsuite/c_runtime/fmodf/test1/testinfo.dat index 8994ccf..11c7978 100644 --- a/src/pal/tests/palsuite/c_runtime/pow/test3/testinfo.dat +++ b/src/pal/tests/palsuite/c_runtime/fmodf/test1/testinfo.dat @@ -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. diff --git a/src/pal/tests/palsuite/c_runtime/log/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/log/CMakeLists.txt index f6aa0cb..5e1ef7f 100644 --- a/src/pal/tests/palsuite/c_runtime/log/CMakeLists.txt +++ b/src/pal/tests/palsuite/c_runtime/log/CMakeLists.txt @@ -1,4 +1,3 @@ cmake_minimum_required(VERSION 2.8.12.2) add_subdirectory(test1) - diff --git a/src/pal/tests/palsuite/c_runtime/log/test1/test1.c b/src/pal/tests/palsuite/c_runtime/log/test1/test1.c index 0328bda..eea592d 100644 --- a/src/pal/tests/palsuite/c_runtime/log/test1/test1.c +++ b/src/pal/tests/palsuite/c_runtime/log/test1/test1.c @@ -2,130 +2,138 @@ // 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 -#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; diff --git a/src/pal/tests/palsuite/c_runtime/log/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/log/test1/testinfo.dat index b27ea23..6b984f6 100644 --- a/src/pal/tests/palsuite/c_runtime/log/test1/testinfo.dat +++ b/src/pal/tests/palsuite/c_runtime/log/test1/testinfo.dat @@ -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. - - - diff --git a/src/pal/tests/palsuite/c_runtime/log10/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/log10/CMakeLists.txt index f6aa0cb..5e1ef7f 100644 --- a/src/pal/tests/palsuite/c_runtime/log10/CMakeLists.txt +++ b/src/pal/tests/palsuite/c_runtime/log10/CMakeLists.txt @@ -1,4 +1,3 @@ cmake_minimum_required(VERSION 2.8.12.2) add_subdirectory(test1) - diff --git a/src/pal/tests/palsuite/c_runtime/log10/test1/test1.c b/src/pal/tests/palsuite/c_runtime/log10/test1/test1.c index 519db31..13711a7 100644 --- a/src/pal/tests/palsuite/c_runtime/log10/test1/test1.c +++ b/src/pal/tests/palsuite/c_runtime/log10/test1/test1.c @@ -6,129 +6,140 @@ ** ** 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 -#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; diff --git a/src/pal/tests/palsuite/c_runtime/modf/test1/test1.c b/src/pal/tests/palsuite/c_runtime/modf/test1/test1.c index 59ab43d..389d079 100644 --- a/src/pal/tests/palsuite/c_runtime/modf/test1/test1.c +++ b/src/pal/tests/palsuite/c_runtime/modf/test1/test1.c @@ -10,99 +10,127 @@ ** ** Dependencies: PAL_Initialize ** PAL_Terminate -** Fail +** Fail ** fabs -** - ** **===========================================================================*/ #include -#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 index 0000000..f6aa0cb --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/modff/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +add_subdirectory(test1) + diff --git a/src/pal/tests/palsuite/c_runtime/exp/test3/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/modff/test1/CMakeLists.txt similarity index 50% rename from src/pal/tests/palsuite/c_runtime/exp/test3/CMakeLists.txt rename to src/pal/tests/palsuite/c_runtime/modff/test1/CMakeLists.txt index 00fbca5..812cd1c 100644 --- a/src/pal/tests/palsuite/c_runtime/exp/test3/CMakeLists.txt +++ b/src/pal/tests/palsuite/c_runtime/modff/test1/CMakeLists.txt @@ -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 index 0000000..6b7a50b --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/modff/test1/test1.c @@ -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 + +// 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; +} diff --git a/src/pal/tests/palsuite/c_runtime/exp/test3/testinfo.dat b/src/pal/tests/palsuite/c_runtime/modff/test1/testinfo.dat similarity index 55% rename from src/pal/tests/palsuite/c_runtime/exp/test3/testinfo.dat rename to src/pal/tests/palsuite/c_runtime/modff/test1/testinfo.dat index 58b7ecb..392491e 100644 --- a/src/pal/tests/palsuite/c_runtime/exp/test3/testinfo.dat +++ b/src/pal/tests/palsuite/c_runtime/modff/test1/testinfo.dat @@ -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. diff --git a/src/pal/tests/palsuite/c_runtime/pow/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/pow/CMakeLists.txt index 1962ade..5e1ef7f 100644 --- a/src/pal/tests/palsuite/c_runtime/pow/CMakeLists.txt +++ b/src/pal/tests/palsuite/c_runtime/pow/CMakeLists.txt @@ -1,6 +1,3 @@ cmake_minimum_required(VERSION 2.8.12.2) add_subdirectory(test1) -add_subdirectory(test2) -add_subdirectory(test3) - diff --git a/src/pal/tests/palsuite/c_runtime/pow/test1/test1.c b/src/pal/tests/palsuite/c_runtime/pow/test1/test1.c index 2462ba4..690ae94 100644 --- a/src/pal/tests/palsuite/c_runtime/pow/test1/test1.c +++ b/src/pal/tests/palsuite/c_runtime/pow/test1/test1.c @@ -6,110 +6,208 @@ ** ** 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 -/* 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 index 5d713c5..0000000 --- a/src/pal/tests/palsuite/c_runtime/pow/test2/test2.c +++ /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 - -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 index 205baa8..0000000 --- a/src/pal/tests/palsuite/c_runtime/pow/test2/testinfo.dat +++ /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 index 414c3ba..0000000 --- a/src/pal/tests/palsuite/c_runtime/pow/test3/CMakeLists.txt +++ /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 index d01710b..0000000 --- a/src/pal/tests/palsuite/c_runtime/pow/test3/test3.c +++ /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 - -#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; -} diff --git a/src/pal/tests/palsuite/c_runtime/sin/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sin/CMakeLists.txt index f6aa0cb..5e1ef7f 100644 --- a/src/pal/tests/palsuite/c_runtime/sin/CMakeLists.txt +++ b/src/pal/tests/palsuite/c_runtime/sin/CMakeLists.txt @@ -1,4 +1,3 @@ cmake_minimum_required(VERSION 2.8.12.2) add_subdirectory(test1) - diff --git a/src/pal/tests/palsuite/c_runtime/sin/test1/test1.c b/src/pal/tests/palsuite/c_runtime/sin/test1/test1.c index 701856b..bec58d4 100644 --- a/src/pal/tests/palsuite/c_runtime/sin/test1/test1.c +++ b/src/pal/tests/palsuite/c_runtime/sin/test1/test1.c @@ -10,93 +10,122 @@ ** ** Dependencies: PAL_Initialize ** PAL_Terminate -** Fail +** Fail ** fabs -** - ** **===========================================================================*/ #include -#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; } - - - - - - - - - - - - - diff --git a/src/pal/tests/palsuite/c_runtime/sin/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sin/test1/testinfo.dat index 05c49d6..57eae6b 100644 --- a/src/pal/tests/palsuite/c_runtime/sin/test1/testinfo.dat +++ b/src/pal/tests/palsuite/c_runtime/sin/test1/testinfo.dat @@ -11,6 +11,3 @@ EXE1 = test1 Description = Passes to sin() a series of angle value, checking that = each one return to correct value. - - - diff --git a/src/pal/tests/palsuite/c_runtime/sinh/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sinh/CMakeLists.txt index f6aa0cb..5e1ef7f 100644 --- a/src/pal/tests/palsuite/c_runtime/sinh/CMakeLists.txt +++ b/src/pal/tests/palsuite/c_runtime/sinh/CMakeLists.txt @@ -1,4 +1,3 @@ cmake_minimum_required(VERSION 2.8.12.2) add_subdirectory(test1) - diff --git a/src/pal/tests/palsuite/c_runtime/sinh/test1/test1.c b/src/pal/tests/palsuite/c_runtime/sinh/test1/test1.c index c4cc54e..e790b16 100644 --- a/src/pal/tests/palsuite/c_runtime/sinh/test1/test1.c +++ b/src/pal/tests/palsuite/c_runtime/sinh/test1/test1.c @@ -10,93 +10,121 @@ ** ** Dependencies: PAL_Initialize ** PAL_Terminate -** Fail +** Fail ** fabs -** - ** **===========================================================================*/ #include -#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; } - - - - - - - - - - - - - diff --git a/src/pal/tests/palsuite/c_runtime/sinh/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sinh/test1/testinfo.dat index ecffb06..f7aee40 100644 --- a/src/pal/tests/palsuite/c_runtime/sinh/test1/testinfo.dat +++ b/src/pal/tests/palsuite/c_runtime/sinh/test1/testinfo.dat @@ -11,6 +11,3 @@ EXE1 = test1 Description = Passes to sinh() a series of angle value, checking that = each one return to correct value. - - - diff --git a/src/pal/tests/palsuite/c_runtime/sqrt/test1/test1.c b/src/pal/tests/palsuite/c_runtime/sqrt/test1/test1.c index 028dc2c..62d2251 100644 --- a/src/pal/tests/palsuite/c_runtime/sqrt/test1/test1.c +++ b/src/pal/tests/palsuite/c_runtime/sqrt/test1/test1.c @@ -12,67 +12,112 @@ ** **===================================================================*/ -/* Note: Calling sqrt on anything negative gives indefinite results. */ - #include -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; } - - - - - - - - - - - - - diff --git a/src/pal/tests/palsuite/c_runtime/tan/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/tan/CMakeLists.txt index f6aa0cb..5e1ef7f 100644 --- a/src/pal/tests/palsuite/c_runtime/tan/CMakeLists.txt +++ b/src/pal/tests/palsuite/c_runtime/tan/CMakeLists.txt @@ -1,4 +1,3 @@ cmake_minimum_required(VERSION 2.8.12.2) add_subdirectory(test1) - diff --git a/src/pal/tests/palsuite/c_runtime/tan/test1/test1.c b/src/pal/tests/palsuite/c_runtime/tan/test1/test1.c index f30daca..443e5da 100644 --- a/src/pal/tests/palsuite/c_runtime/tan/test1/test1.c +++ b/src/pal/tests/palsuite/c_runtime/tan/test1/test1.c @@ -10,90 +10,128 @@ ** ** Dependencies: PAL_Initialize ** PAL_Terminate -** Fail +** Fail ** fabs -** - ** **===========================================================================*/ #include -#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; } - - - - - - - - - - - - - diff --git a/src/pal/tests/palsuite/c_runtime/tan/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/tan/test1/testinfo.dat index 26546d3..05d6cfe 100644 --- a/src/pal/tests/palsuite/c_runtime/tan/test1/testinfo.dat +++ b/src/pal/tests/palsuite/c_runtime/tan/test1/testinfo.dat @@ -11,6 +11,3 @@ EXE1 = test1 Description = Passes to tan() a series of angle value, checking that = each one return to correct value. - - - diff --git a/src/pal/tests/palsuite/c_runtime/tanh/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/tanh/CMakeLists.txt index f6aa0cb..5e1ef7f 100644 --- a/src/pal/tests/palsuite/c_runtime/tanh/CMakeLists.txt +++ b/src/pal/tests/palsuite/c_runtime/tanh/CMakeLists.txt @@ -1,4 +1,3 @@ cmake_minimum_required(VERSION 2.8.12.2) add_subdirectory(test1) - diff --git a/src/pal/tests/palsuite/c_runtime/tanh/test1/test1.c b/src/pal/tests/palsuite/c_runtime/tanh/test1/test1.c index f3452e8..3b8f879 100644 --- a/src/pal/tests/palsuite/c_runtime/tanh/test1/test1.c +++ b/src/pal/tests/palsuite/c_runtime/tanh/test1/test1.c @@ -10,93 +10,121 @@ ** ** Dependencies: PAL_Initialize ** PAL_Terminate -** Fail +** Fail ** fabs -** - ** **===========================================================================*/ #include -#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; } - - - - - - - - - - - - - diff --git a/src/pal/tests/palsuite/c_runtime/tanh/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/tanh/test1/testinfo.dat index 6af765c..1b2bc91 100644 --- a/src/pal/tests/palsuite/c_runtime/tanh/test1/testinfo.dat +++ b/src/pal/tests/palsuite/c_runtime/tanh/test1/testinfo.dat @@ -11,6 +11,3 @@ EXE1 = test1 Description = Passes to tanh() a series of angle value, checking that = each one return to correct value. - - - diff --git a/src/pal/tests/palsuite/paltestlist.txt b/src/pal/tests/palsuite/paltestlist.txt index 83cfc4d..d0a76e9 100644 --- a/src/pal/tests/palsuite/paltestlist.txt +++ b/src/pal/tests/palsuite/paltestlist.txt @@ -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 diff --git a/src/pal/tests/palsuite/palverify.dat b/src/pal/tests/palsuite/palverify.dat index e667714..36b48d6 100644 --- a/src/pal/tests/palsuite/palverify.dat +++ b/src/pal/tests/palsuite/palverify.dat @@ -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 diff --git a/src/vm/amd64/JitHelpers_Fast.asm b/src/vm/amd64/JitHelpers_Fast.asm index 9018520..f004be5 100644 --- a/src/vm/amd64/JitHelpers_Fast.asm +++ b/src/vm/amd64/JitHelpers_Fast.asm @@ -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 diff --git a/src/vm/ecalllist.h b/src/vm/ecalllist.h index dc9c432..8675ddd 100644 --- a/src/vm/ecalllist.h +++ b/src/vm/ecalllist.h @@ -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) diff --git a/src/vm/mscorlib.cpp b/src/vm/mscorlib.cpp index 91e2a10..7681028 100644 --- a/src/vm/mscorlib.cpp +++ b/src/vm/mscorlib.cpp @@ -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 index 0000000..6429a39 --- /dev/null +++ b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/AbsDouble.cs @@ -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 index 0000000..3ba2867 --- /dev/null +++ b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/AcosDouble.cs @@ -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 index 0000000..030756c --- /dev/null +++ b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/AsinDouble.cs @@ -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 index 0000000..82831e6 --- /dev/null +++ b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/Atan2Double.cs @@ -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 index 0000000..ec2ebe3 --- /dev/null +++ b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/AtanDouble.cs @@ -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 index 0000000..f822aae --- /dev/null +++ b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/CeilingDouble.cs @@ -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 index 0000000..e95ab5c --- /dev/null +++ b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/CosDouble.cs @@ -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 index 0000000..c8b7fb6 --- /dev/null +++ b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/CoshDouble.cs @@ -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 index 0000000..64be839 --- /dev/null +++ b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/ExpDouble.cs @@ -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 index 0000000..4d4b4f2 --- /dev/null +++ b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/FloorDouble.cs @@ -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 index 0000000..330d8a7 --- /dev/null +++ b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/Log10Double.cs @@ -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 index 0000000..bddb84b --- /dev/null +++ b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/LogDouble.cs @@ -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 index 0000000..c824807 --- /dev/null +++ b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/PowDouble.cs @@ -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 index 0000000..9c5dcc9 --- /dev/null +++ b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/RoundDouble.cs @@ -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 index 0000000..73886aa --- /dev/null +++ b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/SinDouble.cs @@ -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 index 0000000..8f79cc9 --- /dev/null +++ b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/SinhDouble.cs @@ -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 index 0000000..5d9e554 --- /dev/null +++ b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/SqrtDouble.cs @@ -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 index 0000000..6988c67 --- /dev/null +++ b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/TanDouble.cs @@ -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 index 0000000..c4809e5 --- /dev/null +++ b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Double/TanhDouble.cs @@ -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 index 0000000..8ddc6ad --- /dev/null +++ b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Functions.cs @@ -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 TestList = new Dictionary() { + ["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 testsToRun = new HashSet(); + + 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 index 0000000..48fcf72 --- /dev/null +++ b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Functions.csproj @@ -0,0 +1,69 @@ + + + + + Debug + AnyCPU + 2.0 + {C949CB07-60B2-420A-B3CA-59847ED4700B} + Exe + Properties + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + $(ProgramFiles)\Common Files\microsoft shared\VSTT\11.0\UITestExtensionPackages + ..\..\ + + + + + + pdbonly + true + + + pdbonly + true + + + + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $(JitPackagesConfigFileDirectory)benchmark\project.json + $(JitPackagesConfigFileDirectory)benchmark\project.lock.json + + + + + \ 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 index 0000000..b738c75 --- /dev/null +++ b/tests/src/JIT/Performance/CodeQuality/Math/Functions/MathTests.cs @@ -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 index 0000000..6168991 --- /dev/null +++ b/tests/src/JIT/Performance/CodeQuality/Math/Functions/Single/AbsSingle.cs @@ -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}"); + } + } + } +} diff --git a/tests/src/JIT/Performance/RunBenchmarks/benchmarks.xml b/tests/src/JIT/Performance/RunBenchmarks/benchmarks.xml index f2ee913..7ce79e0 100644 --- a/tests/src/JIT/Performance/RunBenchmarks/benchmarks.xml +++ b/tests/src/JIT/Performance/RunBenchmarks/benchmarks.xml @@ -666,4 +666,147 @@ SIMD,AVX + + Math + + Functions-AbsDouble + .\Math\Functions\Functions + Functions.exe + absdouble -bench 1000000 + 100 + + + Functions-AbsSingle + .\Math\Functions\Functions + Functions.exe + abssingle -bench 1000000 + 100 + + + Functions-AcosDouble + .\Math\Functions\Functions + Functions.exe + acosdouble -bench 1000000 + 100 + + + Functions-AsinDouble + .\Math\Functions\Functions + Functions.exe + asindouble -bench 1000000 + 100 + + + Functions-AtanDouble + .\Math\Functions\Functions + Functions.exe + atandouble -bench 1000000 + 100 + + + Functions-Atan2Double + .\Math\Functions\Functions + Functions.exe + atan2double -bench 1000000 + 100 + + + Functions-CeilingDouble + .\Math\Functions\Functions + Functions.exe + ceilingdouble -bench 1000000 + 100 + + + Functions-CosDouble + .\Math\Functions\Functions + Functions.exe + cosdouble -bench 1000000 + 100 + + + Functions-CoshDouble + .\Math\Functions\Functions + Functions.exe + coshdouble -bench 1000000 + 100 + + + Functions-ExpDouble + .\Math\Functions\Functions + Functions.exe + expdouble -bench 1000000 + 100 + + + Functions-FloorDouble + .\Math\Functions\Functions + Functions.exe + floordouble -bench 1000000 + 100 + + + Functions-LogDouble + .\Math\Functions\Functions + Functions.exe + logdouble -bench 1000000 + 100 + + + Functions-Log10Double + .\Math\Functions\Functions + Functions.exe + log10double -bench 1000000 + 100 + + + Functions-PowDouble + .\Math\Functions\Functions + Functions.exe + powdouble -bench 1000000 + 100 + + + Functions-RoundDouble + .\Math\Functions\Functions + Functions.exe + rounddouble -bench 1000000 + 100 + + + Functions-SinDouble + .\Math\Functions\Functions + Functions.exe + sindouble -bench 1000000 + 100 + + + Functions-SinhDouble + .\Math\Functions\Functions + Functions.exe + sinhdouble -bench 1000000 + 100 + + + Functions-SqrtDouble + .\Math\Functions\Functions + Functions.exe + sqrtdouble -bench 1000000 + 100 + + + Functions-TanDouble + .\Math\Functions\Functions + Functions.exe + tandouble -bench 1000000 + 100 + + + Functions-TanhDouble + .\Math\Functions\Functions + Functions.exe + tanhdouble -bench 1000000 + 100 + + diff --git a/tests/src/JIT/Performance/RunBenchmarks/coreclr_benchmarks.xml b/tests/src/JIT/Performance/RunBenchmarks/coreclr_benchmarks.xml index 66e6318..ebbc2ea 100644 --- a/tests/src/JIT/Performance/RunBenchmarks/coreclr_benchmarks.xml +++ b/tests/src/JIT/Performance/RunBenchmarks/coreclr_benchmarks.xml @@ -582,4 +582,147 @@ 100 + + Math + + Functions-AbsDouble + .\Math\Functions\Functions + Functions.exe + absdouble -bench 1000000 + 100 + + + Functions-AbsSingle + .\Math\Functions\Functions + Functions.exe + abssingle -bench 1000000 + 100 + + + Functions-AcosDouble + .\Math\Functions\Functions + Functions.exe + acosdouble -bench 1000000 + 100 + + + Functions-AsinDouble + .\Math\Functions\Functions + Functions.exe + asindouble -bench 1000000 + 100 + + + Functions-AtanDouble + .\Math\Functions\Functions + Functions.exe + atandouble -bench 1000000 + 100 + + + Functions-Atan2Double + .\Math\Functions\Functions + Functions.exe + atan2double -bench 1000000 + 100 + + + Functions-CeilingDouble + .\Math\Functions\Functions + Functions.exe + ceilingdouble -bench 1000000 + 100 + + + Functions-CosDouble + .\Math\Functions\Functions + Functions.exe + cosdouble -bench 1000000 + 100 + + + Functions-CoshDouble + .\Math\Functions\Functions + Functions.exe + coshdouble -bench 1000000 + 100 + + + Functions-ExpDouble + .\Math\Functions\Functions + Functions.exe + expdouble -bench 1000000 + 100 + + + Functions-FloorDouble + .\Math\Functions\Functions + Functions.exe + floordouble -bench 1000000 + 100 + + + Functions-LogDouble + .\Math\Functions\Functions + Functions.exe + logdouble -bench 1000000 + 100 + + + Functions-Log10Double + .\Math\Functions\Functions + Functions.exe + log10double -bench 1000000 + 100 + + + Functions-PowDouble + .\Math\Functions\Functions + Functions.exe + powdouble -bench 1000000 + 100 + + + Functions-RoundDouble + .\Math\Functions\Functions + Functions.exe + rounddouble -bench 1000000 + 100 + + + Functions-SinDouble + .\Math\Functions\Functions + Functions.exe + sindouble -bench 1000000 + 100 + + + Functions-SinhDouble + .\Math\Functions\Functions + Functions.exe + sinhdouble -bench 1000000 + 100 + + + Functions-SqrtDouble + .\Math\Functions\Functions + Functions.exe + sqrtdouble -bench 1000000 + 100 + + + Functions-TanDouble + .\Math\Functions\Functions + Functions.exe + tandouble -bench 1000000 + 100 + + + Functions-TanhDouble + .\Math\Functions\Functions + Functions.exe + tanhdouble -bench 1000000 + 100 + +