include_directories("../inc")
set(FLOAT_SOURCES
- floatnative.cpp
+ floatdouble.cpp
+ floatsingle.cpp
)
if(CLR_CMAKE_PLATFORM_UNIX)
</PropertyGroup>
<!--Leaf Project Items-->
<ItemGroup>
- <CppCompile Include="FloatNative.cpp" />
+ <CppCompile Include="floatdouble.cpp" />
+ <CppCompile Include="floatsingle.cpp" />
</ItemGroup>
<!--Import the targets-->
<Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.targets" />
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+// File: FloatDouble.cpp
+//
+
+#include <common.h>
+
+#include "floatdouble.h"
+
+#define IS_DBL_INFINITY(x) (((*((INT64*)((void*)&x))) & I64(0x7FFFFFFFFFFFFFFF)) == I64(0x7FF0000000000000))
+
+// The default compilation mode is /fp:precise, which disables floating-point intrinsics. This
+// default compilation mode has previously caused performance regressions in floating-point code.
+// We enable /fp:fast semantics for the majority of the math functions, as it will speed up performance
+// and is really unlikely to cause any other code regressions.
+
+// Sin, Cos, and Tan on AMD64 Windows were previously implemented in vm\amd64\JitHelpers_Fast.asm
+// by calling x87 floating point code (fsin, fcos, fptan) because the CRT helpers were too slow. This
+// is no longer the case and the CRT call is used on all platforms.
+
+// Log, Log10 and Exp were previously slower with /fp:fast on SSE2 enabled hardware (see #500373).
+// This is no longer the case and they now consume use the /fp:fast versions.
+
+// Exp(+/-INFINITY) did not previously return the expected results of +0.0 (for -INFINITY)
+// and +INFINITY (for +INFINITY) so these cases were handled specially. As this is no longer
+// the case and the expected results are now returned, the special handling has been removed.
+
+// Previously there was more special handling for the x86 Windows version of Pow.
+// This additional handling was unnecessary and has since been removed.
+
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+///
+/// beginning of /fp:fast scope
+///
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef _MSC_VER
+#pragma float_control(precise, off)
+#endif
+
+/*=====================================Abs======================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Abs, double x)
+ FCALL_CONTRACT;
+
+ return (double)fabs(x);
+FCIMPLEND
+
+/*=====================================Acos=====================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Acos, double x)
+ FCALL_CONTRACT;
+
+ return (double)acos(x);
+FCIMPLEND
+
+/*=====================================Asin=====================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Asin, double x)
+ FCALL_CONTRACT;
+
+ return (double)asin(x);
+FCIMPLEND
+
+/*=====================================Atan=====================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Atan, double x)
+ FCALL_CONTRACT;
+
+ return (double)atan(x);
+FCIMPLEND
+
+/*=====================================Atan2====================================
+**
+==============================================================================*/
+FCIMPL2_VV(double, COMDouble::Atan2, double y, double x)
+ FCALL_CONTRACT;
+
+ // atan2(+/-INFINITY, +/-INFINITY) produces +/-0.78539816339744828 (x is +INFINITY) and
+ // +/-2.3561944901923448 (x is -INFINITY) instead of the expected value of NaN. We handle
+ // that case here ourselves.
+ if (IS_DBL_INFINITY(y) && IS_DBL_INFINITY(x)) {
+ return (double)(y / x);
+ }
+
+ return (double)atan2(y, x);
+FCIMPLEND
+
+/*====================================Ceil======================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Ceil, double x)
+ FCALL_CONTRACT;
+
+ return (double)ceil(x);
+FCIMPLEND
+
+/*=====================================Cos======================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Cos, double x)
+ FCALL_CONTRACT;
+
+ return (double)cos(x);
+FCIMPLEND
+
+/*=====================================Cosh=====================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Cosh, double x)
+ FCALL_CONTRACT;
+
+ return (double)cosh(x);
+FCIMPLEND
+
+/*=====================================Exp======================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Exp, double x)
+ FCALL_CONTRACT;
+
+ return (double)exp(x);
+FCIMPLEND
+
+/*====================================Floor=====================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Floor, double x)
+ FCALL_CONTRACT;
+
+ return (double)floor(x);
+FCIMPLEND
+
+/*=====================================Log======================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Log, double x)
+ FCALL_CONTRACT;
+
+ return (double)log(x);
+FCIMPLEND
+
+/*====================================Log10=====================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Log10, double x)
+ FCALL_CONTRACT;
+
+ return (double)log10(x);
+FCIMPLEND
+
+/*=====================================ModF=====================================
+**
+==============================================================================*/
+FCIMPL1(double, COMDouble::ModF, double* iptr)
+ FCALL_CONTRACT;
+
+ return (double)modf(*iptr, iptr);
+FCIMPLEND
+
+/*=====================================Pow======================================
+**
+==============================================================================*/
+FCIMPL2_VV(double, COMDouble::Pow, double x, double y)
+ FCALL_CONTRACT;
+
+ // The CRT version of pow preserves the NaN payload of x over the NaN payload of y.
+
+ if(_isnan(y)) {
+ return y; // IEEE 754-2008: NaN payload must be preserved
+ }
+
+ if(_isnan(x)) {
+ return x; // IEEE 754-2008: NaN payload must be preserved
+ }
+
+ // The CRT version of pow does not return NaN for pow(-1.0, +/-INFINITY) and
+ // instead returns +1.0.
+
+ if(IS_DBL_INFINITY(y) && (x == -1.0)) {
+ INT64 result = CLR_NAN_64;
+ return (*((double*)((INT64*)&result)));
+ }
+
+ return (double)pow(x, y);
+FCIMPLEND
+
+/*====================================Round=====================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Round, double x)
+ FCALL_CONTRACT;
+
+ // If the number has no fractional part do nothing
+ // This shortcut is necessary to workaround precision loss in borderline cases on some platforms
+ if (x == (double)((INT64)x)) {
+ return x;
+ }
+
+ // We had a number that was equally close to 2 integers.
+ // We need to return the even one.
+
+ double tempVal = (x + 0.5);
+ double flrTempVal = floor(tempVal);
+
+ if ((flrTempVal == tempVal) && (fmod(tempVal, 2.0) != 0)) {
+ flrTempVal -= 1.0;
+ }
+
+ return _copysign(flrTempVal, x);
+FCIMPLEND
+
+/*=====================================Sin======================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Sin, double x)
+ FCALL_CONTRACT;
+
+ return (double)sin(x);
+FCIMPLEND
+
+/*=====================================Sinh=====================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Sinh, double x)
+ FCALL_CONTRACT;
+
+ return (double)sinh(x);
+FCIMPLEND
+
+/*=====================================Sqrt=====================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Sqrt, double x)
+ FCALL_CONTRACT;
+
+ return (double)sqrt(x);
+FCIMPLEND
+
+/*=====================================Tan======================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Tan, double x)
+ FCALL_CONTRACT;
+
+ return (double)tan(x);
+FCIMPLEND
+
+/*=====================================Tanh=====================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Tanh, double x)
+ FCALL_CONTRACT;
+
+ return (double)tanh(x);
+FCIMPLEND
+
+#ifdef _MSC_VER
+#pragma float_control(precise, on )
+#endif
+
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+///
+/// End of /fp:fast scope
+///
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-//
-// File: FloatNative.cpp
-//
-
-#include <common.h>
-
-#include "floatnative.h"
-#include "floatclass.h"
-
-#define IS_DBL_INFINITY(x) ((*((UINT64 *)((void *)&x)) & UI64(0x7FFFFFFFFFFFFFFF)) == UI64(0x7FF0000000000000))
-#define IS_DBL_ONE(x) ((*((UINT64 *)((void *)&x))) == UI64(0x3FF0000000000000))
-#define IS_DBL_NEGATIVEONE(x) ((*((UINT64 *)((void *)&x))) == UI64(0xBFF0000000000000))
-
-
-// Default compilation mode is /fp:precise, which disables fp intrinsics. This has caused
-// regression in floating point code. I've grouped all the helpers that are really simple
-// (where /fp:fast semantics are really unlikely to cause any regression) and grouped them
-// here in order to get back to Everett performance numbers
-
-////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////
-///
-/// Beggining of /fp:fast scope
-///
-////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////
-
-#ifdef _MSC_VER
-#pragma float_control(precise, off)
-#endif
-
-/*====================================Floor=====================================
-**
-==============================================================================*/
-FCIMPL1_V(double, COMDouble::Floor, double d)
- FCALL_CONTRACT;
-
- return (double) floor(d);
-FCIMPLEND
-
-
-/*====================================Ceil=====================================
-**
-==============================================================================*/
-FCIMPL1_V(double, COMDouble::Ceil, double d)
- FCALL_CONTRACT;
-
- return (double) ceil(d);
-FCIMPLEND
-
-/*=====================================Sqrt=====================================
-**
-==============================================================================*/
-FCIMPL1_V(double, COMDouble::Sqrt, double d)
- FCALL_CONTRACT;
-
- return (double) sqrt(d);
-FCIMPLEND
-
-/*=====================================Acos=====================================
-**
-==============================================================================*/
-FCIMPL1_V(double, COMDouble::Acos, double d)
- FCALL_CONTRACT;
-
- return (double) acos(d);
-FCIMPLEND
-
-
-/*=====================================Asin=====================================
-**
-==============================================================================*/
-FCIMPL1_V(double, COMDouble::Asin, double d)
- FCALL_CONTRACT;
-
- return (double) asin(d);
-FCIMPLEND
-
-
-/*=====================================AbsFlt=====================================
-**
-==============================================================================*/
-FCIMPL1_V(float, COMDouble::AbsFlt, float f)
- FCALL_CONTRACT;
-
- FCUnique(0x14);
-
- return fabsf(f);
-FCIMPLEND
-
-/*=====================================AbsDbl=====================================
-**
-==============================================================================*/
-FCIMPL1_V(double, COMDouble::AbsDbl, double d)
- FCALL_CONTRACT;
-
- return fabs(d);
-FCIMPLEND
-
-/*=====================================Atan=====================================
-**
-==============================================================================*/
-FCIMPL1_V(double, COMDouble::Atan, double d)
- FCALL_CONTRACT;
-
- return (double) atan(d);
-FCIMPLEND
-
-/*=====================================Atan2=====================================
-**
-==============================================================================*/
-FCIMPL2_VV(double, COMDouble::Atan2, double x, double y)
- FCALL_CONTRACT;
-
- // the intrinsic for Atan2 does not produce Nan for Atan2(+-inf,+-inf)
- if (IS_DBL_INFINITY(x) && IS_DBL_INFINITY(y)) {
- return(x / y); // create a NaN
- }
- return (double) atan2(x, y);
-FCIMPLEND
-
-// COMDouble::Sin/Cos/Tan are all implemented in JitHelpers_Fast.asm as x87 floating
-// point for code AMD64 (on Windows) because the CRT helpers is too slow (apparently they don't
-// have a /fp:fast v ersion).
-#if !defined(_TARGET_AMD64_) || defined(FEATURE_PAL)
-
-/*=====================================Sin=====================================
-**
-==============================================================================*/
-FCIMPL1_V(double, COMDouble::Sin, double d)
- FCALL_CONTRACT;
-
- return (double) sin(d);
-FCIMPLEND
-
-/*=====================================Cos=====================================
-**
-==============================================================================*/
-FCIMPL1_V(double, COMDouble::Cos, double d)
- FCALL_CONTRACT;
-
- return (double) cos(d);
-FCIMPLEND
-
-/*=====================================Tan=====================================
-**
-==============================================================================*/
-FCIMPL1_V(double, COMDouble::Tan, double d)
- FCALL_CONTRACT;
-
- return (double) tan(d);
-FCIMPLEND
-
-#endif // !defined(_TARGET_AMD64_) || defined(FEATURE_PAL)
-
-/*=====================================Sinh====================================
-**
-==============================================================================*/
-FCIMPL1_V(double, COMDouble::Sinh, double d)
- FCALL_CONTRACT;
-
- return (double) sinh(d);
-FCIMPLEND
-
-/*=====================================Cosh====================================
-**
-==============================================================================*/
-FCIMPL1_V(double, COMDouble::Cosh, double d)
- FCALL_CONTRACT;
-
- return (double) cosh(d);
-FCIMPLEND
-
-/*=====================================Tanh====================================
-**
-==============================================================================*/
-FCIMPL1_V(double, COMDouble::Tanh, double d)
- FCALL_CONTRACT;
-
- return (double) tanh(d);
-FCIMPLEND
-
-FCIMPL1(double, COMDouble::ModFDouble, double* pdblValue)
- FCALL_CONTRACT;
-
- double dblFrac;
- dblFrac = modf(*pdblValue, pdblValue);
- return dblFrac;
-FCIMPLEND
-
-#ifdef _MSC_VER
-#pragma float_control(precise, on )
-#endif
-
-////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////
-///
-/// End of /fp:fast scope
-///
-////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////
-//
-// Log, Log10 and Exp are slower with /fp:fast on SSE2 enabled HW (see #500373)
-// So we'll leave them as fp precise for the moment
-
-/*=====================================Log======================================
-**This is the natural log
-==============================================================================*/
-FCIMPL1_V(double, COMDouble::Log, double d)
- FCALL_CONTRACT;
-
- return (double) log(d);
-FCIMPLEND
-
-
-/*====================================Log10=====================================
-**This is log-10
-==============================================================================*/
-FCIMPL1_V(double, COMDouble::Log10, double d)
- FCALL_CONTRACT;
-
- return (double) log10(d);
-FCIMPLEND
-
-
-/*=====================================Exp======================================
-**
-==============================================================================*/
-FCIMPL1_V(double, COMDouble::Exp, double x)
- FCALL_CONTRACT;
-
- // The C intrinsic below does not handle +- infinity properly
- // so we handle these specially here
- if (IS_DBL_INFINITY(x)) {
- if (x < 0)
- return(+0.0);
- return(x); // Must be + infinity
- }
- return((double) exp(x));
-FCIMPLEND
-
-#if defined(_TARGET_X86_)
-/*=====================================Pow======================================
-**This is the power function. Simple powers are done inline, and special
- cases are sent to the CRT via the helper.
-==============================================================================*/
-FCIMPL2_VV(double, COMDouble::PowHelperSimple, double x, double y)
-{
- FCALL_CONTRACT;
-
- return (double) pow(x,y);
-}
-FCIMPLEND
-
-FCIMPL2_VV(double, COMDouble::PowHelper, double x, double y)
-{
- FCALL_CONTRACT;
-
- double r1;
-
- // TODO: we can get rid following code if VC fixes pow function someday.
- if(_isnan(y)) {
- return y; // IEEE 754-2008: NaN payload must be preserved
- }
- if(_isnan(x)) {
- return x; // IEEE 754-2008: NaN payload must be preserved
- }
- if(IS_DBL_INFINITY(y)) {
- if(IS_DBL_ONE(x)) {
- return x;
- }
-
- if(IS_DBL_NEGATIVEONE(x)) {
- *((INT64 *)(&r1)) = CLR_NAN_64;
- return r1;
- }
- }
-
- return (double) pow(x, y);
-}
-FCIMPLEND
-
-#if defined (_DEBUG)
-__declspec(naked) static double F_CALL_CONV PowRetail(double x, double y)
-#else
-__declspec(naked) double F_CALL_CONV COMDouble::Pow(double x, double y)
-#endif
-{
- WRAPPER_NO_CONTRACT;
- STATIC_CONTRACT_SO_TOLERANT;
-
- // Arguments:
- // exponent: esp+4
- // base: esp+12
-
- _asm
- {
- mov ecx, [esp+8] ; high dword of exponent
- mov edx, [esp+16] ; high dword of base
-
- and ecx, 7ff00000H ; check for special exponent
- cmp ecx, 7ff00000H
- je callHelper
-
- and edx, 7ff00000H ; check for special base
- cmp edx, 7ff00000H
- je callHelper
-
- test edx, 7ff00000H ; see if the base has a zero exponent
- jz test_if_we_have_zero_base
-
-base_is_not_zero:
-
- mov cl, [esp+19] ; Handle negative base in the helper
- and cl, 80H
- jnz callHelper
-
- jmp COMDouble::PowHelperSimple ;
-
-test_if_we_have_zero_base:
-
- mov eax, [esp+16]
- and eax, 000fffffH
- or eax, [esp+12]
- jnz base_is_not_zero
- ; fall through to the helper
-
-callHelper:
-
- jmp COMDouble::PowHelper ; The helper will return control
- ; directly to our caller.
- }
-}
-
-#ifdef _DEBUG
-
-#define EPSILON 0.0000000001
-
-void assertDoublesWithinRange(double r1, double r2)
-{
- WRAPPER_NO_CONTRACT;
-
- if (_finite(r1) && _finite(r2))
- {
- // Both numbers are finite--we need to check that they are close to
- // each other. If they are large (> 1), the error could also be large,
- // which is acceptable, so we compare the error against EPSILON*norm.
-
- double norm = max(fabs(r1), fabs(r2));
- double error = fabs(r1-r2);
-
- assert((error < (EPSILON * norm)) || (error < EPSILON));
- }
- else if (!_isnan(r1) && !_isnan(r2))
- {
- // At least one of r1 and r2 is infinite, so when multiplied by
- // (1 + EPSILON) they should be the same infinity.
-
- assert((r1 * (1 + EPSILON)) == (r2 * (1 + EPSILON)));
- }
- else
- {
- // Otherwise at least one of r1 or r2 is a Nan. Is that case, they better be in
- // the same class.
-
- assert(_fpclass(r1) == _fpclass(r2));
- }
-}
-
-FCIMPL2_VV(double, COMDouble::Pow, double x, double y)
-{
- FCALL_CONTRACT;
-
- double r1, r2;
-
- if(_isnan(y)) {
- return y; // IEEE 754-2008: NaN payload must be preserved
- }
- if(_isnan(x)) {
- return x; // IEEE 754-2008: NaN payload must be preserved
- }
-
- if(IS_DBL_INFINITY(y)) {
- if(IS_DBL_ONE(x)) {
- return x;
- }
-
- if(IS_DBL_NEGATIVEONE(x)) {
- *((INT64 *)(&r1)) = CLR_NAN_64;
- return r1;
- }
- }
-
- // Note that PowRetail expects the argument order to be reversed
-
- r1 = (double) PowRetail(y, x);
-
- r2 = (double) pow(x, y);
-
- // Can't do a floating point compare in case r1 and r2 aren't
- // valid fp numbers.
-
- assertDoublesWithinRange(r1, r2);
-
- return (double) r1;
-}
-FCIMPLEND
-
-#endif // _DEBUG
-
-#else // !defined(_TARGET_X86_)
-FCIMPL2_VV(double, COMDouble::Pow, double x, double y)
-{
- FCALL_CONTRACT;
-
- double r1;
-
- if(_isnan(y)) {
- return y; // IEEE 754-2008: NaN payload must be preserved
- }
- if(_isnan(x)) {
- return x; // IEEE 754-2008: NaN payload must be preserved
- }
-
- if(IS_DBL_INFINITY(y)) {
- if(IS_DBL_ONE(x)) {
- return x;
- }
-
- if(IS_DBL_NEGATIVEONE(x)) {
- *((INT64 *)(&r1)) = CLR_NAN_64;
- return r1;
- }
- }
-
- return (double) pow(x, y);
-}
-FCIMPLEND
-
-#endif // defined(_TARGET_X86_)
-
-
-/*====================================Round=====================================
-**
-==============================================================================*/
-#if defined(_TARGET_X86_)
-__declspec(naked)
-double __fastcall COMDouble::Round(double d)
-{
- LIMITED_METHOD_CONTRACT;
-
- __asm {
- fld QWORD PTR [ESP+4]
- frndint
- ret 8
- }
-}
-
-#else // !defined(_TARGET_X86_)
-FCIMPL1_V(double, COMDouble::Round, double d)
- FCALL_CONTRACT;
-
- double tempVal;
- double flrTempVal;
- // If the number has no fractional part do nothing
- // This shortcut is necessary to workaround precision loss in borderline cases on some platforms
- if ( d == (double)(__int64)d )
- return d;
- tempVal = (d+0.5);
- //We had a number that was equally close to 2 integers.
- //We need to return the even one.
- flrTempVal = floor(tempVal);
- if (flrTempVal==tempVal) {
- if (0 != fmod(tempVal, 2.0)) {
- flrTempVal -= 1.0;
- }
- }
- flrTempVal = _copysign(flrTempVal, d);
- return flrTempVal;
-FCIMPLEND
-#endif // defined(_TARGET_X86_)
-
-
+++ /dev/null
-// 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
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+// File: FloatSingle.cpp
+//
+
+#include <common.h>
+
+#include "floatsingle.h"
+
+#define IS_FLT_INFINITY(x) (((*((INT32*)((void*)&x))) & 0x7FFFFFFF) == 0x7F800000)
+
+// The default compilation mode is /fp:precise, which disables floating-point intrinsics. This
+// default compilation mode has previously caused performance regressions in floating-point code.
+// We enable /fp:fast semantics for the majority of the math functions, as it will speed up performance
+// and is really unlikely to cause any other code regressions.
+
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+///
+/// beginning of /fp:fast scope
+///
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef _MSC_VER
+#pragma float_control(precise, off)
+#endif
+
+/*=====================================Abs=====================================
+**
+==============================================================================*/
+FCIMPL1(float, COMSingle::Abs, float x)
+ FCALL_CONTRACT;
+
+ return (float)fabsf(x);
+FCIMPLEND
+
+#ifdef _MSC_VER
+#pragma float_control(precise, on )
+#endif
+
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+///
+/// End of /fp:fast scope
+///
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#ifndef _FLOATCLASS_H_
-#define _FLOATCLASS_H_
-
-#include <object.h>
-#include <fcall.h>
-
-class COMDouble {
-public:
- FCDECL1_V(static double, Floor, double d);
- FCDECL1_V(static double, Sqrt, double d);
- FCDECL1_V(static double, Log, double d);
- FCDECL1_V(static double, Log10, double d);
- FCDECL1_V(static double, Exp, double d);
- FCDECL2_VV(static double, Pow, double x, double y);
- FCDECL1_V(static double, Acos, double d);
- FCDECL1_V(static double, Asin, double d);
- FCDECL1_V(static double, Atan, double d);
- FCDECL2_VV(static double, Atan2, double x, double y);
- FCDECL1_V(static double, Cos, double d);
- FCDECL1_V(static double, Sin, double d);
- FCDECL1_V(static double, Tan, double d);
- FCDECL1_V(static double, Cosh, double d);
- FCDECL1_V(static double, Sinh, double d);
- FCDECL1_V(static double, Tanh, double d);
- FCDECL1_V(static double, Round, double d);
- FCDECL1_V(static double, Ceil, double d);
- FCDECL1_V(static float, AbsFlt, float f);
- FCDECL1_V(static double, AbsDbl, double d);
- FCDECL1(static double, ModFDouble, double* d);
-
-#if defined(_TARGET_X86_)
-//private:
- FCDECL2_VV(static double, PowHelper, double x, double y);
- FCDECL2_VV(static double, PowHelperSimple, double x, double y);
-#endif
-
-};
-
-
-#endif // _FLOATCLASS_H_
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef _FLOATDOUBLE_H_
+#define _FLOATDOUBLE_H_
+
+#include <object.h>
+#include <fcall.h>
+
+class COMDouble {
+public:
+ FCDECL1_V(static double, Abs, double x);
+ FCDECL1_V(static double, Acos, double x);
+ FCDECL1_V(static double, Asin, double x);
+ FCDECL1_V(static double, Atan, double x);
+ FCDECL2_VV(static double, Atan2, double y, double x);
+ FCDECL1_V(static double, Ceil, double x);
+ FCDECL1_V(static double, Cos, double x);
+ FCDECL1_V(static double, Cosh, double x);
+ FCDECL1_V(static double, Exp, double x);
+ FCDECL1_V(static double, Floor, double x);
+ FCDECL1_V(static double, Log, double x);
+ FCDECL1_V(static double, Log10, double x);
+ FCDECL1(static double, ModF, double* iptr);
+ FCDECL2_VV(static double, Pow, double x, double y);
+ FCDECL1_V(static double, Round, double x);
+ FCDECL1_V(static double, Sin, double x);
+ FCDECL1_V(static double, Sinh, double x);
+ FCDECL1_V(static double, Sqrt, double x);
+ FCDECL1_V(static double, Tan, double x);
+ FCDECL1_V(static double, Tanh, double x);
+};
+
+#endif // _FLOATDOUBLE_H_
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef _FLOATSINGLE_H_
+#define _FLOATSINGLE_H_
+
+#include <object.h>
+#include <fcall.h>
+
+class COMSingle {
+public:
+ FCDECL1(static float, Abs, float x);
+};
+
+#endif // _FLOATSINGLE_H_
// 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);
}
static unsigned __int64 convertDoubleToUInt64(double d);
- static double round(double d);
+ static double round(double x);
};
#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
}
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
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
Module Name:
- finite.cpp
+ math.cpp
Abstract:
- Implementation of _finite function (Windows specific runtime function).
+ Implementation of math family functions.
#include "pal/palinternal.h"
#include "pal/dbgmsg.h"
+
#include <math.h>
#if HAVE_IEEEFP_H
#include <ieeefp.h>
#endif // HAVE_IEEEFP_H
+
#include <errno.h>
-#define PAL_NAN sqrt(-1.0)
-#define PAL_POSINF -log(0.0)
-#define PAL_NEGINF log(0.0)
+#define PAL_NAN_DBL sqrt(-1.0)
+#define PAL_POSINF_DBL -log(0.0)
+#define PAL_NEGINF_DBL log(0.0)
SET_DEFAULT_DEBUG_CHANNEL(CRT);
-
/*++
Function:
_finite
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;
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;
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;
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;
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;
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)
{
}
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;
PALIMPORT LONG __cdecl PAL_labs(LONG l)
{
long lRet;
-
PERF_ENTRY(labs);
ENTRY("labs (l=%ld)\n", 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.
}
/*++
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;
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;
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)
*
* 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;
#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
#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
#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
add_subdirectory(exit)
add_subdirectory(exp)
add_subdirectory(fabs)
+add_subdirectory(fabsf)
add_subdirectory(fclose)
add_subdirectory(feof)
add_subdirectory(ferror)
add_subdirectory(fgets)
add_subdirectory(floor)
add_subdirectory(fmod)
+add_subdirectory(fmodf)
add_subdirectory(fopen)
add_subdirectory(fprintf)
add_subdirectory(fputs)
add_subdirectory(memmove)
add_subdirectory(memset)
add_subdirectory(modf)
+add_subdirectory(modff)
add_subdirectory(pow)
add_subdirectory(printf)
add_subdirectory(qsort)
add_subdirectory(_wsplitpath)
add_subdirectory(_wtoi)
add_subdirectory(__iscsym)
-
cmake_minimum_required(VERSION 2.8.12.2)
add_subdirectory(test1)
-
** of floating point numbers (NaN, -Infinity, Infinity,
** finite nonzero, unnormalized, 0, and -0)
**
-**
**==========================================================================*/
-
#include <palsuite.h>
/*
*/
+#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;
}
-
-
-
-
-
-
-
-
-
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).
cmake_minimum_required(VERSION 2.8.12.2)
add_subdirectory(test1)
-
** the fraction to positive and negative, at which point it should return
** the true value.
**
-**
**==========================================================================*/
#include <palsuite.h>
-#define TO_DOUBLE(a) (*(double*)&a)
-#define TO_I64(a) (*(INT64*) &a)
+#define TO_DOUBLE(x) (*((double*)((void*)&x)))
+#define TO_I64(x) (*((INT64*)((void*)&x)))
/*
* NaN: any double with maximum exponent (0x7ff) and non-zero fraction
*/
int __cdecl main(int argc, char *argv[])
{
- UINT64 PosInf=0;
- UINT64 NegInf=0;
- UINT64 val=0;
-
/*
* Initialize the PAL and return FAIL if this fails
*/
- if (0 != (PAL_Initialize(argc, argv)))
+ if (PAL_Initialize(argc, argv) != 0)
{
return FAIL;
}
+
/*
* Try some trivial values
*/
- if (_isnan(0))
+ if (_isnan(0.0))
{
- Fail ("_isnan() incorrectly identified %f as NaN!\n", 0);
+ Fail("_isnan() incorrectly identified %f as NaN!\n", 0.0);
}
- if (_isnan(1.2423456))
+
+ if (_isnan(1.23456))
{
- Fail ("_isnan() incorrectly identified %f as NaN!\n", 0);
+ Fail("_isnan() incorrectly identified %f as NaN!\n", 1.234567);
}
- if (_isnan(42))
+
+ if (_isnan(42.0))
{
- Fail ("_isnan() incorrectly identified %f as NaN!\n", 0);
+ Fail("_isnan() incorrectly identified %f as NaN!\n", 42.0);
}
-
- PosInf = 0x7ff00000;
- PosInf <<=32;
-
- NegInf = 0xfff00000;
- NegInf <<=32;
+ UINT64 lneginf = UI64(0xfff0000000000000);
+ UINT64 lposinf = UI64(0x7ff0000000000000);
+
+ double neginf = TO_DOUBLE(lneginf);
+ double posinf = TO_DOUBLE(lposinf);
/*
* Try positive and negative infinity
*/
- if (_isnan(TO_DOUBLE(PosInf)))
+ if (_isnan(neginf))
{
- Fail ("_isnan() incorrectly identified %I64x as NaN!\n", PosInf);
+ Fail("_isnan() incorrectly identified negative infinity as NaN!\n");
}
- if (_isnan(TO_DOUBLE(NegInf)))
+ if (_isnan(posinf))
{
- Fail ("_isnan() incorrectly identified %I64x as NaN!\n", NegInf);
+ Fail("_isnan() incorrectly identified infinity as NaN!\n");
}
/*
* Try setting the least significant bit of the fraction,
* positive and negative
*/
- val = PosInf + 1;
- if (!_isnan(TO_DOUBLE(val)))
+ UINT64 lsnan = UI64(0xfff0000000000001);
+ double snan = TO_DOUBLE(lsnan);
+
+ if (!_isnan(snan))
{
- Fail ("_isnan() failed to identify %I64x as NaN!\n", val);
+ Fail("_isnan() failed to identify %I64x as NaN!\n", lsnan);
}
- val = NegInf + 1;
- if (!_isnan(TO_DOUBLE(val)))
+ UINT64 lqnan = UI64(0x7ff0000000000001);
+ double qnan = TO_DOUBLE(lqnan);
+
+ if (!_isnan(qnan))
{
- Fail ("_isnan() failed to identify %I64x as NaN!\n", val);
+ Fail("_isnan() failed to identify %I64x as NaN!\n", lqnan);
}
-
/*
* Try setting the most significant bit of the fraction,
* positive and negative
*/
- val = 0x7ff80000;
- val <<=32;
- if (!_isnan(TO_DOUBLE(val)))
+ lsnan = UI64(0xfff8000000000000);
+ snan = TO_DOUBLE(lsnan);
+
+ if (!_isnan(snan))
{
- Fail ("_isnan() failed to identify %I64x as NaN!\n", val);
+ Fail ("_isnan() failed to identify %I64x as NaN!\n", lsnan);
}
- val = 0xfff80000;
- val <<=32;
- if (!_isnan(TO_DOUBLE(val)))
+ lqnan = UI64(0x7ff8000000000000);
+ qnan = TO_DOUBLE(lqnan);
+
+ if (!_isnan(qnan))
{
- Fail ("_isnan() failed to identify %I64x as NaN!\n", val);
+ Fail ("_isnan() failed to identify %I64x as NaN!\n", lqnan);
}
PAL_Terminate();
-
return PASS;
}
-
cmake_minimum_required(VERSION 2.8.12.2)
add_subdirectory(test1)
-
**
** Source: test1.c
**
-** Purpose: Test to ensure that acos returns correct values.
+** Purpose: Test to ensure that acos return the correct values
**
** Dependencies: PAL_Initialize
** PAL_Terminate
-** Fail
+** Fail
** fabs
-** _finite
-**
-
**
**===========================================================================*/
#include <palsuite.h>
-/* Error acceptance level to the 7th decimal */
-#define DELTA 0.0000001
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
/**
* Helper test structure
*/
struct test
{
- double value; /* value to test the function with */
- double result; /* expected result */
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
};
/**
- * main
- *
- * executable entry point
+ * validate
+ *
+ * test validation function
*/
-INT __cdecl main(INT argc, CHAR **argv)
+void __cdecl validate(double value, double expected, double variance)
{
- double pi = 3.1415926535;
- int i;
+ double result = acos(value);
- struct test tests[] =
- {
- /* Value test result */
- { 1, 0 },
- { 0.9, 0.451026811796 },
- { 0.8, 0.643501108793 },
- { 0.7, 0.795398830184 },
- { 0.6, 0.927295218002 },
- { 0.5, 1.047197551197 },
- { 0.4, 1.159279480727 },
- { 0.3, 1.266103672779 },
- { 0.2, 1.369438406005 },
- { 0.1, 1.470628905633 },
- { 0, pi/2.0 },
- { -0.1, 1.670963747956 },
- { -0.2, 1.772154247585 },
- { -0.3, 1.875488980810 },
- { -0.4, 1.982313172862 },
- { -0.5, 2.094395102393 },
- { -0.6, 2.214297435588 },
- { -0.7, 2.346193823406 },
- { -0.8, 2.498091544797 },
- { -0.9, 2.690565841794 },
- { -1, pi }
- };
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
- double outofrange[] =
+ if (delta > variance)
{
- -864278.51, -1000.2, -2, 2, 10, 100, 1234567.8, 1.7e308
- };
+ Fail("acos(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, expected);
+ }
+}
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result = acos(value);
- /* PAL initialization */
- if( PAL_Initialize(argc, argv) != 0 )
+ if (!_isnan(result))
{
- return (FAIL);
+ Fail("acos(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_NAN);
}
+}
- for( i = 0; i < sizeof(tests) / sizeof(struct test); i++)
+/**
+ * main
+ *
+ * executable entry point
+ */
+int __cdecl main(int argc, char **argv)
+{
+ struct test tests[] =
{
- double result;
- double testDelta;
-
- result = acos( tests[i].value );
+ /* value expected variance */
+ { -1, 3.1415926535897932, PAL_EPSILON * 10 }, // expected: pi
+ { -0.91173391478696510, 2.7182818284590452, PAL_EPSILON * 10 }, // expected: e
+ { -0.66820151019031295, 2.3025850929940457, PAL_EPSILON * 10 }, // expected: ln(10)
+ { 0, 1.5707963267948966, PAL_EPSILON * 10 }, // expected: pi / 2
+ { 0.12775121753523991, 1.4426950408889634, PAL_EPSILON * 10 }, // expected: log2(e)
+ { 0.15594369476537447, 1.4142135623730950, PAL_EPSILON * 10 }, // expected: sqrt(2)
+ { 0.42812514788535792, 1.1283791670955126, PAL_EPSILON * 10 }, // expected: 2 / sqrt(pi)
+ { 0.54030230586813972, 1, PAL_EPSILON * 10 },
+ { 0.70710678118654752, 0.78539816339744831, PAL_EPSILON }, // expected: pi / 4, value: 1 / sqrt(2)
+ { 0.76024459707563015, 0.70710678118654752, PAL_EPSILON }, // expected: 1 / sqrt(2)
+ { 0.76923890136397213, 0.69314718055994531, PAL_EPSILON }, // expected: ln(2)
+ { 0.80410982822879171, 0.63661977236758134, PAL_EPSILON }, // expected: 2 / pi
+ { 0.90716712923909839, 0.43429448190325183, PAL_EPSILON }, // expected: log10(e)
+ { 0.94976571538163866, 0.31830988618379067, PAL_EPSILON }, // expected: 1 / pi
+ { 1, 0, PAL_EPSILON },
+ };
- /*
- * The test is valid when the difference between the
- * result and the expectation is less than DELTA
- */
- testDelta = fabs( result - tests[i].result );
- if( testDelta >= DELTA )
- {
- Fail( "acos(%g) returned %20.10f"
- " when it should have returned %20.10f",
- tests[i].value,
- result,
- tests[i].result );
- }
+ /* PAL initialization */
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
}
- for( i = 0; i < sizeof(outofrange) / sizeof(double); i++)
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
{
- double result;
-
- result = acos( outofrange[i] );
-
- /* The test is valid when the function returns an infinite result */
- if( _finite( result ) )
- {
- Fail( "acos(%g) returned %20.10f"
- " when it should have returned -1.#IND00000000",
- outofrange[i],
- result );
- }
+ validate(tests[i].value, tests[i].expected, tests[i].variance);
}
+
+ validate_isnan(PAL_NEGINF);
+ validate_isnan(PAL_NAN);
+ validate_isnan(PAL_POSINF);
PAL_Terminate();
return PASS;
= 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.
-
-
-
cmake_minimum_required(VERSION 2.8.12.2)
add_subdirectory(test1)
-
**
** Source: test1.c
**
-** Purpose: Test to ensure that asin returns correct values.
+** Purpose: Test to ensure that asin return the correct values
**
** Dependencies: PAL_Initialize
** PAL_Terminate
-** Fail
+** Fail
** fabs
-** _finite
-**
-
**
**===========================================================================*/
#include <palsuite.h>
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
-#define DELTA 0.0000001 /* Error acceptance level to the 7th decimal */
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
/**
* Helper test structure
*/
struct test
{
- double value; /* value to test the function with */
- double result; /* expected result */
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
};
/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+ double result = asin(value);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("asin(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result = asin(value);
+
+ if (!_isnan(result))
+ {
+ Fail("asin(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_NAN);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning +INF
+ */
+void __cdecl validate_isinf_positive(double value)
+{
+ double result = asin(value);
+
+ if (result != PAL_POSINF)
+ {
+ Fail("asin(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_POSINF);
+ }
+}
+
+/**
* main
*
* executable entry point
*/
-INT __cdecl main(INT argc, CHAR **argv)
+int __cdecl main(int argc, char **argv)
{
- double pi = 3.1415926535;
- int i;
-
struct test tests[] =
{
- /* Value test result */
- { 1, pi/2.0 },
- { 0.9, 1.119769514999 },
- { 0.8, 0.927295218002 },
- { 0.7, 0.775397496611 },
- { 0.6, 0.643501108793 },
- { 0.5, 0.523598775598 },
- { 0.4, 0.411516846067 },
- { 0.3, 0.304692654015 },
- { 0.2, 0.201357920790 },
- { 0.1, 0.100167421162 },
- { 0, 0 },
- { -0.1, -0.100167421162 },
- { -0.2, -0.201357920790 },
- { -0.3, -0.304692654015 },
- { -0.4, -0.411516846067 },
- { -0.5, -0.523598775598 },
- { -0.6, -0.643501108793 },
- { -0.7, -0.775397496611 },
- { -0.8, -0.927295218002 },
- { -0.9, -1.119769514999 },
- { -1, -(pi/2.0) }
- };
-
- double outofrange[] =
- {
- -864278.51, -1000.2, -2, 2, 10, 100, 1234567.8, 1.7e308
+ /* value expected variance */
+ { 0, 0, PAL_EPSILON },
+ { 0.31296179620778659, 0.31830988618379067, PAL_EPSILON }, // expected: 1 / pi
+ { 0.41078129050290870, 0.42331082513074800, PAL_EPSILON }, // expected: pi - e
+ { 0.42077048331375735, 0.43429448190325183, PAL_EPSILON }, // expected: log10(e)
+ { 0.59448076852482208, 0.63661977236758134, PAL_EPSILON }, // expected: 2 / pi
+ { 0.63896127631363480, 0.69314718055994531, PAL_EPSILON }, // expected: ln(2)
+ { 0.64963693908006244, 0.70710678118654752, PAL_EPSILON }, // expected: 1 / sqrt(2)
+ { 0.70710678118654752, 0.78539816339744831, PAL_EPSILON }, // expected: pi / 4, value: 1 / sqrt(2)
+ { 0.74398033695749319, 0.83900756059574755, PAL_EPSILON }, // expected: pi - ln(10)
+ { 0.84147098480789651, 1, PAL_EPSILON * 10 },
+ { 0.90371945743584630, 1.1283791670955126, PAL_EPSILON * 10 }, // expected: 2 / sqrt(pi)
+ { 0.98776594599273553, 1.4142135623730950, PAL_EPSILON * 10 }, // expected: sqrt(2)
+ { 0.99180624439366372, 1.4426950408889634, PAL_EPSILON * 10 }, // expected: log2(e)
+ { 1, 1.5707963267948966, PAL_EPSILON * 10 }, // expected: pi / 2
};
-
/* PAL initialization */
- if( PAL_Initialize(argc, argv) != 0 )
- {
- return (FAIL);
- }
-
- for( i = 0; i < sizeof(tests) / sizeof(struct test); i++)
+ if (PAL_Initialize(argc, argv) != 0)
{
- double result;
- double testDelta;
-
- result = asin( tests[i].value );
-
- /*
- * The test is valid when the difference between the
- * result and the expectation is less than DELTA
- */
- testDelta = fabs( result - tests[i].result );
- if( testDelta >= DELTA )
- {
- Fail( "asin(%g) returned %20.10f"
- " when it should have returned %20.10f",
- tests[i].value,
- result,
- tests[i].result );
- }
+ return FAIL;
}
- for( i = 0; i < sizeof(outofrange) / sizeof(double); i++)
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
{
- double result;
-
- result = asin( outofrange[i] );
-
- /* The test is valid when the function returns an infinite result */
- if( _finite( result ) )
- {
- Fail( "asin(%g) returned %20.10f"
- " when it should have returned -1.#IND00000000",
- outofrange[i],
- result );
- }
+ validate( tests[i].value, tests[i].expected, tests[i].variance);
+ validate(-tests[i].value, -tests[i].expected, tests[i].variance);
}
+ validate_isnan(PAL_NEGINF);
+ validate_isnan(PAL_NAN);
+ validate_isnan(PAL_POSINF);
+
PAL_Terminate();
return PASS;
}
-
-
-
-
-
-
-
-
-
-
-
-
-
= 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.
-
-
-
cmake_minimum_required(VERSION 2.8.12.2)
add_subdirectory(test1)
-
**
** Source: test1.c
**
-** Purpose: Test to ensure that atan returns correct values.
+** Purpose: Test to ensure that atan return the correct values
**
** Dependencies: PAL_Initialize
** PAL_Terminate
-** Fail
+** Fail
** fabs
-**
-
**
**===========================================================================*/
#include <palsuite.h>
-#define DELTA 0.0000001 /* Error acceptance level to the 7th decimal */
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
/**
* Helper test structure
*/
struct test
{
- double value; /* value to test the function with */
- double result; /* expected result */
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
};
/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+ double result = atan(value);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("atan(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result = atan(value);
+
+ if (!_isnan(result))
+ {
+ Fail("atan(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_NAN);
+ }
+}
+
+/**
* main
*
* executable entry point
*/
-INT __cdecl main(INT argc, CHAR **argv)
+int __cdecl main(int argc, char **argv)
{
- double pi = 3.1415926535;
- int i;
-
struct test tests[] =
{
- /* Value test result */
- { -1.7976931348623158e+307, -(pi/2) },
- { -25928.789941099276, -1.570757759627 },
- { -10162.054261909849, -1.570697921495 },
- { -7742.279976805932, -1.570667165876 },
- { -4027.241187780389, -1.570548017858 },
- { -2020.329477828303, -1.570301358064 },
- { -928.811975463118, -1.569719683039 },
- { -0.993835261086, -0.782306273415 },
- { -0.936490981780, -0.752613986257 },
- { -0.884395886105, -0.724126849580 },
- { -0.728537858211, -0.629623252584 },
- { -0.571733756523, -0.519376146611 },
- { -0.370342112491, -0.354680802574 },
- { -0.264778588214, -0.258838835750 },
- { -0.199255348369, -0.196679446239 },
- { -0.077700125126, -0.077544322548 },
- { -0.036713766900, -0.036697284724 },
- { 0, 0},
- { 0.284035767693, 0.276747134475 },
- { 0.329264198737, 0.318083873607 },
- { 0.332560197760, 0.321054571066 },
- { 0.338206122013, 0.326129634676 },
- { 0.421887874996, 0.399231699263 },
- { 0.645222327342, 0.573009239835 },
- { 0.648396252327, 0.575246979388 },
- { 0.721427045503, 0.624962252188 },
- { 0.723685415204, 0.626445984185 },
- { 0.747856074709, 0.642127583998 },
- { 401.853083895383, 1.568307860298 },
- { 1579.672322763756, 1.570163284200 },
- { 2540.318308053835, 1.570402675359 },
- { 6105.661946470535, 1.570632544391 },
- { 10221.297708059939, 1.570698491860 },
- { 17155.000305185094, 1.570738034753 },
- { 20600.197424237798, 1.570747783571 },
- { 1.7976931348623158e+308, pi/2 }
+ /* value expected variance */
+ { 0, 0, PAL_EPSILON },
+ { 0.32951473309607836, 0.31830988618379067, PAL_EPSILON }, // expected: 1 / pi
+ { 0.45054953406980750, 0.42331082513074800, PAL_EPSILON }, // expected: pi - e
+ { 0.46382906716062964, 0.43429448190325183, PAL_EPSILON }, // expected: log10(e)
+ { 0.73930295048660405, 0.63661977236758134, PAL_EPSILON }, // expected: 2 / pi
+ { 0.83064087786078395, 0.69314718055994531, PAL_EPSILON }, // expected: ln(2)
+ { 0.85451043200960189, 0.70710678118654752, PAL_EPSILON }, // expected: 1 / sqrt(2)
+ { 1, 0.78539816339744831, PAL_EPSILON }, // expected: pi / 4
+ { 1.1134071468135374, 0.83900756059574755, PAL_EPSILON }, // expected: pi - ln(10)
+ { 1.5574077246549022, 1, PAL_EPSILON * 10 },
+ { 2.1108768356626451, 1.1283791670955126, PAL_EPSILON * 10 }, // expected: 2 / sqrt(pi)
+ { 6.3341191670421916, 1.4142135623730950, PAL_EPSILON * 10 }, // expected: sqrt(2)
+ { 7.7635756709721848, 1.4426950408889634, PAL_EPSILON * 10 }, // expected: log2(e)
+ { PAL_POSINF, 1.5707963267948966, PAL_EPSILON * 10 }, // expected: pi / 2
};
-
/* PAL initialization */
- if( PAL_Initialize(argc, argv) != 0 )
+ if (PAL_Initialize(argc, argv) != 0)
{
- return (FAIL);
+ return FAIL;
}
- for( i = 0; i < sizeof(tests) / sizeof(struct test); i++)
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
{
- double result;
- double testDelta;
-
- result = atan( tests[i].value );
-
- /*
- * The test is valid when the difference between the
- * result and the expectation is less than DELTA
- */
- testDelta = fabs( result - tests[i].result );
- if( testDelta >= DELTA )
- {
- Fail( "atan(%g) returned %20.10f"
- " when it should have returned %20.10f",
- tests[i].value,
- result,
- tests[i].result );
- }
+ validate( tests[i].value, tests[i].expected, tests[i].variance);
+ validate(-tests[i].value, -tests[i].expected, tests[i].variance);
}
+ validate_isnan(PAL_NAN);
+
PAL_Terminate();
return PASS;
}
Description
= Passes a series of values to the atan() function,
= checking each for the expected result.
-
-
-
cmake_minimum_required(VERSION 2.8.12.2)
add_subdirectory(test1)
-
** Tests with positive and negative values of x and y to ensure
** atan2 is returning results from the correct quadrant.
**
-**
**===================================================================*/
#include <palsuite.h>
-#define DELTA 0.0000001 //Error acceptance level to the 7th decimal
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
struct test
{
- double x;
- double y;
- double result; // expected result
+ double y; /* second component of the value to test the function with */
+ double x; /* first component of the value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
};
-
-void DoTest(double x, double y, double expected)
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double y, double x, double expected, double variance)
{
- double result;
- double testDelta;
+ double result = atan2(y, x);
- result = atan2(x, y);
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
- // The test is valid when the difference between the
- // result and the expectation is less than DELTA
- testDelta = fabs(result - expected);
- if( testDelta >= DELTA )
+ if (delta > variance)
{
- Fail( "atan2(%g, %g) returned %g when it should have returned %g",
- x, y, result, expected);
+ Fail("atan2(%g, %g) returned %20.17g when it should have returned %20.17g",
+ y, x, result, expected);
}
}
-int __cdecl main(int argc, char **argv)
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double y, double x)
{
- double pi = 3.1415926535;
- int i;
+ double result = atan2(y, x);
+ if (!_isnan(result))
+ {
+ Fail("atan2(%g, %g) returned %20.17g when it should have returned %20.17g",
+ y, x, result, PAL_NAN);
+ }
+}
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+int __cdecl main(int argc, char **argv)
+{
struct test tests[] =
{
- {0, 0, 0},
- {0, 1, 0},
- {0.104528463, 0.994521895, 0.104719755},
- {0.207911691, 0.978147601, 0.20943951},
- {0.309016994, 0.951056516, 0.314159265},
- {0.406736643, 0.913545458, 0.41887902},
- {0.5, 0.866025404, 0.523598776},
- {0.587785252, 0.809016994, 0.628318531},
- {0.669130606, 0.743144825, 0.733038286},
- {0.743144825, 0.669130606, 0.837758041},
- {0.809016994, 0.587785252, 0.942477796},
- {0.866025404, 0.5, 1.04719755},
- {0.913545458, 0.406736643, 1.15191731},
- {0.951056516, 0.309016994, 1.25663706},
- {0.978147601, 0.207911691, 1.36135682},
- {0.994521895, 0.104528463, 1.46607657},
- {1, 4.48965922e-011, 1.57079633},
+ /* y x expected variance */
+ { 0, PAL_POSINF, 0, PAL_EPSILON },
+ { 0, 0, 0, PAL_EPSILON },
+ { 0.31296179620778659, 0.94976571538163866, 0.31830988618379067, PAL_EPSILON }, // expected: 1 / pi
+ { 0.42077048331375735, 0.90716712923909839, 0.43429448190325183, PAL_EPSILON }, // expected: log10(e)
+ { 0.59448076852482208, 0.80410982822879171, 0.63661977236758134, PAL_EPSILON }, // expected: 2 / pi
+ { 0.63896127631363480, 0.76923890136397213, 0.69314718055994531, PAL_EPSILON }, // expected: ln(2)
+ { 0.64963693908006244, 0.76024459707563015, 0.70710678118654752, PAL_EPSILON }, // expected: 1 / sqrt(2)
+ { 0.70710678118654752, 0.70710678118654752, 0.78539816339744831, PAL_EPSILON }, // expected: pi / 4, value: 1 / sqrt(2)
+ { 1, 1, 0.78539816339744831, PAL_EPSILON }, // expected: pi / 4
+ { PAL_POSINF, PAL_POSINF, 0.78539816339744831, PAL_EPSILON }, // expected: pi / 4
+ { 0.84147098480789651, 0.54030230586813972, 1, PAL_EPSILON * 10 },
+ { 0.90371945743584630, 0.42812514788535792, 1.1283791670955126, PAL_EPSILON * 10 }, // expected: 2 / sqrt(pi)
+ { 0.98776594599273553, 0.15594369476537447, 1.4142135623730950, PAL_EPSILON * 10 }, // expected: sqrt(2)
+ { 0.99180624439366372, 0.12775121753523991, 1.4426950408889634, PAL_EPSILON * 10 }, // expected: log2(e)
+ { 1, 0, 1.5707963267948966, PAL_EPSILON * 10 }, // expected: pi / 2
+ { PAL_POSINF, 0, 1.5707963267948966, PAL_EPSILON * 10 }, // expected: pi / 2
+ { PAL_POSINF, 1, 1.5707963267948966, PAL_EPSILON * 10 }, // expected: pi / 2
+ { 0.74398033695749319, -0.66820151019031295, 2.3025850929940457, PAL_EPSILON * 10 }, // expected: ln(10)
+ { 0.41078129050290870, -0.91173391478696510, 2.7182818284590452, PAL_EPSILON * 10 }, // expected: e
+ { 0, -1, 3.1415926535897932, PAL_EPSILON * 10 }, // expected: pi
+ { 1, PAL_POSINF, 0, PAL_EPSILON },
};
-
if (PAL_Initialize(argc, argv) != 0)
{
- return FAIL;
+ return FAIL;
}
- for( i = 0; i < sizeof(tests) / sizeof(struct test); i++)
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
{
- DoTest(tests[i].x, tests[i].y, tests[i].result);
- DoTest(-tests[i].x, tests[i].y, -tests[i].result);
- DoTest(tests[i].x, -tests[i].y, pi - tests[i].result);
- DoTest(-tests[i].x, -tests[i].y, tests[i].result - pi);
+ const double pi = 3.1415926535897932;
+
+ validate( tests[i].y, tests[i].x, tests[i].expected, tests[i].variance);
+ validate(-tests[i].y, tests[i].x, -tests[i].expected, tests[i].variance);
+ validate( tests[i].y, -tests[i].x, pi - tests[i].expected, tests[i].variance);
+ validate(-tests[i].y, -tests[i].x, tests[i].expected - pi, tests[i].variance);
}
+
+ validate_isnan(PAL_NEGINF, PAL_NAN);
+ validate_isnan(PAL_NAN, PAL_NEGINF);
+ validate_isnan(PAL_NAN, PAL_POSINF);
+ validate_isnan(PAL_POSINF, PAL_NAN);
+
+ validate_isnan(PAL_NAN, -1);
+ validate_isnan(PAL_NAN, -0.0);
+ validate_isnan(PAL_NAN, 0);
+ validate_isnan(PAL_NAN, 1);
+
+ validate_isnan(-1, PAL_NAN);
+ validate_isnan(-0.0, PAL_NAN);
+ validate_isnan( 0, PAL_NAN);
+ validate_isnan( 1, PAL_NAN);
+
+ validate_isnan(PAL_NAN, PAL_NAN);
PAL_Terminate();
return PASS;
cmake_minimum_required(VERSION 2.8.12.2)
add_subdirectory(test1)
-
** negative infinity. Makes sure that calling ceil on NaN returns
** NaN
**
-**
**==========================================================================*/
#include <palsuite.h>
-typedef struct
-{
- double value;
- double ceilVal;
-} testCase;
-
-typedef struct
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
{
- INT64 value;
- INT64 ceilVal;
-} extremeCase;
-
-#define INT64_TO_DOUBLE(a) (*(double*)&a)
-
-int __cdecl main(int argc, char *argv[])
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
+};
+
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
{
- INT64 NaN = I64(0x7ff8000000000000);
- double value;
- double ceilVal;
- double ret;
- int i;
-
- testCase testCases[] =
- {
- {2.8, 3},
- {-2.8, -2},
- {5.5, 6},
- {-5.5, -5},
- {3, 3},
- {-3, -3},
- {0, 0},
- };
- extremeCase extremeCases[] =
- {
- /* Positive Infinity */
- {I64(0x7ff0000000000000), I64(0x7ff0000000000000)},
- /* Negative Infinitey */
- {I64(0xfff0000000000000), I64(0xfff0000000000000)},
- /* Smallest possible +value */
- {I64(0x0000000000000001), I64(0x3FF0000000000000)},
- /* Smallest possible -value */
- {I64(0x8000000000000001), I64(0x8000000000000000)},
- };
-
+ double result = ceil(value);
/*
- * Initialize the PAL and return FAIL if this fails
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
*/
- if (0 != (PAL_Initialize(argc, argv)))
+ double delta = fabs(result - expected);
+
+ if (delta > variance)
{
- return FAIL;
+ Fail("ceil(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, expected);
}
+}
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result = ceil(value);
- for (i=0; i<sizeof(testCases) / sizeof(testCase); i++)
+ if (!_isnan(result))
{
- ret = ceil(testCases[i].value);
-
- if (ret != testCases[i].ceilVal)
- {
- Fail("Expected ceil(%g) to return %g, got %g\n",
- testCases[i].value, testCases[i].ceilVal, ret);
- }
+ Fail("ceil(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_NAN);
}
-
- for (i=0; i<sizeof(extremeCases) / sizeof(extremeCase); i++)
- {
- value = INT64_TO_DOUBLE(extremeCases[i].value);
- ceilVal = INT64_TO_DOUBLE(extremeCases[i].ceilVal);
+}
- ret = ceil(value);
+/**
+ * main
+ *
+ * executable entry point
+ */
+int __cdecl main(int argc, char *argv[])
+{
+ struct test tests[] =
+ {
+ /* value expected variance */
+ { 0.31830988618379067, 1, PAL_EPSILON * 10 }, // value: 1 / pi
+ { 0.43429448190325183, 1, PAL_EPSILON * 10 }, // value: log10(e)
+ { 0.63661977236758134, 1, PAL_EPSILON * 10 }, // value: 2 / pi
+ { 0.69314718055994531, 1, PAL_EPSILON * 10 }, // value: ln(2)
+ { 0.70710678118654752, 1, PAL_EPSILON * 10 }, // value: 1 / sqrt(2)
+ { 0.78539816339744831, 1, PAL_EPSILON * 10 }, // value: pi / 4
+ { 1.1283791670955126, 2, PAL_EPSILON * 10 }, // value: 2 / sqrt(pi)
+ { 1.4142135623730950, 2, PAL_EPSILON * 10 }, // value: sqrt(2)
+ { 1.4426950408889634, 2, PAL_EPSILON * 10 }, // value: log2(e)
+ { 1.5707963267948966, 2, PAL_EPSILON * 10 }, // value: pi / 2
+ { 2.3025850929940457, 3, PAL_EPSILON * 10 }, // value: ln(10)
+ { 2.7182818284590452, 3, PAL_EPSILON * 10 }, // value: e
+ { 3.1415926535897932, 4, PAL_EPSILON * 10 }, // value: pi
+ { PAL_POSINF, PAL_POSINF, 0 }
+ };
- if (ret != ceilVal)
- {
- Fail("Expected ceil(%g) to return %g, got %I64X\n",
- value, ceilVal, ret);
- }
+ /* PAL initialization */
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
}
-
- /* Test how ceil handles NaN */
- if (!_isnan(ceil(INT64_TO_DOUBLE(NaN))))
+
+ validate( 0, 0, PAL_EPSILON);
+ validate(-0.0, 0, PAL_EPSILON);
+
+ validate( 1, 1, PAL_EPSILON * 10);
+ validate(-1.0, -1, PAL_EPSILON * 10);
+
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
{
- Fail("Passing NaN to ceil did not return NaN!\n");
+ validate( tests[i].value, tests[i].expected, tests[i].variance);
+ validate(-tests[i].value, 1 - tests[i].expected, tests[i].variance);
}
+
+ validate_isnan(PAL_NAN);
PAL_Terminate();
return PASS;
}
-
cmake_minimum_required(VERSION 2.8.12.2)
add_subdirectory(test1)
-
** PAL_Terminate
** Fail
** fabs
-**
-
**
**===========================================================================*/
#include <palsuite.h>
-#define DELTA 0.0000001 /* Error acceptance level to the 7th decimal */
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
/**
* Helper test structure
*/
struct test
{
- double value; /* value to test the function with */
- double result; /* expected result */
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
};
/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+ double result = cos(value);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("cos(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result = cos(value);
+
+ if (!_isnan(result))
+ {
+ Fail("cos(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_NAN);
+ }
+}
+
+/**
* main
*
* executable entry point
*/
-INT __cdecl main(INT argc, CHAR **argv)
+int __cdecl main(int argc, char **argv)
{
- double pi = 3.1415926535;
- int i;
-
struct test tests[] =
{
- /* Value test result */
- { 0, 1 },
- { pi/2.0, 0 },
- { pi, -1 },
- { (3.0*pi) / 2.0, 0 },
- { 2.0 * pi, 1 },
- { 5.0*pi/2.0, 0 },
- { 3.0*pi, -1 },
- { (7.0*pi) / 2.0, 0 },
- { 4.0 * pi, 1 },
- { 1.7e-12, 1 },
- { 1.7e+12, 0.1745850 }
+ /* value expected variance */
+ { 0, 1, PAL_EPSILON * 10 },
+ { 0.31830988618379067, 0.94976571538163866, PAL_EPSILON }, // value: 1 / pi
+ { 0.43429448190325183, 0.90716712923909839, PAL_EPSILON }, // value: log10(e)
+ { 0.63661977236758134, 0.80410982822879171, PAL_EPSILON }, // value: 2 / pi
+ { 0.69314718055994531, 0.76923890136397213, PAL_EPSILON }, // value: ln(2)
+ { 0.70710678118654752, 0.76024459707563015, PAL_EPSILON }, // value: 1 / sqrt(2)
+ { 0.78539816339744831, 0.70710678118654752, PAL_EPSILON }, // value: pi / 4, expected: 1 / sqrt(2)
+ { 1, 0.54030230586813972, PAL_EPSILON },
+ { 1.1283791670955126, 0.42812514788535792, PAL_EPSILON }, // value: 2 / sqrt(pi)
+ { 1.4142135623730950, 0.15594369476537447, PAL_EPSILON }, // value: sqrt(2)
+ { 1.4426950408889634, 0.12775121753523991, PAL_EPSILON }, // value: log2(e)
+ { 1.5707963267948966, 0, PAL_EPSILON }, // value: pi / 2
+ { 2.3025850929940457, -0.66820151019031295, PAL_EPSILON }, // value: ln(10)
+ { 2.7182818284590452, -0.91173391478696510, PAL_EPSILON }, // value: e
+ { 3.1415926535897932, -1, PAL_EPSILON * 10 }, // value: pi
};
-
/* PAL initialization */
- if( PAL_Initialize(argc, argv) != 0 )
+ if (PAL_Initialize(argc, argv) != 0)
{
- return (FAIL);
+ return FAIL;
}
- for( i = 0; i < sizeof(tests) / sizeof(struct test); i++)
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
{
- double result;
- double testDelta;
-
- result = cos( tests[i].value );
-
- /* The test is valid when the difference between the */
- /* result and the expectation is less than DELTA */
- testDelta = fabs( result - tests[i].result );
- if( testDelta >= DELTA )
- {
- Fail( "cos(%g) returned %20.10g"
- " when it should have returned %20.10g",
- tests[i].value,
- result,
- tests[i].result );
- }
+ validate( tests[i].value, tests[i].expected, tests[i].variance);
+ validate(-tests[i].value, tests[i].expected, tests[i].variance);
}
+
+ validate_isnan(PAL_NEGINF);
+ validate_isnan(PAL_NAN);
+ validate_isnan(PAL_POSINF);
PAL_Terminate();
return PASS;
}
-
-
Description
= Passes to cos() a series of angle value, checking that
= each one return the correct value.
-
-
-
cmake_minimum_required(VERSION 2.8.12.2)
add_subdirectory(test1)
-
**
** Dependencies: PAL_Initialize
** PAL_Terminate
-** Fail
+** Fail
** fabs
-**
-
**
**===========================================================================*/
#include <palsuite.h>
-#define DELTA 0.0000001 /* Error acceptance level to the 7th decimal */
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
/**
* Helper test structure
*/
struct test
{
- double value; /* value to test the function with */
- double result; /* expected result */
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
};
/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+ double result = cosh(value);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("cosh(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning PAL_NAN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result = cosh(value);
+
+ if (!_isnan(result))
+ {
+ Fail("cosh(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_NAN);
+ }
+}
+
+/**
* main
*
* executable entry point
*/
-INT __cdecl main(INT argc, CHAR **argv)
+int __cdecl main(int argc, char **argv)
{
- double pi = 3.1415926535;
- int i;
-
struct test tests[] =
{
- /* Value test result */
- { 0, 1 },
- { pi/2.0, 2.5091785 },
- { pi, 11.5919533 },
- { (3.0*pi) / 2.0, 55.6633809 },
- { 2.0 * pi, 267.7467614 },
- { 5.0*pi/2.0, 1287.9854421 },
- { 3.0*pi, 6195.8239426 },
- { (7.0*pi) / 2.0, 29804.8707455 },
- { 4.0 * pi, 143375.6565186 }
+ /* value expected variance */
+ { 0, 1, PAL_EPSILON * 10 },
+ { 0.31830988618379067, 1.0510897883672876, PAL_EPSILON * 10 }, // value: 1 / pi
+ { 0.43429448190325183, 1.0957974645564909, PAL_EPSILON * 10 }, // value: log10(e)
+ { 0.63661977236758134, 1.2095794864199787, PAL_EPSILON * 10 }, // value: 2 / pi
+ { 0.69314718055994531, 1.25, PAL_EPSILON * 10 }, // value: ln(2)
+ { 0.70710678118654752, 1.2605918365213561, PAL_EPSILON * 10 }, // value: 1 / sqrt(2)
+ { 0.78539816339744831, 1.3246090892520058, PAL_EPSILON * 10 }, // value: pi / 4
+ { 1, 1.5430806348152438, PAL_EPSILON * 10 },
+ { 1.1283791670955126, 1.7071001431069344, PAL_EPSILON * 10 }, // value: 2 / sqrt(pi)
+ { 1.4142135623730950, 2.1781835566085709, PAL_EPSILON * 10 }, // value: sqrt(2)
+ { 1.4426950408889634, 2.2341880974508023, PAL_EPSILON * 10 }, // value: log2(e)
+ { 1.5707963267948966, 2.5091784786580568, PAL_EPSILON * 10 }, // value: pi / 2
+ { 2.3025850929940457, 5.05, PAL_EPSILON * 10 }, // value: ln(10)
+ { 2.7182818284590452, 7.6101251386622884, PAL_EPSILON * 10 }, // value: e
+ { 3.1415926535897932, 11.591953275521521, PAL_EPSILON * 100 }, // value: pi
+ { PAL_POSINF, PAL_POSINF, 0 },
};
-
/* PAL initialization */
- if( PAL_Initialize(argc, argv) != 0 )
+ if (PAL_Initialize(argc, argv) != 0)
{
- return (FAIL);
+ return FAIL;
}
- for( i = 0; i < sizeof(tests) / sizeof(struct test); i++)
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
{
- double result;
- double testDelta;
-
-
- result = cosh( tests[i].value );
-
- /*
- * The test is valid when the difference between the
- * result and the expectation is less than DELTA
- */
- testDelta = fabs( result - tests[i].result );
- if( testDelta >= DELTA )
- {
- Fail( "cosh(%g) returned %g"
- " when it should have returned %g",
- tests[i].value,
- result,
- tests[i].result );
- }
+ validate( tests[i].value, tests[i].expected, tests[i].variance);
+ validate(-tests[i].value, tests[i].expected, tests[i].variance);
}
+
+ validate_isnan(PAL_NAN);
PAL_Terminate();
return PASS;
}
-
-
-
-
-
-
-
-
-
-
-
-
-
Description
= Passes to cosh() a series of angle value, checking that
= each one return to correct value.
-
-
-
cmake_minimum_required(VERSION 2.8.12.2)
add_subdirectory(test1)
-add_subdirectory(test2)
-add_subdirectory(test3)
-
**
** Purpose: Tests exp with a normal set of values.
**
-**
**===================================================================*/
#include <palsuite.h>
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
+
+/**
+ * Helper test structure
+ */
struct test
{
- double value;
- double result;
- double delta;
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
};
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+ double result = exp(value);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
-int __cdecl main(int argc, char **argv)
-{
- double value;
- double testDelta;
- int i;
+ if (delta > variance)
+ {
+ Fail("exp(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, expected);
+ }
+}
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result = exp(value);
+
+ if (!_isnan(result))
+ {
+ Fail("exp(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_NAN);
+ }
+}
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+int __cdecl main(int argc, char **argv)
+{
struct test tests[] =
{
- {0, 1, 1e-7},
- {0.5, 1.64872127, 1e-7},
- {-0.5, 0.60653066, 1e-7},
- {1, 2.71828183, 1e-7},
- {-1, 0.367879441, 1e-7},
- {10, 2.202646579481e+004, 1e-4},
- {-10, 4.53999298e-005, 1e-13},
-
- {600, 3.7730203009299397e+260, 1e+252},
- {-600, 2.6503965530043108e-261, 1e-269}
+ /* value expected variance */
+ { PAL_NEGINF, 0, PAL_EPSILON },
+ { -3.1415926535897932, 0.043213918263772250, PAL_EPSILON / 10 }, // value: -(pi)
+ { -2.7182818284590452, 0.065988035845312537, PAL_EPSILON / 10 }, // value: -(e)
+ { -2.3025850929940457, 0.1, PAL_EPSILON }, // value: -(ln(10))
+ { -1.5707963267948966, 0.20787957635076191, PAL_EPSILON }, // value: -(pi / 2)
+ { -1.4426950408889634, 0.23629008834452270, PAL_EPSILON }, // value: -(log2(e))
+ { -1.4142135623730950, 0.24311673443421421, PAL_EPSILON }, // value: -(sqrt(2))
+ { -1.1283791670955126, 0.32355726390307110, PAL_EPSILON }, // value: -(2 / sqrt(pi))
+ { -1, 0.36787944117144232, PAL_EPSILON }, // value: -(1)
+ { -0.78539816339744831, 0.45593812776599624, PAL_EPSILON }, // value: -(pi / 4)
+ { -0.70710678118654752, 0.49306869139523979, PAL_EPSILON }, // value: -(1 / sqrt(2))
+ { -0.69314718055994531, 0.5, PAL_EPSILON }, // value: -(ln(2))
+ { -0.63661977236758134, 0.52907780826773535, PAL_EPSILON }, // value: -(2 / pi)
+ { -0.43429448190325183, 0.64772148514180065, PAL_EPSILON }, // value: -(log10(e))
+ { -0.31830988618379067, 0.72737734929521647, PAL_EPSILON }, // value: -(1 / pi)
+ { 0, 1, PAL_EPSILON * 10 },
+ { 0.31830988618379067, 1.3748022274393586, PAL_EPSILON * 10 }, // value: 1 / pi
+ { 0.43429448190325183, 1.5438734439711811, PAL_EPSILON * 10 }, // value: log10(e)
+ { 0.63661977236758134, 1.8900811645722220, PAL_EPSILON * 10 }, // value: 2 / pi
+ { 0.69314718055994531, 2, PAL_EPSILON * 10 }, // value: ln(2)
+ { 0.70710678118654752, 2.0281149816474725, PAL_EPSILON * 10 }, // value: 1 / sqrt(2)
+ { 0.78539816339744831, 2.1932800507380155, PAL_EPSILON * 10 }, // value: pi / 4
+ { 1, 2.7182818284590452, PAL_EPSILON * 10 }, // expected: e
+ { 1.1283791670955126, 3.0906430223107976, PAL_EPSILON * 10 }, // value: 2 / sqrt(pi)
+ { 1.4142135623730950, 4.1132503787829275, PAL_EPSILON * 10 }, // value: sqrt(2)
+ { 1.4426950408889634, 4.2320861065570819, PAL_EPSILON * 10 }, // value: log2(e)
+ { 1.5707963267948966, 4.8104773809653517, PAL_EPSILON * 10 }, // value: pi / 2
+ { 2.3025850929940457, 10, PAL_EPSILON * 100 }, // value: ln(10)
+ { 2.7182818284590452, 15.154262241479264, PAL_EPSILON * 100 }, // value: e
+ { 3.1415926535897932, 23.140692632779269, PAL_EPSILON * 100 }, // value: pi
+ { PAL_POSINF, PAL_POSINF, 0 },
};
-
if (PAL_Initialize(argc, argv) != 0)
{
- return FAIL;
+ return FAIL;
}
- for( i = 0; i < sizeof(tests) / sizeof(struct test); i++)
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
{
- value = exp(tests[i].value);
-
- testDelta = fabs(value - tests[i].result);
- if( testDelta >= tests[i].delta )
- {
- Fail("exp(%g) returned %g when it should have returned %g\n",
- tests[i].value, value, tests[i].result);
- }
+ validate(tests[i].value, tests[i].expected, tests[i].variance);
}
+ validate_isnan(PAL_NAN);
+
PAL_Terminate();
return PASS;
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-/*=====================================================================
-**
-** Source: test1.c
-**
-** Purpose: Tests that exp handles underflows, overflows, and NaNs
-** corectly.
-**
-**
-**===================================================================*/
-
-#include <palsuite.h>
-
-int __cdecl main(int argc, char **argv)
-{
- double zero = 0.0;
- double PosInf = 1.0 / zero;
- double NaN = 0.0 / zero;
- // Force 'value' to be converted to a double to avoid
- // using the internal precision of the FPU for comparisons.
- volatile double value;
-
- if (PAL_Initialize(argc, argv) != 0)
- {
- return FAIL;
- }
-
- /* Test overflows give PosInf */
- value = exp(800.0);
- if (value != PosInf)
- {
- Fail( "exp(%g) returned %g when it should have returned %g\n",
- 800.0, value, PosInf);
- }
-
- value = exp(PosInf);
- if (value != PosInf)
- {
- Fail( "exp(%g) returned %g when it should have returned %g\n",
- PosInf, value, PosInf);
- }
-
- /* Test underflows give 0 */
- value = exp(-800);
- if (value != 0)
- {
- Fail( "exp(%g) returned %g when it should have returned %g\n",
- -800.0, value, 0.0);
- }
-
- /* Test that a NaN as input gives a NaN */
- value = exp(NaN);
- if (_isnan(value) == 0)
- {
- Fail( "exp( NaN ) returned %g when it should have returned NaN\n",
- value);
- }
-
- PAL_Terminate();
- return PASS;
-}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-/*=============================================================================
-**
-** Source: test3.c
-**
-** Purpose: Test to ensure that exp returns correct values.
-**
-** Dependencies: PAL_Initialize
-** PAL_Terminate
-** Fail
-** fabs
-** _finite
-** _isnan
-**
-
-**
-**===========================================================================*/
-
-#include <palsuite.h>
-
-#define DELTA 0.0000001 /* Error acceptance level to the 7th decimal */
-
-/**
- * Helper test structure
- */
-struct test
-{
- double value; /* value to test the function with */
- double result; /* expected result */
-};
-
-/**
- * main
- *
- * executable entry point
- */
-INT __cdecl main(INT argc, CHAR **argv)
-{
- int i;
- double result;
-
- struct test tests[] =
- {
- /* Value test result */
- { 0.100000000000, 1.105170918076 },
- { 1.000000000000, 2.718281828459 },
- { 2.400000000000, 11.023176380642 },
- { 3.750000000000, 42.521082000063 },
- { 7.630000000000, 2059.050019837344 },
- { 10.000000000000, 22026.465794806718 },
- { 13.260000000000, 573779.238840227250 },
- { 18.100000000000, 72565488.372322351000 },
- { 25.000000000000, 72004899337.385880000000 },
- { 29.310000000000, 5360079912775.353500000000 }
- };
-
- double infinite[] =
- {
- 2215.8, 20554.1
- };
-
-
- /* PAL initialization */
- if( PAL_Initialize(argc, argv) != 0 )
- {
- return (FAIL);
- }
-
- for( i = 0; i < sizeof(tests) / sizeof(struct test); i++)
- {
- double testDelta;
- double allowedDelta;
-
- result = exp( tests[i].value );
-
- /* The test is valid when the difference between the */
- /* result and the expectation is less than DELTA */
- allowedDelta = (tests[i].value > 1) ? 1 : DELTA;
- testDelta = fabs( result - tests[i].result );
- if( testDelta >= allowedDelta )
- {
- Fail( "exp(%g) returned %20.10g"
- " when it should have returned %20.10g\n",
- tests[i].value,
- result,
- tests[i].result );
- }
- }
-
- for( i = 0; i < sizeof(infinite) / sizeof(double); i++)
- {
- result = exp( infinite[i] );
-
- /* The test is valid when the function returns an infinite result */
- if( _finite( result ) )
- {
- Fail( "exp(%g) returned %20.10g"
- " when it should have returned 1.#INF00000000",
- infinite[i],
- result );
- }
- }
-
- PAL_Terminate();
- return PASS;
-}
cmake_minimum_required(VERSION 2.8.12.2)
add_subdirectory(test1)
-
**
** Dependencies: PAL_Initialize
** PAL_Terminate
-** Fail
-**
-
+** Fail
**
**===========================================================================*/
#include <palsuite.h>
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
+
/**
* Helper test structure
*/
struct test
{
- double value; // param 1
- double result; // expected result
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
};
/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+ double result = fabs(value);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("fabs(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result = fabs(value);
+
+ if (!_isnan(result))
+ {
+ Fail("fabs(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_NAN);
+ }
+}
+
+/**
* main
*
* executable entry point
*/
INT __cdecl main(INT argc, CHAR **argv)
{
- int i;
-
struct test tests[] =
{
- // param 1 result
- { 3, 3 },
- { -10, 10 },
- { 0, 0 },
- { 1.7e308, 1.7e308 },
- { -1.7e308, 1.7e308 },
- { 4.94e-324, 4.94e-324 },
- { -4.94e-324, 4.94e-324 }
+ /* value expected variance */
+ { PAL_NEGINF, PAL_POSINF, 0 },
+ { -3.1415926535897932, 3.1415926535897932, PAL_EPSILON * 10 }, // value: -(pi) expected: pi
+ { -2.7182818284590452, 2.7182818284590452, PAL_EPSILON * 10 }, // value: -(e) expected: e
+ { -2.3025850929940457, 2.3025850929940457, PAL_EPSILON * 10 }, // value: -(ln(10)) expected: ln(10)
+ { -1.5707963267948966, 1.5707963267948966, PAL_EPSILON * 10 }, // value: -(pi / 2) expected: pi / 2
+ { -1.4426950408889634, 1.4426950408889634, PAL_EPSILON * 10 }, // value: -(log2(e)) expected: log2(e)
+ { -1.4142135623730950, 1.4142135623730950, PAL_EPSILON * 10 }, // value: -(sqrt(2)) expected: sqrt(2)
+ { -1.1283791670955126, 1.1283791670955126, PAL_EPSILON * 10 }, // value: -(2 / sqrt(pi)) expected: 2 / sqrt(pi)
+ { -1, 1, PAL_EPSILON * 10 },
+ { -0.78539816339744831, 0.78539816339744831, PAL_EPSILON }, // value: -(pi / 4) expected: pi / 4
+ { -0.70710678118654752, 0.70710678118654752, PAL_EPSILON }, // value: -(1 / sqrt(2)) expected: 1 / sqrt(2)
+ { -0.69314718055994531, 0.69314718055994531, PAL_EPSILON }, // value: -(ln(2)) expected: ln(2)
+ { -0.63661977236758134, 0.63661977236758134, PAL_EPSILON }, // value: -(2 / pi) expected: 2 / pi
+ { -0.43429448190325183, 0.43429448190325183, PAL_EPSILON }, // value: -(log10(e)) expected: log10(e)
+ { -0.31830988618379067, 0.31830988618379067, PAL_EPSILON }, // value: -(1 / pi) expected: 1 / pi
+ { -0.0, 0, PAL_EPSILON },
};
// PAL initialization
- if( PAL_Initialize(argc, argv) != 0 )
+ if (PAL_Initialize(argc, argv) != 0)
{
- return FAIL;
+ return FAIL;
}
- for( i = 0; i < sizeof(tests) / sizeof(struct test); i++ )
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
{
- double result;
-
- result = fabs( tests[i].value );
-
- if( result != tests[i].result )
- {
- Fail( "fabs(%f) returned %f"
- " when it should have returned %f",
- tests[i].value,
- result,
- tests[i].result );
- }
+ validate( tests[i].value, tests[i].expected, tests[i].variance);
+ validate(-tests[i].value, tests[i].expected, tests[i].variance);
}
+
+ validate_isnan(PAL_NAN);
PAL_Terminate();
return PASS;
}
-
-
-
-
-
-
-
-
-
-
-
-
-
Description
= Passes to fabs() a series of values, checking that
= each one return to correct value.
-
-
-
--- /dev/null
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
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
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test to ensure that fabsf return the correct values
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** Fail
+**
+**===========================================================================*/
+
+#include <palsuite.h>
+
+// binary32 (float) has a machine epsilon of 2^-23 (approx. 1.19e-07). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-21 (approx. 4.76e-07) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (6-9 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxx will use PAL_EPSILON
+// for the variance, while an expected result in the format of 0.0xxxxxxxxx will use
+// PAL_EPSILON / 10 and and expected result in the format of x.xxxxxx will use PAL_EPSILON * 10.
+#define PAL_EPSILON 4.76837158e-07
+
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
+{
+ float value; /* value to test the function with */
+ float expected; /* expected result */
+ float variance; /* maximum delta between the expected and actual result */
+};
+
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(float value, float expected, float variance)
+{
+ float result = fabsf(value);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ float delta = fabsf(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("fabsf(%g) returned %10.9g when it should have returned %10.9g",
+ value, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(float value)
+{
+ float result = fabsf(value);
+
+ if (!_isnan(result))
+ {
+ Fail("fabsf(%g) returned %10.9g when it should have returned %10.9g",
+ value, result, PAL_NAN);
+ }
+}
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+INT __cdecl main(INT argc, CHAR **argv)
+{
+ struct test tests[] =
+ {
+ /* value expected variance */
+ { PAL_NEGINF, PAL_POSINF, 0 },
+ { -3.14159265f, 3.14159265f, PAL_EPSILON * 10 }, // value: -(pi) expected: pi
+ { -2.71828183f, 2.71828183f, PAL_EPSILON * 10 }, // value: -(e) expected: e
+ { -2.30258509f, 2.30258509f, PAL_EPSILON * 10 }, // value: -(ln(10)) expected: ln(10)
+ { -1.57079633f, 1.57079633f, PAL_EPSILON * 10 }, // value: -(pi / 2) expected: pi / 2
+ { -1.44269504f, 1.44269504f, PAL_EPSILON * 10 }, // value: -(log2(e)) expected: log2(e)
+ { -1.41421356f, 1.41421356f, PAL_EPSILON * 10 }, // value: -(sqrt(2)) expected: sqrt(2)
+ { -1.12837917f, 1.12837917f, PAL_EPSILON * 10 }, // value: -(2 / sqrt(pi)) expected: 2 / sqrt(pi)
+ { -1, 1, PAL_EPSILON * 10 },
+ { -0.785398163f, 0.785398163f, PAL_EPSILON }, // value: -(pi / 4) expected: pi / 4
+ { -0.707106781f, 0.707106781f, PAL_EPSILON }, // value: -(1 / sqrt(2)) expected: 1 / sqrt(2)
+ { -0.693147181f, 0.693147181f, PAL_EPSILON }, // value: -(ln(2)) expected: ln(2)
+ { -0.636619772f, 0.636619772f, PAL_EPSILON }, // value: -(2 / pi) expected: 2 / pi
+ { -0.434294482f, 0.434294482f, PAL_EPSILON }, // value: -(log10(e)) expected: log10(e)
+ { -0.318309886f, 0.318309886f, PAL_EPSILON }, // value: -(1 / pi) expected: 1 / pi
+ { -0.0f, 0, PAL_EPSILON },
+ };
+
+
+ // PAL initialization
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
+ {
+ validate( tests[i].value, tests[i].expected, tests[i].variance);
+ validate(-tests[i].value, tests[i].expected, tests[i].variance);
+ }
+
+ validate_isnan(PAL_NAN);
+
+ PAL_Terminate();
+ return PASS;
+}
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.
cmake_minimum_required(VERSION 2.8.12.2)
add_subdirectory(test1)
-
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-/*=============================================================================
+/*============================================================================
**
-** Source: test1.c
+** Source: test1.c
**
-** Purpose: Test to ensure that floor return the correct values
-**
-** Dependencies: PAL_Initialize
-** PAL_Terminate
-** Fail
-**
-
+** Purpose: Tests floor with simple positive and negative values. Also tests
+** extreme cases like extremely small values and positive and
+** negative infinity. Makes sure that calling floor on NaN returns
+** NaN
**
-**===========================================================================*/
+**==========================================================================*/
#include <palsuite.h>
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
+
/**
* Helper test structure
*/
struct test
{
- double value; // floor param 1
- double result; // expected result
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
};
/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+ double result = floor(value);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("floor(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result = floor(value);
+
+ if (!_isnan(result))
+ {
+ Fail("floor(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_NAN);
+ }
+}
+
+/**
* main
*
* executable entry point
*/
-INT __cdecl main(INT argc, CHAR **argv)
+int __cdecl main(int argc, char *argv[])
{
- int i;
-
struct test tests[] =
{
- // param 1 result
- { 3, 3 },
- { -10, -10 },
- { 0, 0 },
- { 1.7e308, 1.7e308 },
- { -1.7e308, -1.7e308 },
- { 4.94e-324, 0 },
- { -4.94e-324, -1 },
- { 1234.1234, 1234 },
- { -1234.1234, -1235 },
- {-0, 0 }
+ /* value expected variance */
+ { 0.31830988618379067, 0, PAL_EPSILON }, // value: 1 / pi
+ { 0.43429448190325183, 0, PAL_EPSILON }, // value: log10(e)
+ { 0.63661977236758134, 0, PAL_EPSILON }, // value: 2 / pi
+ { 0.69314718055994531, 0, PAL_EPSILON }, // value: ln(2)
+ { 0.70710678118654752, 0, PAL_EPSILON }, // value: 1 / sqrt(2)
+ { 0.78539816339744831, 0, PAL_EPSILON }, // value: pi / 4
+ { 1.1283791670955126, 1, PAL_EPSILON * 10 }, // value: 2 / sqrt(pi)
+ { 1.4142135623730950, 1, PAL_EPSILON * 10 }, // value: sqrt(2)
+ { 1.4426950408889634, 1, PAL_EPSILON * 10 }, // value: log2(e)
+ { 1.5707963267948966, 1, PAL_EPSILON * 10 }, // value: pi / 2
+ { 2.3025850929940457, 2, PAL_EPSILON * 10 }, // value: ln(10)
+ { 2.7182818284590452, 2, PAL_EPSILON * 10 }, // value: e
+ { 3.1415926535897932, 3, PAL_EPSILON * 10 }, // value: pi
+ { PAL_POSINF, PAL_POSINF, 0 }
};
-
- // PAL initialization
- if( PAL_Initialize(argc, argv) != 0 )
+ /* PAL initialization */
+ if (PAL_Initialize(argc, argv) != 0)
{
- return FAIL;
+ return FAIL;
}
-
- for( i = 0; i < sizeof(tests) / sizeof(struct test); i++)
+
+ validate( 0, 0, PAL_EPSILON);
+ validate(-0.0, 0, PAL_EPSILON);
+
+ validate( 1, 1, PAL_EPSILON * 10);
+ validate(-1.0, -1, PAL_EPSILON * 10);
+
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
{
- double result;
-
- result = floor( tests[i].value );
-
- if( result != tests[i].result )
- {
- Fail( "floor(%f) returned %f"
- " when it should have returned %f",
- tests[i].value,
- result,
- tests[i].result );
- }
+ validate( tests[i].value, tests[i].expected, tests[i].variance);
+ validate(-tests[i].value, -(tests[i].expected + 1), tests[i].variance);
}
+
+ validate_isnan(PAL_NAN);
PAL_Terminate();
return PASS;
}
-
-
-
-
-
-
-
-
-
-
-
-
-
Description
= Passes to floor() a series of value, checking that
= each one return to correct value.
-
-
-
cmake_minimum_required(VERSION 2.8.12.2)
add_subdirectory(test1)
-
**
** Dependencies: PAL_Initialize
** PAL_Terminate
-** Fail
+** Fail
** fabs
-**
-
**
**===========================================================================*/
#include <palsuite.h>
-#define DELTA 0.0000001 //Error acceptance level to the 7th decimal
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
/**
* Helper test structure
*/
struct test
{
- double valueX; // fmod param 1
- double valueY; // fmod param 2
- double result; // expected result
+ double numerator; /* second component of the value to test the function with */
+ double denominator; /* first component of the value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
};
/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double numerator, double denominator, double expected, double variance)
+{
+ double result = fmod(numerator, denominator);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("fmod(%g, %g) returned %20.17g when it should have returned %20.17g",
+ numerator, denominator, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double numerator, double denominator)
+{
+ double result = fmod(numerator, denominator);
+
+ if (!_isnan(result))
+ {
+ Fail("fmod(%g, %g) returned %20.17g when it should have returned %20.17g",
+ numerator, denominator, result, PAL_NAN);
+ }
+}
+
+/**
* main
*
* executable entry point
*/
INT __cdecl main(INT argc, CHAR **argv)
{
- int i;
-
struct test tests[] =
{
- // param 1 param 2 result
- { 3, 2, 1 },
- { -10, 3, -1 },
- { 1, 0.0, 0 },
- { 1.7e308, -1.7e308, 0 },
- { 100, -1.1234, 0.017400 },
- { -100, -1.1234, -0.017400},
- { 0, 0, 0 },
- {-0, 1, 0 },
- {-0, -0, 0 }
+ /* numerator denominator expected variance */
+ { 0, PAL_POSINF, 0, PAL_EPSILON },
+ { 0.31296179620778659, 0.94976571538163866, 0.31296179620778658, PAL_EPSILON },
+ { 0.42077048331375735, 0.90716712923909839, 0.42077048331375733, PAL_EPSILON },
+ { 0.59448076852482208, 0.80410982822879171, 0.59448076852482212, PAL_EPSILON },
+ { 0.63896127631363480, 0.76923890136397213, 0.63896127631363475, PAL_EPSILON },
+ { 0.64963693908006244, 0.76024459707563015, 0.64963693908006248, PAL_EPSILON },
+ { 0.70710678118654752, 0.70710678118654752, 0, PAL_EPSILON },
+ { 1, 1, 0, PAL_EPSILON },
+ { 0.84147098480789651, 0.54030230586813972, 0.30116867893975674, PAL_EPSILON },
+ { 0.90371945743584630, 0.42812514788535792, 0.047469161665130377, PAL_EPSILON / 10 },
+ { 0.98776594599273553, 0.15594369476537447, 0.052103777400488605, PAL_EPSILON / 10 },
+ { 0.99180624439366372, 0.12775121753523991, 0.097547721646984359, PAL_EPSILON / 10 },
+ { 0.74398033695749319, -0.66820151019031295, 0.075778826767180285, PAL_EPSILON / 10 },
+ { 0.41078129050290870, -0.91173391478696510, 0.41078129050290868, PAL_EPSILON },
+ { 0, -1, 0, PAL_EPSILON },
+ { 1, PAL_POSINF, 1, PAL_EPSILON * 10 },
};
// PAL initialization
- if( PAL_Initialize(argc, argv) != 0 )
+ if (PAL_Initialize(argc, argv) != 0)
{
- return FAIL;
+ return FAIL;
}
- for( i = 0; i < sizeof(tests) / sizeof(struct test); i++ )
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
{
- double result;
- double testDelta;
-
- result = fmod( tests[i].valueX, tests[i].valueY );
-
- // The test is valid when the difference between the
- // result and the expectation is less than DELTA
- testDelta = fabs( result - tests[i].result );
- if( testDelta >= DELTA )
- {
- Fail( "fmod(%f, %f) returned %f"
- " when it should have returned %f",
- tests[i].valueX,
- tests[i].valueY,
- result,
- tests[i].result );
- }
+ validate( tests[i].numerator, tests[i].denominator, tests[i].expected, tests[i].variance);
+ validate(-tests[i].numerator, tests[i].denominator, -tests[i].expected, tests[i].variance);
+ validate( tests[i].numerator, -tests[i].denominator, tests[i].expected, tests[i].variance);
+ validate(-tests[i].numerator, -tests[i].denominator, -tests[i].expected, tests[i].variance);
}
+ validate_isnan( 0, 0);
+ validate_isnan(-0.0, 0);
+ validate_isnan( 0, -0.0);
+ validate_isnan(-0.0, -0.0);
+
+ validate_isnan( 1, 0);
+ validate_isnan(-1.0, 0);
+ validate_isnan( 1, -0.0);
+ validate_isnan(-1.0, -0.0);
+
+ validate_isnan(PAL_POSINF, PAL_POSINF);
+ validate_isnan(PAL_NEGINF, PAL_POSINF);
+ validate_isnan(PAL_POSINF, PAL_NEGINF);
+ validate_isnan(PAL_NEGINF, PAL_NEGINF);
+
+ validate_isnan(PAL_POSINF, 0);
+ validate_isnan(PAL_NEGINF, 0);
+ validate_isnan(PAL_POSINF, -0.0);
+ validate_isnan(PAL_NEGINF, -0.0);
+
+ validate_isnan(PAL_POSINF, 1);
+ validate_isnan(PAL_NEGINF, 1);
+ validate_isnan(PAL_POSINF, -1.0);
+ validate_isnan(PAL_NEGINF, -1.0);
+
PAL_Terminate();
return PASS;
}
-
-
-
-
-
-
-
-
-
-
-
-
-
Description
= Passes to fmod() a series of values, checking that
= each one return to correct value.
-
-
-
--- /dev/null
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
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
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test to ensure that fmodf return the correct values
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** Fail
+** fabsf
+**
+**===========================================================================*/
+
+#include <palsuite.h>
+
+// binary32 (float) has a machine epsilon of 2^-23 (approx. 1.19e-07). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-21 (approx. 4.76e-07) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (6-9 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxx will use PAL_EPSILON
+// for the variance, while an expected result in the format of 0.0xxxxxxxxx will use
+// PAL_EPSILON / 10 and and expected result in the format of x.xxxxxx will use PAL_EPSILON * 10.
+#define PAL_EPSILON 4.76837158e-07
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
+{
+ float numerator; /* second component of the value to test the function with */
+ float denominator; /* first component of the value to test the function with */
+ float expected; /* expected result */
+ float variance; /* maximum delta between the expected and actual result */
+};
+
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(float numerator, float denominator, float expected, float variance)
+{
+ float result = fmodf(numerator, denominator);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ float delta = fabsf(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("fmodf(%g, %g) returned %10.9g when it should have returned %10.9g",
+ numerator, denominator, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(float numerator, float denominator)
+{
+ float result = fmodf(numerator, denominator);
+
+ if (!_isnan(result))
+ {
+ Fail("fmodf(%g, %g) returned %10.9g when it should have returned %10.9g",
+ numerator, denominator, result, PAL_NAN);
+ }
+}
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+INT __cdecl main(INT argc, CHAR **argv)
+{
+ struct test tests[] =
+ {
+ /* numerator denominator expected variance */
+ { 0, PAL_POSINF, 0, PAL_EPSILON },
+ { 0.312961796f, 0.949765715f, 0.312961796f, PAL_EPSILON },
+ { 0.420770483f, 0.907167129f, 0.420770483f, PAL_EPSILON },
+ { 0.594480769f, 0.804109828f, 0.594480769f, PAL_EPSILON },
+ { 0.638961276f, 0.769238901f, 0.638961276f, PAL_EPSILON },
+ { 0.649636939f, 0.760244597f, 0.649636939f, PAL_EPSILON },
+ { 0.707106781f, 0.707106781f, 0, PAL_EPSILON },
+ { 1, 1, 0, PAL_EPSILON },
+ { 0.841470985f, 0.540302306f, 0.301168679f, PAL_EPSILON },
+ { 0.903719457f, 0.428125148f, 0.0474691617f, PAL_EPSILON / 10 },
+ { 0.987765946f, 0.155943695f, 0.0521037774f, PAL_EPSILON / 10 },
+ { 0.991806244f, 0.127751218f, 0.0975477216f, PAL_EPSILON / 10 },
+ { 0.743980337f, -0.668201510f, 0.0757788268f, PAL_EPSILON / 10 },
+ { 0.410781291f, -0.911733915f, 0.410781291f, PAL_EPSILON },
+ { 0, -1, 0, PAL_EPSILON },
+ { 1, PAL_POSINF, 1, PAL_EPSILON * 10 },
+ };
+
+
+ // PAL initialization
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
+ {
+ validate( tests[i].numerator, tests[i].denominator, tests[i].expected, tests[i].variance);
+ validate(-tests[i].numerator, tests[i].denominator, -tests[i].expected, tests[i].variance);
+ validate( tests[i].numerator, -tests[i].denominator, tests[i].expected, tests[i].variance);
+ validate(-tests[i].numerator, -tests[i].denominator, -tests[i].expected, tests[i].variance);
+ }
+
+ validate_isnan( 0, 0);
+ validate_isnan(-0.0f, 0);
+ validate_isnan( 0, -0.0f);
+ validate_isnan(-0.0f, -0.0f);
+
+ validate_isnan( 1, 0);
+ validate_isnan(-1, 0);
+ validate_isnan( 1, -0.0f);
+ validate_isnan(-1, -0.0f);
+
+ validate_isnan(PAL_POSINF, PAL_POSINF);
+ validate_isnan(PAL_NEGINF, PAL_POSINF);
+ validate_isnan(PAL_POSINF, PAL_NEGINF);
+ validate_isnan(PAL_NEGINF, PAL_NEGINF);
+
+ validate_isnan(PAL_POSINF, 0);
+ validate_isnan(PAL_NEGINF, 0);
+ validate_isnan(PAL_POSINF, -0.0f);
+ validate_isnan(PAL_NEGINF, -0.0f);
+
+ validate_isnan(PAL_POSINF, 1);
+ validate_isnan(PAL_NEGINF, 1);
+ validate_isnan(PAL_POSINF, -1);
+ validate_isnan(PAL_NEGINF, -1);
+
+ PAL_Terminate();
+ return PASS;
+}
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.
cmake_minimum_required(VERSION 2.8.12.2)
add_subdirectory(test1)
-
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-/*=============================================================================
+/*=====================================================================
**
-** Source: test1.c
+** Source: test1.c
**
-** Purpose: Test to ensure that log returns correct values.
-**
-** Dependencies: PAL_Initialize
-** PAL_Terminate
-** Fail
-** fabs
-** _finite
-** _isnan
-**
-
+** Purpose: Tests log with a normal set of values.
**
-**===========================================================================*/
+**===================================================================*/
#include <palsuite.h>
-#define DELTA 0.0000001 /* Error acceptance level to the 7th decimal */
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
/**
* Helper test structure
*/
struct test
{
- double value; /* value to test the function with */
- double result; /* expected result */
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
};
/**
- * main
- *
- * executable entry point
+ * validate
+ *
+ * test validation function
*/
-INT __cdecl main(INT argc, CHAR **argv)
+void __cdecl validate(double value, double expected, double variance)
{
- int i;
- double result;
+ double result = log(value);
- struct test tests[] =
- {
- /* Value test result */
- { 4.812768944365, 1.571272582596 },
- { 25.873592333750, 3.253222847545 },
- { 30.301828058718, 3.411208042666 },
- { 53.752250740074, 3.984385540365 },
- { 65.282143620106, 4.178718547435 },
- { 74.843592638936, 4.315400504515 },
- { 92.446668904691, 4.526631925866 },
- { 99.832148197882, 4.603490257677 },
- { 1830.360576189459, 7.512268262595 },
- { 6524.430494094669, 8.783308947783 },
- { 12456.186254463331, 9.429972666394 },
- { 14183.841639454329, 9.559858682961 },
- { 18221.999603259377, 9.810384912501 },
- { 20792.917264320811, 9.942367691562 },
- { 26488.001312295906, 10.184447128770 },
- { 29724.154423657950, 10.299715274515 },
- { 27899211.434430983, 17.144108982393 },
- { 55048606.214117862, 17.823727102268 },
- { 66659312.564470351, 18.015105318226 },
- { 113314373.84325695, 18.545676583294 },
- { 201366015.49641407, 19.120634782682 },
- { 311568417.23368025, 19.557129510064 },
- { 486835298.54176462, 20.003436427833 },
- };
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
- double indefinite[] =
+ if (delta > variance)
{
- -864278.51, -1000.2, -2
- };
+ Fail("log(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, expected);
+ }
+}
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result = log(value);
- /* PAL initialization */
- if( PAL_Initialize(argc, argv) != 0 )
+ if (!_isnan(result))
{
- return (FAIL);
+ Fail("log(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_NAN);
}
+}
- for( i = 0; i < sizeof(tests) / sizeof(struct test); i++)
+/**
+ * main
+ *
+ * executable entry point
+ */
+int __cdecl main(int argc, char **argv)
+{
+ struct test tests[] =
{
- double testDelta;
-
- result = log( tests[i].value );
-
- /*
- * The test is valid when the difference between the
- * result and the expectation is less than DELTA
- */
- testDelta = fabs( result - tests[i].result );
- if( testDelta >= DELTA )
- {
- Fail( "log(%g) returned %20.10f"
- " when it should have returned %20.10f",
- tests[i].value,
- result,
- tests[i].result );
- }
- }
+ /* value expected variance */
+ { 0, PAL_NEGINF, 0 },
+ { 0.043213918263772250, -3.1415926535897932, PAL_EPSILON * 10 }, // expected: -(pi)
+ { 0.065988035845312537, -2.7182818284590452, PAL_EPSILON * 10 }, // expected: -(e)
+ { 0.1, -2.3025850929940457, PAL_EPSILON * 10 }, // expected: -(ln(10))
+ { 0.20787957635076191, -1.5707963267948966, PAL_EPSILON * 10 }, // expected: -(pi / 2)
+ { 0.23629008834452270, -1.4426950408889634, PAL_EPSILON * 10 }, // expected: -(log2(e))
+ { 0.24311673443421421, -1.4142135623730950, PAL_EPSILON * 10 }, // expected: -(sqrt(2))
+ { 0.32355726390307110, -1.1283791670955126, PAL_EPSILON * 10 }, // expected: -(2 / sqrt(pi))
+ { 0.36787944117144232, -1, PAL_EPSILON * 10 }, // expected: -(1)
+ { 0.45593812776599624, -0.78539816339744831, PAL_EPSILON }, // expected: -(pi / 4)
+ { 0.49306869139523979, -0.70710678118654752, PAL_EPSILON }, // expected: -(1 / sqrt(2))
+ { 0.5, -0.69314718055994531, PAL_EPSILON }, // expected: -(ln(2))
+ { 0.52907780826773535, -0.63661977236758134, PAL_EPSILON }, // expected: -(2 / pi)
+ { 0.64772148514180065, -0.43429448190325183, PAL_EPSILON }, // expected: -(log10(e))
+ { 0.72737734929521647, -0.31830988618379067, PAL_EPSILON }, // expected: -(1 / pi)
+ { 1, 0, PAL_EPSILON },
+ { 1.3748022274393586, 0.31830988618379067, PAL_EPSILON }, // expected: 1 / pi
+ { 1.5438734439711811, 0.43429448190325183, PAL_EPSILON }, // expected: log10(e)
+ { 1.8900811645722220, 0.63661977236758134, PAL_EPSILON }, // expected: 2 / pi
+ { 2, 0.69314718055994531, PAL_EPSILON }, // expected: ln(2)
+ { 2.0281149816474725, 0.70710678118654752, PAL_EPSILON }, // expected: 1 / sqrt(2)
+ { 2.1932800507380155, 0.78539816339744831, PAL_EPSILON }, // expected: pi / 4
+ { 2.7182818284590452, 1, PAL_EPSILON * 10 }, // value: e
+ { 3.0906430223107976, 1.1283791670955126, PAL_EPSILON * 10 }, // expected: 2 / sqrt(pi)
+ { 4.1132503787829275, 1.4142135623730950, PAL_EPSILON * 10 }, // expected: sqrt(2)
+ { 4.2320861065570819, 1.4426950408889634, PAL_EPSILON * 10 }, // expected: log2(e)
+ { 4.8104773809653517, 1.5707963267948966, PAL_EPSILON * 10 }, // expected: pi / 2
+ { 10, 2.3025850929940457, PAL_EPSILON * 10 }, // expected: ln(10)
+ { 15.154262241479264, 2.7182818284590452, PAL_EPSILON * 10 }, // expected: e
+ { 23.140692632779269, 3.1415926535897932, PAL_EPSILON * 10 }, // expected: pi
+ { PAL_POSINF, PAL_POSINF, 0 },
+ };
+
- for( i = 0; i < sizeof(indefinite) / sizeof(double); i++)
+ if (PAL_Initialize(argc, argv) != 0)
{
- result = log( indefinite[i] );
-
- /* The test is valid when the function returns a defined result */
- if( ! _isnan( result ) )
- {
- Fail( "log(%g) returned %20.10f"
- " when it should have returned -1.#IND00000000",
- indefinite[i],
- result );
- }
+ return FAIL;
}
- /* log(0) is a special case */
- result = log( 0.0 );
- if( _finite( result ) )
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
{
- Fail( "log(%g) returned %20.10f"
- " when it should have returned -1.#INF00000000",
- 0.0,
- result );
+ validate(tests[i].value, tests[i].expected, tests[i].variance);
}
+
+ validate_isnan(PAL_NEGINF);
+ validate_isnan(PAL_NAN);
PAL_Terminate();
return PASS;
= 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.
-
-
-
cmake_minimum_required(VERSION 2.8.12.2)
add_subdirectory(test1)
-
**
** Source: test1.c
**
-** Purpose: Test to ensure that log returns correct values.
+** Purpose: Test to ensure that log10 returns correct values.
**
** Dependencies: PAL_Initialize
** PAL_Terminate
-** Fail
+** Fail
** fabs
-** _finite
** _isnan
**
-
-**
**===========================================================================*/
#include <palsuite.h>
-#define DELTA 0.0000001 /*Error acceptance level to the 7th decimal */
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
/**
* Helper test structure
*/
struct test
{
- double value; /* value to test the function with */
- double result; /* expected result */
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
};
/**
- * main
- *
- * executable entry point
+ * validate
+ *
+ * test validation function
*/
-INT __cdecl main(INT argc, CHAR **argv)
+void __cdecl validate(double value, double expected, double variance)
{
- int i;
- double result;
+ double result = log10(value);
- struct test tests[] =
- {
- /* Value test result */
- { 6.704916531877, 0.826393375779 },
- { 15.823847163305, 1.199312079583 },
- { 21.658986175115, 1.335638124087 },
- { 34.134952848903, 1.533199307291 },
- { 42.857142857143, 1.632023214705 },
- { 57.573168126469, 1.760220128395 },
- { 67.363505966369, 1.828424682147 },
- { 75.649281289102, 1.878804806336 },
- { 99.877925962096, 1.999469515332 },
- { 1706.203161717582, 3.232030742400 },
- { 3016.598101748711, 3.479517453423 },
- { 4017.596636860256, 3.603966331820 },
- { 5462.646626178777, 3.737403107294 },
- { 7199.790368358409, 3.857319851544 },
- { 13577.991882076480, 4.132835544685 },
- { 19235.535721915341, 4.284104286189 },
- { 24904.989593188267, 4.396286364594 },
- { 10690368.906277657000, 7.028992692224 },
- { 40653667.728385270000, 7.609099733260 },
- { 71100035.987914667000, 7.851869820552 },
- { 111208971.628284560000, 8.046139824759 },
- { 172499991.153172400000, 8.236789077136 },
- { 244361677.392925830000, 8.388033097635 },
- { 292552744.803003010000, 8.466204177125 },
- { 317831243.774193530000, 8.502196587433 },
- { 501815331.063020770000, 8.700543925401 },
- };
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
- double indefinite[] =
+ if (delta > variance)
{
- -864278.51, -1000.2, -2
- };
+ Fail("log10(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, expected);
+ }
+}
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result = log10(value);
- /* PAL initialization */
- if( PAL_Initialize(argc, argv) != 0 )
+ if (!_isnan(result))
{
- return (FAIL);
+ Fail("log10(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_NAN);
}
+}
- for( i = 0; i < sizeof(tests) / sizeof(struct test); i++)
+/**
+ * main
+ *
+ * executable entry point
+ */
+int __cdecl main(int argc, char **argv)
+{
+ struct test tests[] =
{
- double testDelta;
-
- result = log10( tests[i].value );
-
- /*
- * The test is valid when the difference between the
- * result and the expectation is less than DELTA
- */
- testDelta = fabs( result - tests[i].result );
- if( testDelta >= DELTA )
- {
- Fail( "log10(%g) returned %20.10f"
- " when it should have returned %20.10f",
- tests[i].value,
- result,
- tests[i].result );
- }
- }
+ /* value expected variance */
+ { 0, PAL_NEGINF, 0 },
+ { 0.00072178415907472774, -3.1415926535897932, PAL_EPSILON * 10 }, // expected: -(pi)
+ { 0.0019130141022243176, -2.7182818284590452, PAL_EPSILON * 10 }, // expected: -(e)
+ { 0.0049821282964407206, -2.3025850929940457, PAL_EPSILON * 10 }, // expected: -(ln(10))
+ { 0.026866041001136132, -1.5707963267948966, PAL_EPSILON * 10 }, // expected: -(pi / 2)
+ { 0.036083192820787210, -1.4426950408889634, PAL_EPSILON * 10 }, // expected: -(log2(e))
+ { 0.038528884700322026, -1.4142135623730950, PAL_EPSILON * 10 }, // expected: -(sqrt(2))
+ { 0.074408205860642723, -1.1283791670955126, PAL_EPSILON * 10 }, // expected: -(2 / sqrt(pi))
+ { 0.1, -1, PAL_EPSILON * 10 }, // expected: -(1)
+ { 0.16390863613957665, -0.78539816339744831, PAL_EPSILON }, // expected: -(pi / 4)
+ { 0.19628775993505562, -0.70710678118654752, PAL_EPSILON }, // expected: -(1 / sqrt(2))
+ { 0.20269956628651730, -0.69314718055994531, PAL_EPSILON }, // expected: -(ln(2))
+ { 0.23087676451600055, -0.63661977236758134, PAL_EPSILON }, // expected: -(2 / pi)
+ { 0.36787944117144232, -0.43429448190325183, PAL_EPSILON }, // expected: -(log10(e))
+ { 0.48049637305186868, -0.31830988618379067, PAL_EPSILON }, // expected: -(1 / pi)
+ { 1, 0, PAL_EPSILON },
+ { 2.0811811619898573, 0.31830988618379067, PAL_EPSILON }, // expected: 1 / pi
+ { 2.7182818284590452, 0.43429448190325183, PAL_EPSILON }, // expected: log10(e) value: e
+ { 4.3313150290214525, 0.63661977236758134, PAL_EPSILON }, // expected: 2 / pi
+ { 4.9334096679145963, 0.69314718055994531, PAL_EPSILON }, // expected: ln(2)
+ { 5.0945611704512962, 0.70710678118654752, PAL_EPSILON }, // expected: 1 / sqrt(2)
+ { 6.1009598002416937, 0.78539816339744831, PAL_EPSILON }, // expected: pi / 4
+ { 10, 1, PAL_EPSILON * 10 },
+ { 13.439377934644400, 1.1283791670955126, PAL_EPSILON * 10 }, // expected: 2 / sqrt(pi)
+ { 25.954553519470081, 1.4142135623730950, PAL_EPSILON * 10 }, // expected: sqrt(2)
+ { 27.713733786437790, 1.4426950408889634, PAL_EPSILON * 10 }, // expected: log2(e)
+ { 37.221710484165167, 1.5707963267948966, PAL_EPSILON * 10 }, // expected: pi / 2
+ { 200.71743249053009, 2.3025850929940457, PAL_EPSILON * 10 }, // expected: ln(10)
+ { 522.73529967043665, 2.7182818284590452, PAL_EPSILON * 10 }, // expected: e
+ { 1385.4557313670111, 3.1415926535897932, PAL_EPSILON * 10 }, // expected: pi
+ { PAL_POSINF, PAL_POSINF, 0 },
+ };
+
- for( i = 0; i < sizeof(indefinite) / sizeof(double); i++)
+ if (PAL_Initialize(argc, argv) != 0)
{
- result = log10( indefinite[i] );
-
- /* The test is valid when the function returns a defined result */
- if( ! _isnan( result ) )
- {
- Fail( "log10(%g) returned %20.10f"
- " when it should have returned -1.#IND00000000",
- indefinite[i],
- result );
- }
+ return FAIL;
}
- /* log(0) is a special case */
- result = log10( 0.0 );
- if( _finite( result ) )
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
{
- Fail( "log10(%g) returned %20.10f"
- " when it should have returned -1.#INF00000000",
- 0.0,
- result );
+ validate(tests[i].value, tests[i].expected, tests[i].variance);
}
+
+ validate_isnan(PAL_NEGINF);
+ validate_isnan(PAL_NAN);
PAL_Terminate();
return PASS;
**
** Dependencies: PAL_Initialize
** PAL_Terminate
-** Fail
+** Fail
** fabs
-**
-
**
**===========================================================================*/
#include <palsuite.h>
-#define DELTA 0.0000001 //Error acceptance level to the 7th decimal
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
/**
* Helper test structure
*/
struct test
{
- double value; // fmodf param 1
- double result1; // expected result (fractional portion)
- double result2; // expected result (integer portion)
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
+ double expected_intpart; /* expected result */
+ double variance_intpart; /* maximum delta between the expected and actual result */
};
/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance, double expected_intpart, double variance_intpart)
+{
+ double result_intpart;
+ double result = modf(value, &result_intpart);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
+ double delta_intpart = fabs(result_intpart - expected_intpart);
+
+ if ((delta > variance) || (delta_intpart > variance_intpart))
+ {
+ Fail("modf(%g) returned %20.17g with an intpart of %20.17g when it should have returned %20.17g with an intpart of %20.17g",
+ value, result, result_intpart, expected, expected_intpart);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result_intpart;
+ double result = modf(value, &result_intpart);
+
+ if (!_isnan(result) || !_isnan(result_intpart))
+ {
+ Fail("modf(%g) returned %20.17g with an intpart of %20.17g when it should have returned %20.17g with an intpart of %20.17g",
+ value, result, result_intpart, PAL_NAN, PAL_NAN);
+ }
+}
+
+/**
* main
*
* executable entry point
*/
-INT __cdecl main(INT argc, CHAR **argv)
+int __cdecl main(int argc, char **argv)
{
- INT i;
-
struct test tests[] =
{
- // param 1 fractional integer
- { 3, 0, 3 },
- { -10, 0, -10 },
- { 1.1234, 0.1234, 1 },
- { -1.1234, -0.1234, -1 },
- { 1.7e308, 0, 1.7e308 },
- { -1.7e308, 0, -1.7e308 },
- { 1.7e-30, 1.7e-30, 0 },
- { 0, 0, 0 }
+ /* value expected variance expected_intpart variance_intpart */
+ { 0, 0, PAL_EPSILON, 0, PAL_EPSILON },
+ { 0.31830988618379067, 0.31830988618379067, PAL_EPSILON, 0, PAL_EPSILON }, // value: 1 / pi
+ { 0.43429448190325183, 0.43429448190325183, PAL_EPSILON, 0, PAL_EPSILON }, // value: log10(e)
+ { 0.63661977236758134, 0.63661977236758134, PAL_EPSILON, 0, PAL_EPSILON }, // value: 2 / pi
+ { 0.69314718055994531, 0.69314718055994531, PAL_EPSILON, 0, PAL_EPSILON }, // value: ln(2)
+ { 0.70710678118654752, 0.70710678118654752, PAL_EPSILON, 0, PAL_EPSILON }, // value: 1 / sqrt(2)
+ { 0.78539816339744831, 0.78539816339744831, PAL_EPSILON, 0, PAL_EPSILON }, // value: pi / 4
+ { 1, 0, PAL_EPSILON, 1, PAL_EPSILON * 10 },
+ { 1.1283791670955126, 0.1283791670955126, PAL_EPSILON, 1, PAL_EPSILON * 10 }, // value: 2 / sqrt(pi)
+ { 1.4142135623730950, 0.4142135623730950, PAL_EPSILON, 1, PAL_EPSILON * 10 }, // value: sqrt(2)
+ { 1.4426950408889634, 0.4426950408889634, PAL_EPSILON, 1, PAL_EPSILON * 10 }, // value: log2(e)
+ { 1.5707963267948966, 0.5707963267948966, PAL_EPSILON, 1, PAL_EPSILON * 10 }, // value: pi / 2
+ { 2.3025850929940457, 0.3025850929940457, PAL_EPSILON, 2, PAL_EPSILON * 10 }, // value: ln(10)
+ { 2.7182818284590452, 0.7182818284590452, PAL_EPSILON, 2, PAL_EPSILON * 10 }, // value: e
+ { 3.1415926535897932, 0.1415926535897932, PAL_EPSILON, 3, PAL_EPSILON * 10 }, // value: pi
+ { PAL_POSINF, 0, PAL_EPSILON, PAL_POSINF, 0 }
+
};
-
- // PAL initialization
- if( PAL_Initialize(argc, argv) != 0 )
+ /* PAL initialization */
+ if (PAL_Initialize(argc, argv) != 0)
{
- return FAIL;
+ return FAIL;
}
- for( i = 0; i < sizeof(tests) / sizeof(struct test); i++ )
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
{
- double fractionalResult;
- double integerResult;
- double testDelta;
-
- fractionalResult = modf( tests[i].value, &integerResult );
-
- // The test is valid when the difference between the
- // result and the expectation is less than DELTA
-
- testDelta = fabs( fractionalResult - tests[i].result1 );
-
- if( (testDelta >= DELTA) ||
- (integerResult != tests[i].result2) )
-
- {
- Fail( "ERROR: "
- "modf(%f) returned "
- "fraction=%20.20f and integer=%20.20f "
- "when it should have returned "
- "fraction=%20.20f and integer=%20.20f ",
- tests[i].value,
- fractionalResult,
- integerResult,
- tests[i].result1,
- tests[i].result2 );
- }
+ validate( tests[i].value, tests[i].expected, tests[i].variance, tests[i].expected_intpart, tests[i].variance_intpart);
+ validate(-tests[i].value, -tests[i].expected, tests[i].variance, -tests[i].expected_intpart, tests[i].variance_intpart);
}
+ validate_isnan(PAL_NAN);
+
PAL_Terminate();
return PASS;
}
-
-
-
-
-
-
-
-
-
-
-
-
-
--- /dev/null
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
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
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test1.c (modf)
+**
+** Purpose: Test to ensure that modf return the correct values
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** Fail
+** fabs
+**
+**===========================================================================*/
+
+#include <palsuite.h>
+
+// binary32 (float) has a machine epsilon of 2^-23 (approx. 1.19e-07). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-21 (approx. 4.76e-07) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (6-9 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxx will use PAL_EPSILON
+// for the variance, while an expected result in the format of 0.0xxxxxxxxx will use
+// PAL_EPSILON / 10 and and expected result in the format of x.xxxxxx will use PAL_EPSILON * 10.
+#define PAL_EPSILON 4.76837158e-07
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
+{
+ float value; /* value to test the function with */
+ float expected; /* expected result */
+ float variance; /* maximum delta between the expected and actual result */
+ float expected_intpart; /* expected result */
+ float variance_intpart; /* maximum delta between the expected and actual result */
+};
+
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(float value, float expected, float variance, float expected_intpart, float variance_intpart)
+{
+ float result_intpart;
+ float result = modff(value, &result_intpart);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ float delta = fabsf(result - expected);
+ float delta_intpart = fabsf(result_intpart - expected_intpart);
+
+ if ((delta > variance) || (delta_intpart > variance_intpart))
+ {
+ Fail("modff(%g) returned %10.9g with an intpart of %10.9g when it should have returned %10.9g with an intpart of %10.9g",
+ value, result, result_intpart, expected, expected_intpart);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(float value)
+{
+ float result_intpart;
+ float result = modff(value, &result_intpart);
+
+ if (!_isnan(result) || !_isnan(result_intpart))
+ {
+ Fail("modff(%g) returned %10.9g with an intpart of %10.9g when it should have returned %10.9g with an intpart of %10.9g",
+ value, result, result_intpart, PAL_NAN, PAL_NAN);
+ }
+}
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+int __cdecl main(int argc, char **argv)
+{
+ struct test tests[] =
+ {
+ /* value expected variance expected_intpart variance_intpart */
+ { 0, 0, PAL_EPSILON, 0, PAL_EPSILON },
+ { 0.318309886f, 0.318309886f, PAL_EPSILON, 0, PAL_EPSILON }, // value: 1 / pi
+ { 0.434294482f, 0.434294482f, PAL_EPSILON, 0, PAL_EPSILON }, // value: log10(e)
+ { 0.636619772f, 0.636619772f, PAL_EPSILON, 0, PAL_EPSILON }, // value: 2 / pi
+ { 0.693147181f, 0.693147181f, PAL_EPSILON, 0, PAL_EPSILON }, // value: ln(2)
+ { 0.707106781f, 0.707106781f, PAL_EPSILON, 0, PAL_EPSILON }, // value: 1 / sqrt(2)
+ { 0.785398163f, 0.785398163f, PAL_EPSILON, 0, PAL_EPSILON }, // value: pi / 4
+ { 1, 0, PAL_EPSILON, 1, PAL_EPSILON * 10 },
+ { 1.12837917f, 0.128379167f, PAL_EPSILON, 1, PAL_EPSILON * 10 }, // value: 2 / sqrt(pi)
+ { 1.41421356f, 0.414213562f, PAL_EPSILON, 1, PAL_EPSILON * 10 }, // value: sqrt(2)
+ { 1.44269504f, 0.442695041f, PAL_EPSILON, 1, PAL_EPSILON * 10 }, // value: log2(e)
+ { 1.57079633f, 0.570796327f, PAL_EPSILON, 1, PAL_EPSILON * 10 }, // value: pi / 2
+ { 2.30258509f, 0.302585093f, PAL_EPSILON, 2, PAL_EPSILON * 10 }, // value: ln(10)
+ { 2.71828183f, 0.718281828f, PAL_EPSILON, 2, PAL_EPSILON * 10 }, // value: e
+ { 3.14159265f, 0.141592654f, PAL_EPSILON, 3, PAL_EPSILON * 10 }, // value: pi
+ { PAL_POSINF, 0, PAL_EPSILON, PAL_POSINF, 0 }
+
+ };
+
+ /* PAL initialization */
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
+ {
+ validate( tests[i].value, tests[i].expected, tests[i].variance, tests[i].expected_intpart, tests[i].variance_intpart);
+ validate(-tests[i].value, -tests[i].expected, tests[i].variance, -tests[i].expected_intpart, tests[i].variance_intpart);
+ }
+
+ validate_isnan(PAL_NAN);
+
+ PAL_Terminate();
+ return PASS;
+}
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.
cmake_minimum_required(VERSION 2.8.12.2)
add_subdirectory(test1)
-add_subdirectory(test2)
-add_subdirectory(test3)
-
**
** Source: test1.c
**
-** Purpose: Call the pow function with various values,
-** to test specified valid input and boundaries.
-**
+** Purpose: Tests that atan2 returns correct values for a subset of values.
+** Tests with positive and negative values of x and y to ensure
+** atan2 is returning results from the correct quadrant.
**
**===================================================================*/
-/* Notes: SCENARIO CASE
- - Both number and exponent may be non-integers 1
- - Exponent may be negative 2
- - If number anything and exponent is 0, returns 1 3
- - If number is 0 and exponent is positive, returns 0 4
- - Number may be negative with integer exponents 5
- - Other valid input returns the usual valid output 6
- - See test2 for infinite and nan input/output cases
-*/
-
#include <palsuite.h>
-/* Error acceptance level to the 7th decimal */
-#define DELTA 0.0000001
-
-struct testCase
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
{
- double Number;
- double Exponent;
- double CorrectValue;
+ double x; /* first component of the value to test the function with */
+ double y; /* second component of the value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
};
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double x, double y, double expected, double variance)
+{
+ double result = pow(x, y);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("pow(%g, %g) returned %20.17g when it should have returned %20.17g",
+ x, y, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double x, double y)
+{
+ double result = pow(x, y);
+
+ if (!_isnan(result))
+ {
+ Fail("pow(%g, %g) returned %20.17g when it should have returned %20.17g",
+ x, y, result, PAL_NAN);
+ }
+}
+
+/**
+ * main
+ *
+ * executable entry point
+ */
int __cdecl main(int argc, char **argv)
{
- double result=0;
- double testDelta=99999;
- int i=0;
-
- struct testCase testCases[] = /* CASE */
- {
- {0, 0, 1 }, /* 3 */
- {0.0, 0.0, 1 }, /* 3 */
- {-0, 0, 1 }, /* 3 */
- {-0, -0, 1 }, /* 3 */
- {2, 0, 1 }, /* 3 */
- {2, 0.0, 1 }, /* 3 */
- {2, -0.0, 1 }, /* 3 */
- {42.3124234, 0, 1 }, /* 3 */
- {-2, -0.0, 1 }, /* 3 */
- {-3.33132, -0.0, 1 }, /* 3 */
- {-999990, 0, 1 }, /* 3 */
- {9999.9999, 0.0, 1 }, /* 3 */
- {-9999.9999, 0.0, 1 }, /* 3 */
- {0, 1, 0 }, /* 4 */
- {0.0, 2, 0 }, /* 4 */
- {0.0, 3, 0 }, /* 4 */
- {-0, 9.99999, 0 }, /* 4 */
- {2, 2, 4 }, /* 6 */
- {2, -2, 0.25 }, /* 6 */
- {6.25, 2.5, 97.65625 }, /* 6 */
- {12345.12345, 9.99999,
- 82207881573997179707867981634171194834944.0 }, /* 6 */
- {12345, 75,
- 7.2749844621476552703935675020036e+306 }, /* 6 */
- {-2.012, 2, 4.048144 }, /* 6 */
- {2, 1, 2 }, /* 6 */
- {8, 1, 8 }, /* 6 */
- {MAXLONG, 1, MAXLONG }, /* 6 */
- {4.321, 1, 4.321 }, /* 6 */
- {-4.321, 1, -4.321 } /* 6 */
- };
- if (0 != (PAL_Initialize(argc, argv)))
+ struct test tests[] =
+ {
+ /* x y expected variance */
+ { PAL_NEGINF, PAL_NEGINF, 0, PAL_EPSILON },
+ { PAL_NEGINF, PAL_POSINF, PAL_POSINF, 0 },
+
+ { -10, PAL_NEGINF, 0, PAL_EPSILON },
+ { -10, -1, -0.1, PAL_EPSILON },
+ { -10, 0, 1, PAL_EPSILON * 10 },
+ { -10, 1, -10, PAL_EPSILON * 100 },
+ { -10, PAL_POSINF, PAL_POSINF, 0 },
+
+ { -2.7182818284590452, PAL_NEGINF, 0, PAL_EPSILON }, // x: -(e)
+ { -2.7182818284590452, -1, -0.36787944117144232, PAL_EPSILON }, // x: -(e)
+ { -2.7182818284590452, 0, 1, PAL_EPSILON * 10 }, // x: -(e)
+ { -2.7182818284590452, 1, -2.7182818284590452, PAL_EPSILON * 10 }, // x: -(e) expected: e
+ { -2.7182818284590452, PAL_POSINF, PAL_POSINF, 0 }, // x: -(e)
+
+ { -0.0, -0.0, 1, PAL_EPSILON * 10 },
+ { -0.0, 0, 1, PAL_EPSILON * 10 },
+
+ { 0, -0.0, 1, PAL_EPSILON * 10 },
+ { 0, 0, 1, PAL_EPSILON * 10 },
+
+ { 2.7182818284590452, PAL_NEGINF, 0, PAL_EPSILON },
+ { 2.7182818284590452, -3.1415926535897932, 0.043213918263772250, PAL_EPSILON / 10 }, // x: e y: -(pi)
+ { 2.7182818284590452, -2.7182818284590452, 0.065988035845312537, PAL_EPSILON / 10 }, // x: e y: -(e)
+ { 2.7182818284590452, -2.3025850929940457, 0.1, PAL_EPSILON }, // x: e y: -(ln(10))
+ { 2.7182818284590452, -1.5707963267948966, 0.20787957635076191, PAL_EPSILON }, // x: e y: -(pi / 2)
+ { 2.7182818284590452, -1.4426950408889634, 0.23629008834452270, PAL_EPSILON }, // x: e y: -(log2(e))
+ { 2.7182818284590452, -1.4142135623730950, 0.24311673443421421, PAL_EPSILON }, // x: e y: -(sqrt(2))
+ { 2.7182818284590452, -1.1283791670955126, 0.32355726390307110, PAL_EPSILON }, // x: e y: -(2 / sqrt(pi))
+ { 2.7182818284590452, -1, 0.36787944117144232, PAL_EPSILON }, // x: e y: -(1)
+ { 2.7182818284590452, -0.78539816339744831, 0.45593812776599624, PAL_EPSILON }, // x: e y: -(pi / 4)
+ { 2.7182818284590452, -0.70710678118654752, 0.49306869139523979, PAL_EPSILON }, // x: e y: -(1 / sqrt(2))
+ { 2.7182818284590452, -0.69314718055994531, 0.5, PAL_EPSILON }, // x: e y: -(ln(2))
+ { 2.7182818284590452, -0.63661977236758134, 0.52907780826773535, PAL_EPSILON }, // x: e y: -(2 / pi)
+ { 2.7182818284590452, -0.43429448190325183, 0.64772148514180065, PAL_EPSILON }, // x: e y: -(log10(e))
+ { 2.7182818284590452, -0.31830988618379067, 0.72737734929521647, PAL_EPSILON }, // x: e y: -(1 / pi)
+ { 2.7182818284590452, 0, 1, PAL_EPSILON * 10 }, // x: e
+ { 2.7182818284590452, 0.31830988618379067, 1.3748022274393586, PAL_EPSILON * 10 }, // x: e y: 1 / pi
+ { 2.7182818284590452, 0.43429448190325183, 1.5438734439711811, PAL_EPSILON * 10 }, // x: e y: log10(e)
+ { 2.7182818284590452, 0.63661977236758134, 1.8900811645722220, PAL_EPSILON * 10 }, // x: e y: 2 / pi
+ { 2.7182818284590452, 0.69314718055994531, 2, PAL_EPSILON * 10 }, // x: e y: ln(2)
+ { 2.7182818284590452, 0.70710678118654752, 2.0281149816474725, PAL_EPSILON * 10 }, // x: e y: 1 / sqrt(2)
+ { 2.7182818284590452, 0.78539816339744831, 2.1932800507380155, PAL_EPSILON * 10 }, // x: e y: pi / 4
+ { 2.7182818284590452, 1, 2.7182818284590452, PAL_EPSILON * 10 }, // x: e expected: e
+ { 2.7182818284590452, 1.1283791670955126, 3.0906430223107976, PAL_EPSILON * 10 }, // x: e y: 2 / sqrt(pi)
+ { 2.7182818284590452, 1.4142135623730950, 4.1132503787829275, PAL_EPSILON * 10 }, // x: e y: sqrt(2)
+ { 2.7182818284590452, 1.4426950408889634, 4.2320861065570819, PAL_EPSILON * 10 }, // x: e y: log2(e)
+ { 2.7182818284590452, 1.5707963267948966, 4.8104773809653517, PAL_EPSILON * 10 }, // x: e y: pi / 2
+ { 2.7182818284590452, 2.3025850929940457, 10, PAL_EPSILON * 100 }, // x: e y: ln(10)
+ { 2.7182818284590452, 2.7182818284590452, 15.154262241479264, PAL_EPSILON * 100 }, // x: e y: e
+ { 2.7182818284590452, 3.1415926535897932, 23.140692632779269, PAL_EPSILON * 100 }, // x: e y: pi
+ { 2.7182818284590452, PAL_POSINF, PAL_POSINF, 0 }, // x: e
+
+ { 10, PAL_NEGINF, 0, 0 },
+ { 10, -3.1415926535897932, 0.00072178415907472774, PAL_EPSILON / 1000 }, // y: -(pi)
+ { 10, -2.7182818284590452, 0.0019130141022243176, PAL_EPSILON / 100 }, // y: -(e)
+ { 10, -2.3025850929940457, 0.0049821282964407206, PAL_EPSILON / 100 }, // y: -(ln(10))
+ { 10, -1.5707963267948966, 0.026866041001136132, PAL_EPSILON / 10 }, // y: -(pi / 2)
+ { 10, -1.4426950408889634, 0.036083192820787210, PAL_EPSILON / 10 }, // y: -(log2(e))
+ { 10, -1.4142135623730950, 0.038528884700322026, PAL_EPSILON / 10 }, // y: -(sqrt(2))
+ { 10, -1.1283791670955126, 0.074408205860642723, PAL_EPSILON / 10 }, // y: -(2 / sqrt(pi))
+ { 10, -1, 0.1, PAL_EPSILON }, // y: -(1)
+ { 10, -0.78539816339744831, 0.16390863613957665, PAL_EPSILON }, // y: -(pi / 4)
+ { 10, -0.70710678118654752, 0.19628775993505562, PAL_EPSILON }, // y: -(1 / sqrt(2))
+ { 10, -0.69314718055994531, 0.20269956628651730, PAL_EPSILON }, // y: -(ln(2))
+ { 10, -0.63661977236758134, 0.23087676451600055, PAL_EPSILON }, // y: -(2 / pi)
+ { 10, -0.43429448190325183, 0.36787944117144232, PAL_EPSILON }, // y: -(log10(e))
+ { 10, -0.31830988618379067, 0.48049637305186868, PAL_EPSILON }, // y: -(1 / pi)
+ { 10, 0, 1, PAL_EPSILON * 10 },
+ { 10, 0.31830988618379067, 2.0811811619898573, PAL_EPSILON * 10 }, // y: 1 / pi
+ { 10, 0.43429448190325183, 2.7182818284590452, PAL_EPSILON * 10 }, // y: log10(e) expected: e
+ { 10, 0.63661977236758134, 4.3313150290214525, PAL_EPSILON * 10 }, // y: 2 / pi
+ { 10, 0.69314718055994531, 4.9334096679145963, PAL_EPSILON * 10 }, // y: ln(2)
+ { 10, 0.70710678118654752, 5.0945611704512962, PAL_EPSILON * 10 }, // y: 1 / sqrt(2)
+ { 10, 0.78539816339744831, 6.1009598002416937, PAL_EPSILON * 10 }, // y: pi / 4
+ { 10, 1, 10, PAL_EPSILON * 100 },
+ { 10, 1.1283791670955126, 13.439377934644400, PAL_EPSILON * 100 }, // y: 2 / sqrt(pi)
+ { 10, 1.4142135623730950, 25.954553519470081, PAL_EPSILON * 100 }, // y: sqrt(2)
+ { 10, 1.4426950408889634, 27.713733786437790, PAL_EPSILON * 100 }, // y: log2(e)
+ { 10, 1.5707963267948966, 37.221710484165167, PAL_EPSILON * 100 }, // y: pi / 2
+ { 10, 2.3025850929940457, 200.71743249053009, PAL_EPSILON * 1000 }, // y: ln(10)
+ { 10, 2.7182818284590452, 522.73529967043665, PAL_EPSILON * 1000 }, // y: e
+ { 10, 3.1415926535897932, 1385.4557313670111, PAL_EPSILON * 10000 }, // y: pi
+ { 10, PAL_POSINF, PAL_POSINF, 0 },
+
+ { PAL_POSINF, PAL_NEGINF, 0, PAL_EPSILON },
+ { PAL_POSINF, PAL_POSINF, PAL_POSINF, 0 },
+ };
+
+ if (PAL_Initialize(argc, argv) != 0)
{
return FAIL;
}
- /* Loop through each case. Call pow on each value and check the
- result.
- */
- for(i = 0; i < sizeof(testCases) / sizeof(struct testCase); i++)
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
{
- result = pow(testCases[i].Number, testCases[i].Exponent);
- testDelta = fabs(result - testCases[i].CorrectValue);
-
- if ( testDelta >= DELTA )
- {
- Fail("ERROR: pow took the '%f' to the exponent '%f' "
- "to be %f instead of %f.\n",
- testCases[i].Number,
- testCases[i].Exponent,
- result,
- testCases[i].CorrectValue);
- }
+ validate(tests[i].x, tests[i].y, tests[i].expected, tests[i].variance);
}
+ validate_isnan(-10, -1.5707963267948966); // y: -(pi / 2)
+ validate_isnan(-10, -0.78539816339744828); // y: -(pi / 4)
+ validate_isnan(-10, 0.78539816339744828); // y: pi / 4
+ validate_isnan(-10, 1.5707963267948966); // y: pi / 2
+
+ validate_isnan(-2.7182818284590452, -1.5707963267948966); // x: -(e) y: -(pi / 2)
+ validate_isnan(-2.7182818284590452, -0.78539816339744828); // x: -(e) y: -(pi / 4)
+ validate_isnan(-2.7182818284590452, 0.78539816339744828); // x: -(e) y: pi / 4
+ validate_isnan(-2.7182818284590452, 1.5707963267948966); // x: -(e) y: pi / 2
+
+ validate_isnan(PAL_NEGINF, PAL_NAN);
+ validate_isnan(PAL_NAN, PAL_NEGINF);
+
+ validate_isnan(PAL_POSINF, PAL_NAN);
+ validate_isnan(PAL_NAN, PAL_POSINF);
+
+ validate_isnan(PAL_NAN, PAL_NAN);
+
PAL_Terminate();
return PASS;
}
-
-
-
-
-
-
-
-
-
-
-
-
-
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-/*=====================================================================
-**
-** Source: test2.c
-**
-** Purpose: Call the pow function with various values,
-** to test special in/out values.
-**
-**
-**===================================================================*/
-
-/* Notes: The following table summarizes expected results:
- NUMBER EXPONENT RETURNS CASE
- PosInf > 0 PosInf 1
- PosInf < 0 0 2
- NegInf > 0 (even int) PosInf 3
- NegInf > 0 (odd int) NegInf 4
- NegInf < 0 (odd int) 0 5
- NegInf < 0 (even int) 0 6
- |num| > 1 PosInf PosInf 7
- |num| < 1 PosInf 0 8
- |num| > 1 NegInf 0 9
- |num| < 1 NegInf PosInf 10
- +1 PosInf NaN 11
- +1 NegInf NaN 12
- < 0 non-int NaN 13
- 0 < 0 (odd int) NegInf 14
- 0 < 0 (even int) PosInf 15
- Large Large PosInf 16
- -Large Large NegInf 17
- Large -Large 0 18
- -Large -Large 0 19
-*/
-
-#include <palsuite.h>
-
-struct testCase
-{
- double Number;
- double Exponent;
-};
-
-int __cdecl main(int argc, char **argv)
-{
- double zero = 0.0;
- double PosInf = 1.0 / zero;
- double NegInf = -1.0 / zero;
- double NaN = 0.0 / zero;
- volatile double result=0;
- int i=0;
-
- struct testCase retPosInf[] =
- { /* CASE */
- {PosInf, .3123 }, /* 1 */
- {PosInf, 3123 }, /* 1 */
- {PosInf, 31.23 }, /* 1 */
- {NegInf, 2 }, /* 3 */
- {NegInf, 3576 }, /* 3 */
- {1.1, PosInf }, /* 7 */
- {6.2315, PosInf }, /* 7 */
- {423511, PosInf }, /* 7 */
- {-1.1, PosInf }, /* 7 */
- {-6.2315, PosInf }, /* 7 */
- {-423511, PosInf }, /* 7 */
- {0.1234, NegInf }, /* 10 */
- {-0.134, NegInf }, /* 10 */
- {0.1234, NegInf }, /* 10 */
- {0, -1 }, /* 14 */
- {0, -3 }, /* 14 */
- {0, -1324391351 }, /* 14 */
- {0, -2 }, /* 15 */
- {0, -35798 }, /* 15 */
- {MAXLONG, MAXLONG } /* 16 */
- };
-
- struct testCase retNegInf[] =
- {
- {NegInf, 1 }, /* 4 */
- {NegInf, 1324391315 }, /* 4 */
- {-(MAXLONG), MAXLONG } /* 17 */
- };
-
- struct testCase retNaN[] =
- {
- {1, PosInf }, /* 11 */
- {1, NegInf }, /* 12 */
- {-1, -0.1 }, /* 13 */
- {-0.1, -0.1 }, /* 13 */
- {-1324391351, -0.1 }, /* 13 */
- {-3124.391351, -0.1 }, /* 13 */
- {-1, 0.1 }, /* 13 */
- {-0.1, 0.1 }, /* 13 */
- {-1324391351, 0.1 }, /* 13 */
- {-3124.391351, 0.1 } /* 13 */
- };
-
- struct testCase retZero[] =
- {
- {PosInf, -0.323 }, /* 2 */
- {PosInf, -1 }, /* 2 */
- {PosInf, -1324391351 }, /* 2 */
- {PosInf, -3124.391351 }, /* 2 */
- {NegInf, -1 }, /* 5 */
- {NegInf, -3 }, /* 5 */
- {NegInf, -1324391351 }, /* 5 */
- {NegInf, -2 }, /* 6 */
- {NegInf, -4 }, /* 6 */
- {NegInf, -1243913514 }, /* 6 */
- {0.132, PosInf }, /* 8 */
- {-0.132, PosInf }, /* 8 */
- {1.1, NegInf }, /* 9 */
- {-1.1, NegInf }, /* 9 */
- {2, NegInf }, /* 9 */
- {3, NegInf }, /* 9 */
- {-1324391353, NegInf }, /* 9 */
- {1324391354, NegInf }, /* 9 */
- {-31.24391353, NegInf }, /* 9 */
- {31.24391353, NegInf }, /* 9 */
- {MAXLONG, -(MAXLONG) }, /* 18 */
- {-(MAXLONG), -(MAXLONG) } /* 19 */
- };
-
-
- if (0 != (PAL_Initialize(argc, argv)))
- {
- return FAIL;
- }
-
- /* Loop through each case. Call pow on each number/exponent pair
- and check the result.
- */
- /* First those test cases returning positive infinity. */
- for(i = 0; i < sizeof(retPosInf) / sizeof(struct testCase); i++)
- {
- result = pow(retPosInf[i].Number, retPosInf[i].Exponent);
-
- if ( result != PosInf )
- {
- Fail("ERROR: pow took '%f' to the exponent '%f' "
- "to be %f instead of %f.\n",
- retPosInf[i].Number,
- retPosInf[i].Exponent,
- result,
- PosInf);
- }
- }
-
- /* First those test cases returning negative infinity. */
- for(i = 0; i < sizeof(retNegInf) / sizeof(struct testCase); i++)
- {
- result = pow(retNegInf[i].Number, retNegInf[i].Exponent);
-
- if ( result != NegInf )
- {
- Fail("ERROR: pow took '%f' to the exponent '%f' "
- "to be %f instead of %f.\n",
- retNegInf[i].Number,
- retNegInf[i].Exponent,
- result,
- NegInf);
- }
- }
-
- /* First those test cases returning non-numbers. */
- for(i = 0; i < sizeof(retNaN) / sizeof(struct testCase); i++)
- {
- result = pow(retNaN[i].Number, retNaN[i].Exponent);
-
- if ( ! _isnan(result) )
- {
- Fail("ERROR: pow took '%f' to the exponent '%f' "
- "to be %f instead of %f.\n",
- retNaN[i].Number,
- retNaN[i].Exponent,
- result,
- NaN);
- }
- }
-
- /* First those test cases returning zero. */
- for(i = 0; i < sizeof(retZero) / sizeof(struct testCase); i++)
- {
- result = pow(retZero[i].Number, retZero[i].Exponent);
-
- if ( result != 0)
- {
- Fail("ERROR: pow took '%f' to the exponent '%f' "
- "to be %f instead of %f.\n",
- retZero[i].Number,
- retZero[i].Exponent,
- result,
- 0.0);
- }
- }
-
- PAL_Terminate();
- return PASS;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
+++ /dev/null
-# 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.
-
+++ /dev/null
-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
-)
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-/*=============================================================================
-**
-** Source: test3.c
-**
-** Purpose: Test to ensure that pow returns correct values.
-**
-** Dependencies: PAL_Initialize
-** PAL_Terminate
-** Fail
-** fabs
-** _finite
-** _isnan
-**
-
-**
-**===========================================================================*/
-
-#include <palsuite.h>
-
-#define DELTA 0.0000001 /* Error acceptance level to the 7th decimal */
-
-/**
- * Helper test structure
- */
-struct test1
-{
- double value; /* value to test the function with */
- double exponent; /* exponent to test */
- double result; /* expected result */
-};
-
-struct test2
-{
- double value; /* value to test the function with */
- double exponent; /* exponent to test */
-};
-
-
-/**
- * main
- *
- * executable entry point
- */
-int __cdecl main(int argc, char **argv)
-{
- int i;
- double result;
-
- struct test1 tests[] =
- {
- /* Value test result */
- { 0.0, 0.0, 1.0 },
- { 4.2, 0.0, 1.0 },
- { 2.0, 3.0, 8.0 },
- { 0.1, 3.25, 0.000562341325 },
- { 1.0, 4.0, 1.000000000000 },
- { 2.4, -6.8, 0.002597547849 },
- { 3.75, 10.4, 933093.543524607670 },
- { 7.63, -4.521, 0.000102354411 },
- { 10, 5, 100000.000000000000 },
- { 13.26, -2.11, 0.004279895490 },
- { 18.1, 3.763, 54031.183101303657 },
- { 25, 4.0001, 390750.757575723810 },
- { 29.31, -5.997, 0.000000001593 }
- };
-
- struct test2 infinite[] =
- {
- { 0.0, -2.5 },
- { 0.0, -1 }
- };
-
-
- /* PAL initialization */
- if( PAL_Initialize(argc, argv) != 0 )
- {
- return (FAIL);
- }
-
- for( i = 0; i < sizeof(tests) / sizeof(struct test1); i++)
- {
- double testDelta;
-
- result = pow( tests[i].value, tests[i].exponent );
-
- /* The test is valid when the difference between the */
- /* result and the expectation is less than DELTA */
- testDelta = fabs( result - tests[i].result );
- if( testDelta >= DELTA )
- {
- Fail( "pow(%g,%g) returned %20.10g"
- " when it should have returned %20.10g\n",
- tests[i].value,
- tests[i].exponent,
- result,
- tests[i].result );
- }
- }
-
- for( i = 0; i < sizeof(infinite) / sizeof(struct test2); i++)
- {
- result = pow( infinite[i].value, infinite[i].exponent );
-
- /* The test is valid when the function returns an infinite result */
- if( _finite( result ) )
- {
- Fail( "pow(%g,%g) returned %20.10g"
- " when it should have returned 1.#INF00000000",
- infinite[i].value,
- infinite[i].exponent,
- result );
- }
- }
-
- PAL_Terminate();
- return PASS;
-}
cmake_minimum_required(VERSION 2.8.12.2)
add_subdirectory(test1)
-
**
** Dependencies: PAL_Initialize
** PAL_Terminate
-** Fail
+** Fail
** fabs
-**
-
**
**===========================================================================*/
#include <palsuite.h>
-#define DELTA 0.0000001 /* Error acceptance level to the 7th decimal */
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
/**
* Helper test structure
*/
struct test
{
- double value; /* value to test the function with */
- double result; /* expected result */
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
};
/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+ double result = sin(value);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("sin(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result = sin(value);
+
+ if (!_isnan(result))
+ {
+ Fail("sin(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_NAN);
+ }
+}
+
+/**
* main
*
* executable entry point
*/
-INT __cdecl main(INT argc, CHAR **argv)
+int __cdecl main(int argc, char **argv)
{
- double pi = 3.1415926535;
- int i;
-
struct test tests[] =
{
- /* Value test result */
- { 0, 0 },
- { pi/2.0, 1 },
- { pi, 0 },
- { (3.0*pi) / 2.0, -1 },
- { 2.0 * pi, 0 },
- { 5.0*pi/2.0, 1 },
- { 3.0*pi, 0 },
- { (7.0*pi) / 2.0, -1 },
- { 4.0 * pi, 0 }
+ /* value expected variance */
+ { 0, 0, PAL_EPSILON },
+ { 0.31830988618379067, 0.31296179620778659, PAL_EPSILON }, // value: 1 / pi
+ { 0.43429448190325183, 0.42077048331375735, PAL_EPSILON }, // value: log10(e)
+ { 0.63661977236758134, 0.59448076852482208, PAL_EPSILON }, // value: 2 / pi
+ { 0.69314718055994531, 0.63896127631363480, PAL_EPSILON }, // value: ln(2)
+ { 0.70710678118654752, 0.64963693908006244, PAL_EPSILON }, // value: 1 / sqrt(2)
+ { 0.78539816339744831, 0.70710678118654752, PAL_EPSILON }, // value: pi / 4, expected: 1 / sqrt(2)
+ { 1, 0.84147098480789651, PAL_EPSILON },
+ { 1.1283791670955126, 0.90371945743584630, PAL_EPSILON }, // value: 2 / sqrt(pi)
+ { 1.4142135623730950, 0.98776594599273553, PAL_EPSILON }, // value: sqrt(2)
+ { 1.4426950408889634, 0.99180624439366372, PAL_EPSILON }, // value: log2(e)
+ { 1.5707963267948966, 1, PAL_EPSILON * 10 }, // value: pi / 2
+ { 2.3025850929940457, 0.74398033695749319, PAL_EPSILON }, // value: ln(10)
+ { 2.7182818284590452, 0.41078129050290870, PAL_EPSILON }, // value: e
+ { 3.1415926535897932, 0, PAL_EPSILON }, // value: pi
};
-
/* PAL initialization */
- if( PAL_Initialize(argc, argv) != 0 )
+ if (PAL_Initialize(argc, argv) != 0)
{
- return (FAIL);
+ return FAIL;
}
- for( i = 0; i < sizeof(tests) / sizeof(struct test); i++)
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
{
- double result;
- double testDelta;
-
-
- result = sin( tests[i].value );
-
- /*
- * The test is valid when the difference between the
- * result and the expectation is less than DELTA
- */
- testDelta = fabs( result - tests[i].result );
- if( testDelta >= DELTA )
- {
- Fail( "sin(%g) returned %g"
- " when it should have returned %g",
- tests[i].value,
- result,
- tests[i].result );
- }
+ validate( tests[i].value, tests[i].expected, tests[i].variance);
+ validate(-tests[i].value, -tests[i].expected, tests[i].variance);
}
+
+ validate_isnan(PAL_NEGINF);
+ validate_isnan(PAL_NAN);
+ validate_isnan(PAL_POSINF);
PAL_Terminate();
return PASS;
}
-
-
-
-
-
-
-
-
-
-
-
-
-
Description
= Passes to sin() a series of angle value, checking that
= each one return to correct value.
-
-
-
cmake_minimum_required(VERSION 2.8.12.2)
add_subdirectory(test1)
-
**
** Dependencies: PAL_Initialize
** PAL_Terminate
-** Fail
+** Fail
** fabs
-**
-
**
**===========================================================================*/
#include <palsuite.h>
-#define DELTA 0.0000001 /*Error acceptance level to the 7th decimal */
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
/**
* Helper test structure
*/
struct test
{
- double value; /* value to test the function with */
- double result; /* expected result */
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
};
/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+ double result = sinh(value);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("sinh(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result = sinh(value);
+
+ if (!_isnan(result))
+ {
+ Fail("sinh(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_NAN);
+ }
+}
+
+/**
* main
*
* executable entry point
*/
-INT __cdecl main(INT argc, CHAR **argv)
+int __cdecl main(int argc, char **argv)
{
- double pi = 3.1415926535;
- int i;
-
struct test tests[] =
{
- /* Value test result */
- { 0, 0 },
- { pi/2.0, 2.3012989 },
- { pi, 11.5487394 },
- { (3.0*pi) / 2.0, 55.6543976 },
- { 2.0 * pi, 267.7448940 },
- { 5.0*pi/2.0, 1287.9850539 },
- { 3.0*pi, 6195.8238619 },
- { (7.0*pi) / 2.0, 29804.8707287 },
- { 4.0 * pi, 143375.6565151 }
+ /* value expected variance */
+ { 0, 0, PAL_EPSILON },
+ { 0.31830988618379067, 0.32371243907207108, PAL_EPSILON }, // value: 1 / pi
+ { 0.43429448190325183, 0.44807597941469025, PAL_EPSILON }, // value: log10(e)
+ { 0.63661977236758134, 0.68050167815224332, PAL_EPSILON }, // value: 2 / pi
+ { 0.69314718055994531, 0.75, PAL_EPSILON }, // value: ln(2)
+ { 0.70710678118654752, 0.76752314512611633, PAL_EPSILON }, // value: 1 / sqrt(2)
+ { 0.78539816339744831, 0.86867096148600961, PAL_EPSILON }, // value: pi / 4
+ { 1, 1.1752011936438015, PAL_EPSILON * 10 },
+ { 1.1283791670955126, 1.3835428792038633, PAL_EPSILON * 10 }, // value: 2 / sqrt(pi)
+ { 1.4142135623730950, 1.9350668221743567, PAL_EPSILON * 10 }, // value: sqrt(2)
+ { 1.4426950408889634, 1.9978980091062796, PAL_EPSILON * 10 }, // value: log2(e)
+ { 1.5707963267948966, 2.3012989023072949, PAL_EPSILON * 10 }, // value: pi / 2
+ { 2.3025850929940457, 4.95, PAL_EPSILON * 10 }, // value: ln(10)
+ { 2.7182818284590452, 7.5441371028169758, PAL_EPSILON * 10 }, // value: e
+ { 3.1415926535897932, 11.548739357257748, PAL_EPSILON * 100 }, // value: pi
+ { PAL_POSINF, PAL_POSINF, 0 },
};
-
/* PAL initialization */
- if( PAL_Initialize(argc, argv) != 0 )
+ if (PAL_Initialize(argc, argv) != 0)
{
- return (FAIL);
+ return FAIL;
}
- for( i = 0; i < sizeof(tests) / sizeof(struct test); i++)
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
{
- double result;
- double testDelta;
-
-
- result = sinh( tests[i].value );
-
- /*
- * The test is valid when the difference between the
- * result and the expectation is less than DELTA
- */
- testDelta = fabs( result - tests[i].result );
- if( testDelta >= DELTA )
- {
- Fail( "sinh(%g) returned %g"
- " when it should have returned %g",
- tests[i].value,
- result,
- tests[i].result );
- }
+ validate( tests[i].value, tests[i].expected, tests[i].variance);
+ validate(-tests[i].value, -tests[i].expected, tests[i].variance);
}
+
+ validate_isnan(PAL_NAN);
PAL_Terminate();
return PASS;
}
-
-
-
-
-
-
-
-
-
-
-
-
-
Description
= Passes to sinh() a series of angle value, checking that
= each one return to correct value.
-
-
-
**
**===================================================================*/
-/* Note: Calling sqrt on anything negative gives indefinite results. */
-
#include <palsuite.h>
-struct testCase
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
{
- double Value;
- double CorrectValue;
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
};
-int __cdecl main(int argc, char **argv)
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
{
- double delta;
- double result=0;
- int i=0;
+ double result = sqrt(value);
- struct testCase testCases[] =
- {
- {100, 10},
- {6.25, 2.5},
- {0, 0},
- {1.7e+308, 1.3038404810405297e+154} /* Max Double value */
- };
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
- if (0 != (PAL_Initialize(argc, argv)))
+ if (delta > variance)
{
- return FAIL;
+ Fail("sqrt(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, expected);
}
+}
- /* Loop through each case. Call sqrt on each value and check the
- result.
- */
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result = sqrt(value);
+
+ if (!_isnan(result))
+ {
+ Fail("sqrt(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_NAN);
+ }
+}
- for(i = 0; i < sizeof(testCases) / sizeof(struct testCase); i++)
+int __cdecl main(int argc, char **argv)
+{
+ struct test tests[] =
{
- result = sqrt(testCases[i].Value);
- delta = pow(10, log10(testCases[i].Value) - 7);
+ /* value expected variance */
+ { 0.31830988618379067, 0.56418958354775629, PAL_EPSILON }, // value: 1 / pi
+ { 0.43429448190325183, 0.65901022898226081, PAL_EPSILON }, // value: log10(e)
+ { 0.63661977236758134, 0.79788456080286536, PAL_EPSILON }, // value: 2 / pi
+ { 0.69314718055994531, 0.83255461115769776, PAL_EPSILON }, // value: ln(2)
+ { 0.70710678118654752, 0.84089641525371454, PAL_EPSILON }, // value: 1 / sqrt(2)
+ { 0.78539816339744831, 0.88622692545275801, PAL_EPSILON }, // value: pi / 4
+ { 1, 1, PAL_EPSILON * 10 },
+ { 1.1283791670955126, 1.0622519320271969, PAL_EPSILON * 10 }, // value: 2 / sqrt(pi)
+ { 1.4142135623730950, 1.1892071150027211, PAL_EPSILON * 10 }, // value: sqrt(2)
+ { 1.4426950408889634, 1.2011224087864498, PAL_EPSILON * 10 }, // value: log2(e)
+ { 1.5707963267948966, 1.2533141373155003, PAL_EPSILON * 10 }, // value: pi / 2
+ { 2.3025850929940457, 1.5174271293851464, PAL_EPSILON * 10 }, // value: ln(10)
+ { 2.7182818284590452, 1.6487212707001281, PAL_EPSILON * 10 }, // value: e
+ { 3.1415926535897932, 1.7724538509055160, PAL_EPSILON * 10 }, // value: pi
+ };
+
+ /* PAL initialization */
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ validate(-0.0, -0.0, PAL_EPSILON);
+ validate( 0.0, 0.0, PAL_EPSILON);
- if (fabs(testCases[i].CorrectValue - result) > delta)
- {
- Fail("ERROR: sqrt took the square root of '%f' to be '%f' "
- "instead of %f.\n",
- testCases[i].Value,
- result,
- testCases[i].CorrectValue);
- }
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
+ {
+ validate(tests[i].value, tests[i].expected, tests[i].variance);
+ validate_isnan(-tests[i].value);
}
+
+ validate_isnan(PAL_NAN);
PAL_Terminate();
return PASS;
}
-
-
-
-
-
-
-
-
-
-
-
-
-
cmake_minimum_required(VERSION 2.8.12.2)
add_subdirectory(test1)
-
**
** Dependencies: PAL_Initialize
** PAL_Terminate
-** Fail
+** Fail
** fabs
-**
-
**
**===========================================================================*/
#include <palsuite.h>
-#define DELTA 0.0000001 /*Error acceptance level to the 7th decimal */
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
/**
* Helper test structure
*/
struct test
{
- double value; /* value to test the function with */
- double result; /* expected result */
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
};
/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+ double result = tan(value);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("tan(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result = tan(value);
+
+ if (!_isnan(result))
+ {
+ Fail("tan(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_NAN);
+ }
+}
+
+/**
* main
*
* executable entry point
*/
-INT __cdecl main(INT argc, CHAR **argv)
+int __cdecl main(int argc, char **argv)
{
- int i;
-
struct test tests[] =
{
- /* Value test result */
- { 0.001, 0.001 },
- { 0.05, 0.050041708 },
- { 0.5, 0.54630249 },
- { 1, 1.557407725 },
- { 2, -2.185039863 },
- { 3, -0.142546543 },
- { 4, 1.157821282 }
+ /* value expected variance */
+ { 0, 0, PAL_EPSILON },
+ { 0.31830988618379067, 0.32951473309607836, PAL_EPSILON }, // value: 1 / pi
+ { 0.43429448190325183, 0.46382906716062964, PAL_EPSILON }, // value: log10(e)
+ { 0.63661977236758134, 0.73930295048660405, PAL_EPSILON }, // value: 2 / pi
+ { 0.69314718055994531, 0.83064087786078395, PAL_EPSILON }, // value: ln(2)
+ { 0.70710678118654752, 0.85451043200960189, PAL_EPSILON }, // value: 1 / sqrt(2)
+ { 0.78539816339744831, 1, PAL_EPSILON * 10 }, // value: pi / 4
+ { 1, 1.5574077246549022, PAL_EPSILON * 10 },
+ { 1.1283791670955126, 2.1108768356626451, PAL_EPSILON * 10 }, // value: 2 / sqrt(pi)
+ { 1.4142135623730950, 6.3341191670421916, PAL_EPSILON * 10 }, // value: sqrt(2)
+ { 1.4426950408889634, 7.7635756709721848, PAL_EPSILON * 10 }, // value: log2(e)
+ // SEE BELOW -- { 1.5707963267948966, PAL_POSINF, 0 }, // value: pi / 2
+ { 2.3025850929940457, -1.1134071468135374, PAL_EPSILON * 10 }, // value: ln(10)
+ { 2.7182818284590452, -0.45054953406980750, PAL_EPSILON }, // value: e
+ { 3.1415926535897932, 0, PAL_EPSILON }, // value: pi
};
-
/* PAL initialization */
- if( PAL_Initialize(argc, argv) != 0 )
+ if (PAL_Initialize(argc, argv) != 0)
{
- return (FAIL);
+ return FAIL;
}
- for( i = 0; i < sizeof(tests) / sizeof(struct test); i++)
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
{
- double result;
- double testDelta;
-
-
- result = tan( tests[i].value );
-
- /*
- * The test is valid when the difference between the
- * result and the expectation is less than DELTA
- */
- testDelta = fabs( result - tests[i].result );
- if( testDelta >= DELTA )
- {
- Fail( "tan(%g) returned %g"
- " when it should have returned %g",
- tests[i].value,
- result,
- tests[i].result );
- }
+ validate( tests[i].value, tests[i].expected, tests[i].variance);
+ validate(-tests[i].value, -tests[i].expected, tests[i].variance);
}
+
+ // -- SPECIAL CASE --
+ // Normally, tan(pi / 2) would return PAL_POSINF (atan2(PAL_POSINF) does return (pi / 2)).
+ // However, it seems instead (on all supported systems), we get a different number entirely.
+ validate( 1.5707963267948966, 16331239353195370.0, 0);
+ validate(-1.5707963267948966, -16331239353195370.0, 0);
+
+ validate_isnan(PAL_NEGINF);
+ validate_isnan(PAL_NAN);
+ validate_isnan(PAL_POSINF);
PAL_Terminate();
return PASS;
}
-
-
-
-
-
-
-
-
-
-
-
-
-
Description
= Passes to tan() a series of angle value, checking that
= each one return to correct value.
-
-
-
cmake_minimum_required(VERSION 2.8.12.2)
add_subdirectory(test1)
-
**
** Dependencies: PAL_Initialize
** PAL_Terminate
-** Fail
+** Fail
** fabs
-**
-
**
**===========================================================================*/
#include <palsuite.h>
-#define DELTA 0.0000001 /* Error acceptance level to the 7th decimal */
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
/**
* Helper test structure
*/
struct test
{
- double value; /* value to test the function with */
- double result; /* expected result */
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
};
/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+ double result = tanh(value);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("tanh(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result = tanh(value);
+
+ if (!_isnan(result))
+ {
+ Fail("tanh(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_NAN);
+ }
+}
+
+/**
* main
*
* executable entry point
*/
-INT __cdecl main(INT argc, CHAR **argv)
+int __cdecl main(int argc, char **argv)
{
- double pi = 3.1415926535;
- int i;
-
struct test tests[] =
{
- /* Value test result */
- { 0, 0 },
- { pi/2.0, 0.9171523 },
- { pi, 0.9962721 },
- { (3.0*pi) / 2.0, 0.9998386 },
- { 2.0 * pi, 0.9999930 },
- { 5.0*pi/2.0, 0.9999997 },
- { 3.0*pi, 1 },
- { (7.0*pi) / 2.0, 1 },
- { 4.0 * pi, 1 }
+ /* value expected variance */
+ { 0, 0, PAL_EPSILON },
+ { 0.31830988618379067, 0.30797791269089433, PAL_EPSILON }, // value: 1 / pi
+ { 0.43429448190325183, 0.40890401183401433, PAL_EPSILON }, // value: log10(e)
+ { 0.63661977236758134, 0.56259360033158334, PAL_EPSILON }, // value: 2 / pi
+ { 0.69314718055994531, 0.6, PAL_EPSILON }, // value: ln(2)
+ { 0.70710678118654752, 0.60885936501391381, PAL_EPSILON }, // value: 1 / sqrt(2)
+ { 0.78539816339744831, 0.65579420263267244, PAL_EPSILON }, // value: pi / 4
+ { 1, 0.76159415595576489, PAL_EPSILON },
+ { 1.1283791670955126, 0.81046380599898809, PAL_EPSILON }, // value: 2 / sqrt(pi)
+ { 1.4142135623730950, 0.88838556158566054, PAL_EPSILON }, // value: sqrt(2)
+ { 1.4426950408889634, 0.89423894585503855, PAL_EPSILON }, // value: log2(e)
+ { 1.5707963267948966, 0.91715233566727435, PAL_EPSILON }, // value: pi / 2
+ { 2.3025850929940457, 0.98019801980198020, PAL_EPSILON }, // value: ln(10)
+ { 2.7182818284590452, 0.99132891580059984, PAL_EPSILON }, // value: e
+ { 3.1415926535897932, 0.99627207622074994, PAL_EPSILON }, // value: pi
+ { PAL_POSINF, 1, PAL_EPSILON * 10 }
};
-
/* PAL initialization */
- if( PAL_Initialize(argc, argv) != 0 )
+ if (PAL_Initialize(argc, argv) != 0)
{
- return (FAIL);
+ return FAIL;
}
- for( i = 0; i < sizeof(tests) / sizeof(struct test); i++)
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
{
- double result;
- double testDelta;
-
-
- result = tanh( tests[i].value );
-
- /*
- * The test is valid when the difference between the
- * result and the expectation is less than DELTA
- */
- testDelta = fabs( result - tests[i].result );
- if( testDelta >= DELTA )
- {
- Fail( "tanh(%g) returned %g"
- " when it should have returned %g",
- tests[i].value,
- result,
- tests[i].result );
- }
+ validate( tests[i].value, tests[i].expected, tests[i].variance);
+ validate(-tests[i].value, -tests[i].expected, tests[i].variance);
}
+
+ validate_isnan(PAL_NAN);
PAL_Terminate();
return PASS;
}
-
-
-
-
-
-
-
-
-
-
-
-
-
Description
= Passes to tanh() a series of angle value, checking that
= each one return to correct value.
-
-
-
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
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
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
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
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
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
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
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)
#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"
--- /dev/null
+// 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}");
+ }
+ }
+ }
+
+}
--- /dev/null
+// 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}");
+ }
+ }
+ }
+}
--- /dev/null
+// 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}");
+ }
+ }
+ }
+}
--- /dev/null
+// 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}");
+ }
+ }
+ }
+}
--- /dev/null
+// 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}");
+ }
+ }
+ }
+}
--- /dev/null
+// 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}");
+ }
+ }
+ }
+}
--- /dev/null
+// 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}");
+ }
+ }
+ }
+}
--- /dev/null
+// 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}");
+ }
+ }
+ }
+}
--- /dev/null
+// 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}");
+ }
+ }
+ }
+}
--- /dev/null
+// 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}");
+ }
+ }
+ }
+}
--- /dev/null
+// 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}");
+ }
+ }
+ }
+}
--- /dev/null
+// 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}");
+ }
+ }
+ }
+
+}
--- /dev/null
+// 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}");
+ }
+ }
+ }
+}
--- /dev/null
+// 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}");
+ }
+ }
+ }
+}
--- /dev/null
+// 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}");
+ }
+ }
+ }
+}
--- /dev/null
+// 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}");
+ }
+ }
+ }
+}
--- /dev/null
+// 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}");
+ }
+ }
+ }
+}
--- /dev/null
+// 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}");
+ }
+ }
+ }
+}
--- /dev/null
+// 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}");
+ }
+ }
+ }
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using Microsoft.Xunit.Performance;
+
+[assembly: OptimizeForBenchmarks]
+[assembly: MeasureInstructionsRetired]
+
+namespace Functions
+{
+ public static class Program
+ {
+#if DEBUG
+ private const int defaultIterations = 1;
+#else
+ private const int defaultIterations = 1000;
+#endif
+
+ private static readonly IDictionary<string, Action> TestList = new Dictionary<string, Action>() {
+ ["absdouble"] = MathTests.AbsDoubleTest,
+ ["abssingle"] = MathTests.AbsSingleTest,
+ ["acosdouble"] = MathTests.AcosDoubleTest,
+ ["asindouble"] = MathTests.AsinDoubleTest,
+ ["atandouble"] = MathTests.AtanDoubleTest,
+ ["atan2double"] = MathTests.Atan2DoubleTest,
+ ["ceilingdouble"] = MathTests.CeilingDoubleTest,
+ ["cosdouble"] = MathTests.CosDoubleTest,
+ ["coshdouble"] = MathTests.CoshDoubleTest,
+ ["expdouble"] = MathTests.ExpDoubleTest,
+ ["floordouble"] = MathTests.FloorDoubleTest,
+ ["logdouble"] = MathTests.LogDoubleTest,
+ ["log10double"] = MathTests.Log10DoubleTest,
+ ["powdouble"] = MathTests.PowDoubleTest,
+ ["rounddouble"] = MathTests.RoundDoubleTest,
+ ["sindouble"] = MathTests.SinDoubleTest,
+ ["sinhdouble"] = MathTests.SinhDoubleTest,
+ ["sqrtdouble"] = MathTests.SqrtDoubleTest,
+ ["tandouble"] = MathTests.TanDoubleTest,
+ ["tanhdouble"] = MathTests.TanhDoubleTest
+ };
+
+ private static int Main(string[] args)
+ {
+ var isPassing = true; var iterations = defaultIterations;
+ ICollection<string> testsToRun = new HashSet<string>();
+
+ try
+ {
+ for (int index = 0; index < args.Length; index++)
+ {
+ if (args[index].ToLowerInvariant() == "-bench")
+ {
+ index++;
+
+ if ((index >= args.Length) || !int.TryParse(args[index], out iterations))
+ {
+ iterations = defaultIterations;
+ }
+ }
+ else if (args[index].ToLowerInvariant() == "all")
+ {
+ testsToRun = TestList.Keys;
+ break;
+ }
+ else
+ {
+ var testName = args[index].ToLowerInvariant();
+
+ if (!TestList.ContainsKey(testName))
+ {
+ PrintUsage();
+ break;
+ }
+
+ testsToRun.Add(testName);
+ }
+ }
+
+ if (testsToRun.Count == 0)
+ {
+ testsToRun = TestList.Keys;
+ }
+
+ foreach (var testToRun in testsToRun)
+ {
+ Console.WriteLine($"Running {testToRun} test...");
+ Test(iterations, TestList[testToRun]);
+ }
+ }
+ catch (Exception exception)
+ {
+ Console.WriteLine($" Error: {exception.Message}");
+ isPassing = false;
+ }
+
+ return isPassing ? 100 : -1;
+ }
+
+ private static void PrintUsage()
+ {
+ Console.WriteLine(@"Usage:
+Functions [name] [-bench #]
+
+ [name]: The name of the function to test. Defaults to 'all'.
+ all");
+
+ foreach (var testName in TestList.Keys)
+ {
+ Console.WriteLine($" {testName}");
+ }
+
+ Console.WriteLine($@"
+ [-bench #]: The number of iterations. Defaults to {defaultIterations}");
+ }
+
+ private static void Test(int iterations, Action action)
+ {
+ // ****************************************************************
+
+ Console.WriteLine(" Warming up...");
+
+ var startTimestamp = Stopwatch.GetTimestamp();
+
+ action();
+
+ var totalElapsedTime = (Stopwatch.GetTimestamp() - startTimestamp);
+ var totalElapsedTimeInSeconds = (totalElapsedTime / (double)(Stopwatch.Frequency));
+
+ Console.WriteLine($" Total Time: {totalElapsedTimeInSeconds}");
+
+ // ****************************************************************
+
+ Console.WriteLine($" Executing {iterations} iterations...");
+
+ totalElapsedTime = 0L;
+
+ for (var iteration = 0; iteration < iterations; iteration++)
+ {
+ startTimestamp = Stopwatch.GetTimestamp();
+
+ action();
+
+ totalElapsedTime += (Stopwatch.GetTimestamp() - startTimestamp);
+ }
+
+ totalElapsedTimeInSeconds = (totalElapsedTime / (double)(Stopwatch.Frequency));
+
+ Console.WriteLine($" Total Time: {totalElapsedTimeInSeconds} seconds");
+ Console.WriteLine($" Average Time: {totalElapsedTimeInSeconds / iterations} seconds");
+
+ // ****************************************************************
+ }
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{C949CB07-60B2-420A-B3CA-59847ED4700B}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <FileAlignment>512</FileAlignment>
+ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\11.0\UITestExtensionPackages</ReferencePath>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+ <NuGetPackageImportStamp>
+ </NuGetPackageImportStamp>
+ </PropertyGroup>
+ <!-- Default configurations to help VS understand the configurations -->
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ </PropertyGroup>
+ <ItemGroup>
+ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+ <Visible>False</Visible>
+ </CodeAnalysisDependentAssemblyPaths>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="$(JitPackagesConfigFileDirectory)benchmark\project.json" />
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Double\AbsDouble.cs" />
+ <Compile Include="Single\AbsSingle.cs" />
+ <Compile Include="Double\AcosDouble.cs" />
+ <Compile Include="Double\AsinDouble.cs" />
+ <Compile Include="Double\AtanDouble.cs" />
+ <Compile Include="Double\Atan2Double.cs" />
+ <Compile Include="Double\CeilingDouble.cs" />
+ <Compile Include="Double\CosDouble.cs" />
+ <Compile Include="Double\CoshDouble.cs" />
+ <Compile Include="Double\ExpDouble.cs" />
+ <Compile Include="Double\FloorDouble.cs" />
+ <Compile Include="Functions.cs" />
+ <Compile Include="Double\LogDouble.cs" />
+ <Compile Include="Double\Log10Double.cs" />
+ <Compile Include="MathTests.cs" />
+ <Compile Include="Double\PowDouble.cs" />
+ <Compile Include="Double\RoundDouble.cs" />
+ <Compile Include="Double\SinDouble.cs" />
+ <Compile Include="Double\SinhDouble.cs" />
+ <Compile Include="Double\SqrtDouble.cs" />
+ <Compile Include="Double\TanDouble.cs" />
+ <Compile Include="Double\TanhDouble.cs" />
+ </ItemGroup>
+ <PropertyGroup>
+ <ProjectJson>$(JitPackagesConfigFileDirectory)benchmark\project.json</ProjectJson>
+ <ProjectLockJson>$(JitPackagesConfigFileDirectory)benchmark\project.lock.json</ProjectLockJson>
+ </PropertyGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+ <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' ">
+ </PropertyGroup>
+</Project>
\ No newline at end of file
--- /dev/null
+// 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;
+ }
+}
--- /dev/null
+// 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}");
+ }
+ }
+ }
+}
<tags>SIMD,AVX</tags>
</benchmark>
</benchmark-suite>
+ <benchmark-suite>
+ <name>Math</name>
+ <benchmark>
+ <name>Functions-AbsDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>absdouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-AbsSingle</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>abssingle -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-AcosDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>acosdouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-AsinDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>asindouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-AtanDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>atandouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-Atan2Double</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>atan2double -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-CeilingDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>ceilingdouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-CosDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>cosdouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-CoshDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>coshdouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-ExpDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>expdouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-FloorDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>floordouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-LogDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>logdouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-Log10Double</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>log10double -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-PowDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>powdouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-RoundDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>rounddouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-SinDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>sindouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-SinhDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>sinhdouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-SqrtDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>sqrtdouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-TanDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>tandouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-TanhDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>tanhdouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ </benchmark-suite>
</benchmark-system>
<expected-results>100</expected-results>
</benchmark>
</benchmark-suite>
+ <benchmark-suite>
+ <name>Math</name>
+ <benchmark>
+ <name>Functions-AbsDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>absdouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-AbsSingle</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>abssingle -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-AcosDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>acosdouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-AsinDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>asindouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-AtanDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>atandouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-Atan2Double</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>atan2double -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-CeilingDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>ceilingdouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-CosDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>cosdouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-CoshDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>coshdouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-ExpDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>expdouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-FloorDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>floordouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-LogDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>logdouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-Log10Double</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>log10double -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-PowDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>powdouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-RoundDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>rounddouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-SinDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>sindouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-SinhDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>sinhdouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-SqrtDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>sqrtdouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-TanDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>tandouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ <benchmark>
+ <name>Functions-TanhDouble</name>
+ <directory>.\Math\Functions\Functions</directory>
+ <executable>Functions.exe</executable>
+ <args>tanhdouble -bench 1000000</args>
+ <expected-results>100</expected-results>
+ </benchmark>
+ </benchmark-suite>
</benchmark-system>