From 28e74af742f984d58d293e6bc6e4d09b5c3fa844 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sat, 23 Feb 2019 14:46:46 -0600 Subject: [PATCH] msvcr120: Add nexttoward implementation. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45631 Signed-off-by: Zebediah Figura Signed-off-by: Piotr Caban Signed-off-by: Alexandre Julliard --- configure | 2 + configure.ac | 2 + .../api-ms-win-crt-math-l1-1-0.spec | 6 +- dlls/msvcr120/msvcr120.spec | 6 +- dlls/msvcr120/tests/msvcr120.c | 89 +++++++++++++++++++ dlls/msvcr120_app/msvcr120_app.spec | 6 +- dlls/msvcrt/math.c | 38 ++++++++ dlls/ucrtbase/ucrtbase.spec | 6 +- include/config.h.in | 6 ++ 9 files changed, 149 insertions(+), 12 deletions(-) diff --git a/configure b/configure index fa50a3cf379..793e2ffc5ce 100755 --- a/configure +++ b/configure @@ -18717,6 +18717,8 @@ for ac_func in \ lroundf \ nearbyint \ nearbyintf \ + nexttoward \ + nexttowardf \ powl \ remainder \ remainderf \ diff --git a/configure.ac b/configure.ac index c6618374e4c..c978477a51c 100644 --- a/configure.ac +++ b/configure.ac @@ -2762,6 +2762,8 @@ AC_CHECK_FUNCS(\ lroundf \ nearbyint \ nearbyintf \ + nexttoward \ + nexttowardf \ powl \ remainder \ remainderf \ diff --git a/dlls/api-ms-win-crt-math-l1-1-0/api-ms-win-crt-math-l1-1-0.spec b/dlls/api-ms-win-crt-math-l1-1-0/api-ms-win-crt-math-l1-1-0.spec index 0d645e5587c..f5e4fb1f8f4 100644 --- a/dlls/api-ms-win-crt-math-l1-1-0/api-ms-win-crt-math-l1-1-0.spec +++ b/dlls/api-ms-win-crt-math-l1-1-0/api-ms-win-crt-math-l1-1-0.spec @@ -297,9 +297,9 @@ @ cdecl nextafter(double double) ucrtbase.nextafter @ cdecl nextafterf(float float) ucrtbase.nextafterf @ cdecl nextafterl(double double) ucrtbase.nextafterl -@ stub nexttoward -@ stub nexttowardf -@ stub nexttowardl +@ cdecl nexttoward(double double) ucrtbase.nexttoward +@ cdecl nexttowardf(float double) ucrtbase.nexttowardf +@ cdecl nexttowardl(double double) ucrtbase.nexttowardl @ stub norm @ stub normf @ stub norml diff --git a/dlls/msvcr120/msvcr120.spec b/dlls/msvcr120/msvcr120.spec index 769ee50790b..7dfcabf4611 100644 --- a/dlls/msvcr120/msvcr120.spec +++ b/dlls/msvcr120/msvcr120.spec @@ -2302,9 +2302,9 @@ @ cdecl nextafter(double double) MSVCRT__nextafter @ cdecl nextafterf(float float) MSVCRT__nextafterf @ cdecl nextafterl(double double) MSVCRT__nextafter -@ stub nexttoward -@ stub nexttowardf -@ stub nexttowardl +@ cdecl nexttoward(double double) MSVCRT_nexttoward +@ cdecl nexttowardf(float double) MSVCRT_nexttowardf +@ cdecl nexttowardl(double double) MSVCRT_nexttoward @ stub norm @ stub normf @ stub norml diff --git a/dlls/msvcr120/tests/msvcr120.c b/dlls/msvcr120/tests/msvcr120.c index 79b667e42b0..3077a18c1ef 100644 --- a/dlls/msvcr120/tests/msvcr120.c +++ b/dlls/msvcr120/tests/msvcr120.c @@ -127,6 +127,16 @@ static inline float __port_nan(void) } #define NAN __port_nan() +static inline int isnormal(double d) +{ + return _fpclass(d) & (_FPCLASS_PN | _FPCLASS_NN); +} + +static inline int isinf(double d) +{ + return _fpclass(d) & (_FPCLASS_PINF | _FPCLASS_NINF); +} + struct MSVCRT_lconv { char* decimal_point; @@ -192,6 +202,9 @@ static unsigned short (__cdecl *p_wctype)(const char*); static int (__cdecl *p_vsscanf)(const char*, const char *, __ms_va_list valist); static _Dcomplex* (__cdecl *p__Cbuild)(_Dcomplex*, double, double); static double (__cdecl *p_creal)(_Dcomplex); +static double (__cdecl *p_nexttoward)(double, double); +static float (__cdecl *p_nexttowardf)(float, double); +static double (__cdecl *p_nexttowardl)(double, double); /* make sure we use the correct errno */ #undef errno @@ -252,6 +265,9 @@ static BOOL init(void) SET(p_vsscanf, "vsscanf"); SET(p__Cbuild, "_Cbuild"); SET(p_creal, "creal"); + SET(p_nexttoward, "nexttoward"); + SET(p_nexttowardf, "nexttowardf"); + SET(p_nexttowardl, "nexttowardl"); if(sizeof(void*) == 8) { /* 64-bit initialization */ SET(p_critical_section_ctor, "??0critical_section@Concurrency@@QEAA@XZ"); @@ -964,6 +980,78 @@ static void test__Cbuild(void) ok(d == 3.0, "creal returned %lf\n", d); } +static void test_nexttoward(void) +{ + errno_t e; + double d; + float f; + int i; + + struct + { + double source; + double dir; + float f; + double d; + } + tests[] = + { + {0.0, 0.0, 0.0f, 0.0}, + {0.0, 1.0, 1.0e-45f, 5.0e-324}, + {0.0, -1.0, -1.0e-45f, -5.0e-324}, + {2.2250738585072009e-308, 0.0, 0.0f, 2.2250738585072004e-308}, + {2.2250738585072009e-308, 2.2250738585072010e-308, 1.0e-45f, 2.2250738585072009e-308}, + {2.2250738585072009e-308, 1.0, 1.0e-45f, 2.2250738585072014e-308}, + {2.2250738585072014e-308, 0.0, 0.0f, 2.2250738585072009e-308}, + {2.2250738585072014e-308, 2.2250738585072014e-308, 1.0e-45f, 2.2250738585072014e-308}, + {2.2250738585072014e-308, 1.0, 1.0e-45f, 2.2250738585072019e-308}, + {1.0, 2.0, 1.00000012f, 1.0000000000000002}, + {1.0, 0.0, 0.99999994f, 0.9999999999999999}, + {1.0, 1.0, 1.0f, 1.0}, + {0.0, INFINITY, 1.0e-45f, 5.0e-324}, + {FLT_MAX, INFINITY, INFINITY, 3.402823466385289e+038}, + {DBL_MAX, INFINITY, INFINITY, INFINITY}, + {INFINITY, INFINITY, INFINITY, INFINITY}, + {INFINITY, 0, FLT_MAX, DBL_MAX}, + }; + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + f = p_nexttowardf(tests[i].source, tests[i].dir); + ok(f == tests[i].f, "Test %d: expected %0.8ef, got %0.8ef.\n", i, tests[i].f, f); + + errno = -1; + d = p_nexttoward(tests[i].source, tests[i].dir); + e = errno; + ok(d == tests[i].d, "Test %d: expected %0.16e, got %0.16e.\n", i, tests[i].d, d); + if (!isnormal(d) && !isinf(tests[i].source)) + ok(e == ERANGE, "Test %d: expected ERANGE, got %d.\n", i, e); + else + ok(e == -1, "Test %d: expected no error, got %d.\n", i, e); + + d = p_nexttowardl(tests[i].source, tests[i].dir); + ok(d == tests[i].d, "Test %d: expected %0.16e, got %0.16e.\n", i, tests[i].d, d); + } + + errno = -1; + d = p_nexttoward(NAN, 0); + e = errno; + ok(_isnan(d), "Expected NAN, got %0.16e.\n", d); + ok(e == -1, "Expected no error, got %d.\n", e); + + errno = -1; + d = p_nexttoward(NAN, NAN); + e = errno; + ok(_isnan(d), "Expected NAN, got %0.16e.\n", d); + ok(e == -1, "Expected no error, got %d.\n", e); + + errno = -1; + d = p_nexttoward(0, NAN); + e = errno; + ok(_isnan(d), "Expected NAN, got %0.16e.\n", d); + ok(e == -1, "Expected no error, got %d.\n", e); +} + START_TEST(msvcr120) { if (!init()) return; @@ -983,4 +1071,5 @@ START_TEST(msvcr120) test_wctype(); test_vsscanf(); test__Cbuild(); + test_nexttoward(); } diff --git a/dlls/msvcr120_app/msvcr120_app.spec b/dlls/msvcr120_app/msvcr120_app.spec index e3323dd83ad..d78d26f81b8 100644 --- a/dlls/msvcr120_app/msvcr120_app.spec +++ b/dlls/msvcr120_app/msvcr120_app.spec @@ -1965,9 +1965,9 @@ @ cdecl nextafter(double double) msvcr120.nextafter @ cdecl nextafterf(float float) msvcr120.nextafterf @ cdecl nextafterl(double double) msvcr120.nextafterl -@ stub nexttoward -@ stub nexttowardf -@ stub nexttowardl +@ cdecl nexttoward(double double) msvcr120.nexttoward +@ cdecl nexttowardf(float double) msvcr120.nexttowardf +@ cdecl nexttowardl(double double) msvcr120.nexttowardl @ stub norm @ stub normf @ stub norml diff --git a/dlls/msvcrt/math.c b/dlls/msvcrt/math.c index d4785d35085..dc12cb1185a 100644 --- a/dlls/msvcrt/math.c +++ b/dlls/msvcrt/math.c @@ -1529,6 +1529,44 @@ float CDECL MSVCRT_nearbyintf(float num) #endif } +/********************************************************************* + * nexttoward (MSVCR120.@) + */ +double CDECL MSVCRT_nexttoward(double num, double next) +{ +#ifdef HAVE_NEXTTOWARD + double ret = nexttoward(num, next); + if (!(MSVCRT__fpclass(ret) & (MSVCRT__FPCLASS_PN | MSVCRT__FPCLASS_NN + | MSVCRT__FPCLASS_SNAN | MSVCRT__FPCLASS_QNAN)) && !isinf(num)) + { + *MSVCRT__errno() = MSVCRT_ERANGE; + } + return ret; +#else + FIXME("not implemented\n"); + return 0; +#endif +} + +/********************************************************************* + * nexttowardf (MSVCR120.@) + */ +float CDECL MSVCRT_nexttowardf(float num, double next) +{ +#ifdef HAVE_NEXTTOWARDF + float ret = nexttowardf(num, next); + if (!(MSVCRT__fpclass(ret) & (MSVCRT__FPCLASS_PN | MSVCRT__FPCLASS_NN + | MSVCRT__FPCLASS_SNAN | MSVCRT__FPCLASS_QNAN)) && !isinf(num)) + { + *MSVCRT__errno() = MSVCRT_ERANGE; + } + return ret; +#else + FIXME("not implemented\n"); + return 0; +#endif +} + #endif /* _MSVCR_VER>=120 */ /********************************************************************* diff --git a/dlls/ucrtbase/ucrtbase.spec b/dlls/ucrtbase/ucrtbase.spec index eb08843d160..00c806483ed 100644 --- a/dlls/ucrtbase/ucrtbase.spec +++ b/dlls/ucrtbase/ucrtbase.spec @@ -2438,9 +2438,9 @@ @ cdecl nextafter(double double) MSVCRT__nextafter @ cdecl nextafterf(float float) MSVCRT__nextafterf @ cdecl nextafterl(double double) MSVCRT__nextafter -@ stub nexttoward -@ stub nexttowardf -@ stub nexttowardl +@ cdecl nexttoward(double double) MSVCRT_nexttoward +@ cdecl nexttowardf(float double) MSVCRT_nexttowardf +@ cdecl nexttowardl(double double) MSVCRT_nexttoward @ stub norm @ stub normf @ stub norml diff --git a/include/config.h.in b/include/config.h.in index 0c99a8ce505..149e8b175ad 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -696,6 +696,12 @@ /* Define to 1 if you have the header file. */ #undef HAVE_NET_ROUTE_H +/* Define to 1 if you have the `nexttoward' function. */ +#undef HAVE_NEXTTOWARD + +/* Define to 1 if you have the `nexttowardf' function. */ +#undef HAVE_NEXTTOWARDF + /* Define to 1 if `_msg_ptr' is a member of `ns_msg'. */ #undef HAVE_NS_MSG__MSG_PTR