Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45631 Signed-off-by: Zebediah Figura z.figura12@gmail.com --- 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 | 30 +++++++ dlls/ucrtbase/ucrtbase.spec | 6 +- 7 files changed, 133 insertions(+), 12 deletions(-)
diff --git a/configure.ac b/configure.ac index 1db7af9177..907fac2f71 100644 --- a/configure.ac +++ b/configure.ac @@ -2746,6 +2746,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 0d645e5587..f5e4fb1f8f 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 c9547bcbdf..e2764dc46e 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 79b667e42b..eee3d5c876 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}, + {1.17549421e-38f, 0.0, 1.17549407e-38f, 1.1754942106924409e-38}, + {1.17549421e-38f, 1.17549421e-38f, 1.17549421e-38f, 1.1754942106924411e-38}, + {1.17549421e-38f, 1.0, 1.17549435e-38f, 1.1754942106924412e-38}, + {1.17549435e-38f, 0.0, 1.17549421e-38f, 1.1754943508222874e-38}, + {1.17549435e-38f, 1.17549435e-38f, 1.17549435e-38f, 1.1754943508222875e-38}, + {1.17549435e-38f, 1.0, 1.17549449e-38f, 1.1754943508222878e-38}, + {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 == -1, "Test %d: expected no error, got %d.\n", i, e); + else + ok(e == ERANGE, "Test %d: expected ERANGE, 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 errno -1, 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 errno ERANGE, 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 errno ERANGE, 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 c1f6e0bcf0..706799ce37 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 d4785d3508..07cf19dfee 100644 --- a/dlls/msvcrt/math.c +++ b/dlls/msvcrt/math.c @@ -1542,6 +1542,36 @@ double CDECL MSVCRT__nextafter(double num, double next) return retval; }
+/********************************************************************* + * nexttoward (MSVCRT.@) + */ +double CDECL MSVCRT_nexttoward(double num, double next) +{ +#if 1 + double ret = nexttoward(num, next); + if (!isnormal(ret) && !isnan(ret) && !isinf(num)) *MSVCRT__errno() = MSVCRT_ERANGE; + return ret; +#else + FIXME("not implemented\n"); + return 0; +#endif +} + +/********************************************************************* + * nexttoward (MSVCRT.@) + */ +float CDECL MSVCRT_nexttowardf(float num, double next) +{ +#if 1 + float ret = nexttowardf(num, next); + if (!isnormal(ret) && !isnan(ret) && !isinf(num)) *MSVCRT__errno() = MSVCRT_ERANGE; + return ret; +#else + FIXME("not implemented\n"); + return 0; +#endif +} + /********************************************************************* * _ecvt (MSVCRT.@) */ diff --git a/dlls/ucrtbase/ucrtbase.spec b/dlls/ucrtbase/ucrtbase.spec index 6e6cc439d8..3592a569e0 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