diff --git a/ChangeLog b/ChangeLog index 29d0a9a487..067337a44b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +2012-10-30 Joseph Myers + + [BZ #14047] + * sysdeps/generic/tininess.h: New file. + * sysdeps/i386/tininess.h: Likewise. + * sysdeps/sh/tininess.h: Likewise. + * sysdeps/x86_64/tininess.h: Likewise. + * stdlib/tst-strtod-underflow.c: Likewise. + * stdlib/tst-tininess.c: Likewise. + * stdlib/strtod_l.c: Include . + (round_and_return): Do not set errno for exact underflow cases. + Force an underflow exception when setting errno for underflow. + Determine underflow based on rounding to normal precision if + TININESS_AFTER_ROUNDING. + * stdlib/tst-strtod.c (tests): Do not expect errno to be set to + ERANGE for exact underflow cases. + * stdlib/Makefile (tests): Add tst-tininess and + tst-strtod-underflow. + ($(objpfx)tst-tininess): Use $(link-libm). + ($(objpfx)tst-strtod-underflow): Likewise. + 2012-10-30 Andreas Jaeger [BZ#14767] diff --git a/NEWS b/NEWS index d548217462..e4e672680a 100644 --- a/NEWS +++ b/NEWS @@ -11,13 +11,13 @@ Version 2.17 1349, 3479, 5044, 5298, 5400, 6530, 6778, 6808, 9685, 9914, 10014, 10038, 10631, 11438, 11607, 12140, 13412, 13542, 13601, 13629, 13679, 13696, - 13717, 13741, 13939, 13966, 14042, 14090, 14150, 14151, 14154, 14157, - 14166, 14173, 14195, 14237, 14251, 14252, 14283, 14298, 14303, 14307, - 14328, 14331, 14336, 14337, 14347, 14349, 14376, 14417, 14459, 14476, - 14477, 14505, 14510, 14516, 14518, 14519, 14530, 14532, 14538, 14543, - 14544, 14545, 14557, 14562, 14568, 14576, 14579, 14583, 14587, 14602, - 14621, 14638, 14645, 14648, 14652, 14660, 14661, 14683, 14694, 14716, - 14743, 14767. + 13717, 13741, 13939, 13966, 14042, 14047, 14090, 14150, 14151, 14154, + 14157, 14166, 14173, 14195, 14237, 14251, 14252, 14283, 14298, 14303, + 14307, 14328, 14331, 14336, 14337, 14347, 14349, 14376, 14417, 14459, + 14476, 14477, 14505, 14510, 14516, 14518, 14519, 14530, 14532, 14538, + 14543, 14544, 14545, 14557, 14562, 14568, 14576, 14579, 14583, 14587, + 14602, 14621, 14638, 14645, 14648, 14652, 14660, 14661, 14683, 14694, + 14716, 14743, 14767. * Support for STT_GNU_IFUNC symbols added for s390 and s390x. Optimized versions of memcpy, memset, and memcmp added for System z10 and diff --git a/ports/ChangeLog.alpha b/ports/ChangeLog.alpha index 8ddde9f25f..eff592b0cb 100644 --- a/ports/ChangeLog.alpha +++ b/ports/ChangeLog.alpha @@ -1,3 +1,8 @@ +2012-10-30 Joseph Myers + + [BZ #14047] + * sysdeps/alpha/tininess.h: New file. + 2012-10-19 Roland McGrath * sysdeps/unix/sysv/linux/alpha/nptl/libc.abilist diff --git a/ports/ChangeLog.am33 b/ports/ChangeLog.am33 index e8243c5326..d732d2c2b8 100644 --- a/ports/ChangeLog.am33 +++ b/ports/ChangeLog.am33 @@ -1,3 +1,8 @@ +2012-10-30 Joseph Myers + + [BZ #14047] + * sysdeps/am33/tininess.h: New file. + 2012-10-09 Roland McGrath * sysdeps/unix/sysv/linux/am33/configure: Regenerated. diff --git a/ports/ChangeLog.hppa b/ports/ChangeLog.hppa index 41b594c6e5..6c828ddbfc 100644 --- a/ports/ChangeLog.hppa +++ b/ports/ChangeLog.hppa @@ -1,3 +1,8 @@ +2012-10-30 Joseph Myers + + [BZ #14047] + * sysdeps/hppa/tininess.h: New file. + 2012-10-29 Carlos O'Donell * sysdeps/unix/sysv/linux/hppa/sysdep.h (ENTRY): Add cfi_startproc. diff --git a/ports/ChangeLog.ia64 b/ports/ChangeLog.ia64 index 47f51c1ae1..1531304ad6 100644 --- a/ports/ChangeLog.ia64 +++ b/ports/ChangeLog.ia64 @@ -1,3 +1,8 @@ +2012-10-30 Joseph Myers + + [BZ #14047] + * sysdeps/ia64/tininess.h: New file. + 2012-10-25 Andreas Jaeger * sysdeps/unix/sysv/linux/ia64/bits/fcntl.h: Remove all diff --git a/ports/ChangeLog.mips b/ports/ChangeLog.mips index 76f2703881..507deb6fef 100644 --- a/ports/ChangeLog.mips +++ b/ports/ChangeLog.mips @@ -1,3 +1,8 @@ +2012-10-30 Joseph Myers + + [BZ #14047] + * sysdeps/mips/tininess.h: New file. + 2012-10-29 Steve Ellcey * sysdeps/unix/sysv/linux/mips/mips32/Makefile: Remove. diff --git a/ports/sysdeps/alpha/tininess.h b/ports/sysdeps/alpha/tininess.h new file mode 100644 index 0000000000..1db37790f8 --- /dev/null +++ b/ports/sysdeps/alpha/tininess.h @@ -0,0 +1 @@ +#define TININESS_AFTER_ROUNDING 1 diff --git a/ports/sysdeps/am33/tininess.h b/ports/sysdeps/am33/tininess.h new file mode 100644 index 0000000000..1db37790f8 --- /dev/null +++ b/ports/sysdeps/am33/tininess.h @@ -0,0 +1 @@ +#define TININESS_AFTER_ROUNDING 1 diff --git a/ports/sysdeps/hppa/tininess.h b/ports/sysdeps/hppa/tininess.h new file mode 100644 index 0000000000..1db37790f8 --- /dev/null +++ b/ports/sysdeps/hppa/tininess.h @@ -0,0 +1 @@ +#define TININESS_AFTER_ROUNDING 1 diff --git a/ports/sysdeps/ia64/tininess.h b/ports/sysdeps/ia64/tininess.h new file mode 100644 index 0000000000..1db37790f8 --- /dev/null +++ b/ports/sysdeps/ia64/tininess.h @@ -0,0 +1 @@ +#define TININESS_AFTER_ROUNDING 1 diff --git a/ports/sysdeps/mips/tininess.h b/ports/sysdeps/mips/tininess.h new file mode 100644 index 0000000000..1db37790f8 --- /dev/null +++ b/ports/sysdeps/mips/tininess.h @@ -0,0 +1 @@ +#define TININESS_AFTER_ROUNDING 1 diff --git a/stdlib/Makefile b/stdlib/Makefile index 682a70c998..57830a8cb9 100644 --- a/stdlib/Makefile +++ b/stdlib/Makefile @@ -69,7 +69,8 @@ tests := tst-strtol tst-strtod testmb testrand testsort testdiv \ tst-makecontext tst-strtod4 tst-strtod5 tst-qsort2 \ tst-makecontext2 tst-strtod6 tst-unsetenv1 \ tst-makecontext3 bug-getcontext bug-fmtmsg1 \ - tst-secure-getenv tst-strtod-overflow tst-strtod-round + tst-secure-getenv tst-strtod-overflow tst-strtod-round \ + tst-tininess tst-strtod-underflow tests-static := tst-secure-getenv include ../Makeconfig @@ -151,3 +152,5 @@ link-libm = $(common-objpfx)math/libm.a endif $(objpfx)bug-getcontext: $(link-libm) $(objpfx)tst-strtod-round: $(link-libm) +$(objpfx)tst-tininess: $(link-libm) +$(objpfx)tst-strtod-underflow: $(link-libm) diff --git a/stdlib/strtod_l.c b/stdlib/strtod_l.c index 95f13e40a2..fdce35742a 100644 --- a/stdlib/strtod_l.c +++ b/stdlib/strtod_l.c @@ -62,6 +62,7 @@ extern unsigned long long int ____strtoull_l_internal (const char *, char **, #include #include #include +#include /* The gmp headers need some configuration frobs. */ #define HAVE_ALLOCA 1 @@ -209,12 +210,15 @@ static FLOAT round_and_return (mp_limb_t *retval, intmax_t exponent, int negative, mp_limb_t round_limb, mp_size_t round_bit, int more_bits) { + int mode = get_rounding_mode (); + if (exponent < MIN_EXP - 1) { if (exponent < MIN_EXP - 1 - MANT_DIG) return underflow_value (negative); mp_size_t shift = MIN_EXP - 1 - exponent; + bool is_tiny = true; more_bits |= (round_limb & ((((mp_limb_t) 1) << round_bit) - 1)) != 0; if (shift == MANT_DIG) @@ -248,6 +252,33 @@ round_and_return (mp_limb_t *retval, intmax_t exponent, int negative, } else if (shift > 0) { + if (TININESS_AFTER_ROUNDING && shift == 1) + { + /* Whether the result counts as tiny depends on whether, + after rounding to the normal precision, it still has + a subnormal exponent. */ + mp_limb_t retval_normal[RETURN_LIMB_SIZE]; + if (round_away (negative, + (retval[0] & 1) != 0, + (round_limb + & (((mp_limb_t) 1) << round_bit)) != 0, + (more_bits + || ((round_limb + & ((((mp_limb_t) 1) << round_bit) - 1)) + != 0)), + mode)) + { + mp_limb_t cy = __mpn_add_1 (retval_normal, retval, + RETURN_LIMB_SIZE, 1); + + if (((MANT_DIG % BITS_PER_MP_LIMB) == 0 && cy) || + ((MANT_DIG % BITS_PER_MP_LIMB) != 0 && + ((retval_normal[RETURN_LIMB_SIZE - 1] + & (((mp_limb_t) 1) << (MANT_DIG % BITS_PER_MP_LIMB))) + != 0))) + is_tiny = false; + } + } round_limb = retval[0]; round_bit = shift - 1; (void) __mpn_rshift (retval, retval, RETURN_LIMB_SIZE, shift); @@ -259,14 +290,20 @@ round_and_return (mp_limb_t *retval, intmax_t exponent, int negative, # define DENORM_EXP (MIN_EXP - 2) #endif exponent = DENORM_EXP; - __set_errno (ERANGE); + if (is_tiny + && ((round_limb & (((mp_limb_t) 1) << round_bit)) != 0 + || more_bits + || (round_limb & ((((mp_limb_t) 1) << round_bit) - 1)) != 0)) + { + __set_errno (ERANGE); + volatile FLOAT force_underflow_exception = MIN_VALUE * MIN_VALUE; + (void) force_underflow_exception; + } } if (exponent > MAX_EXP) goto overflow; - int mode = get_rounding_mode (); - if (round_away (negative, (retval[0] & 1) != 0, (round_limb & (((mp_limb_t) 1) << round_bit)) != 0, diff --git a/stdlib/tst-strtod-underflow.c b/stdlib/tst-strtod-underflow.c new file mode 100644 index 0000000000..892ef158ac --- /dev/null +++ b/stdlib/tst-strtod-underflow.c @@ -0,0 +1,225 @@ +/* Test for strtod handling of arguments that may cause floating-point + underflow. + Copyright (C) 2012 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include + +enum underflow_case + { + /* Result is exact or outside the subnormal range. */ + UNDERFLOW_NONE, + /* Result has magnitude at most half way between the largest + subnormal value and the smallest positive normal value, and is + not exact, so underflows in all rounding modes and independent + of how tininess is detected. */ + UNDERFLOW_ALWAYS, + /* Result is positive, with magnitude larger than half way between + the largest subnormal value and the least positive normal + value, but would underflow when rounded to nearest to normal + precision, so underflows after rounding in all modes except + rounding upward. */ + UNDERFLOW_EXCEPT_UPWARD, + /* Likewise, for a negative result, underflowing after rounding + except when rounding downward. */ + UNDERFLOW_EXCEPT_DOWNWARD, + /* Result is positive, with magnitude at least three quarters of + the way from the largest subnormal value to the smallest + positive normal value, so underflows after rounding only when + rounding downward or toward zero. */ + UNDERFLOW_ONLY_DOWNWARD_ZERO, + /* Likewise, for a negative result, underflowing after rounding + only when rounding upward or toward zero. */ + UNDERFLOW_ONLY_UPWARD_ZERO, + }; + +struct test +{ + const char *s; + enum underflow_case c; +}; + +static const struct test tests[] = + { + { "0x1p-1022", UNDERFLOW_NONE }, + { "-0x1p-1022", UNDERFLOW_NONE }, + { "0x0p-10000000000000000000000000", UNDERFLOW_NONE }, + { "-0x0p-10000000000000000000000000", UNDERFLOW_NONE }, + { "0x1p-10000000000000000000000000", UNDERFLOW_ALWAYS }, + { "-0x1p-10000000000000000000000000", UNDERFLOW_ALWAYS }, + { "0x1.000000000000000000001p-1022", UNDERFLOW_NONE }, + { "-0x1.000000000000000000001p-1022", UNDERFLOW_NONE }, + { "0x1p-1075", UNDERFLOW_ALWAYS }, + { "-0x1p-1075", UNDERFLOW_ALWAYS }, + { "0x1p-1023", UNDERFLOW_NONE }, + { "-0x1p-1023", UNDERFLOW_NONE }, + { "0x1p-1074", UNDERFLOW_NONE }, + { "-0x1p-1074", UNDERFLOW_NONE }, + { "0x1.ffffffffffffep-1023", UNDERFLOW_NONE }, + { "-0x1.ffffffffffffep-1023", UNDERFLOW_NONE }, + { "0x1.fffffffffffffp-1023", UNDERFLOW_ALWAYS }, + { "-0x1.fffffffffffffp-1023", UNDERFLOW_ALWAYS }, + { "0x1.fffffffffffff0001p-1023", UNDERFLOW_EXCEPT_UPWARD }, + { "-0x1.fffffffffffff0001p-1023", UNDERFLOW_EXCEPT_DOWNWARD }, + { "0x1.fffffffffffff7fffp-1023", UNDERFLOW_EXCEPT_UPWARD }, + { "-0x1.fffffffffffff7fffp-1023", UNDERFLOW_EXCEPT_DOWNWARD }, + { "0x1.fffffffffffff8p-1023", UNDERFLOW_ONLY_DOWNWARD_ZERO }, + { "-0x1.fffffffffffff8p-1023", UNDERFLOW_ONLY_UPWARD_ZERO }, + { "0x1.fffffffffffffffffp-1023", UNDERFLOW_ONLY_DOWNWARD_ZERO }, + { "-0x1.fffffffffffffffffp-1023", UNDERFLOW_ONLY_UPWARD_ZERO }, + }; + +/* Return whether to expect underflow from a particular testcase, in a + given rounding mode. */ + +static bool +expect_underflow (enum underflow_case c, int rm) +{ + if (c == UNDERFLOW_NONE) + return false; + if (c == UNDERFLOW_ALWAYS) + return true; + if (TININESS_AFTER_ROUNDING) + { + switch (rm) + { +#ifdef FE_DOWNWARD + case FE_DOWNWARD: + return (c == UNDERFLOW_EXCEPT_UPWARD + || c == UNDERFLOW_ONLY_DOWNWARD_ZERO); +#endif + +#ifdef FE_TOWARDZERO + case FE_TOWARDZERO: + return true; +#endif + +#ifdef FE_UPWARD + case FE_UPWARD: + return (c == UNDERFLOW_EXCEPT_DOWNWARD + || c == UNDERFLOW_ONLY_UPWARD_ZERO); +#endif + + default: + return (c == UNDERFLOW_EXCEPT_UPWARD + || c == UNDERFLOW_EXCEPT_DOWNWARD); + } + } + else + return true; +} + +static bool support_underflow_exception = false; +volatile double d = DBL_MIN; +volatile double dd; + +static int +test_in_one_mode (const char *s, enum underflow_case c, int rm, + const char *mode_name) +{ + int result = 0; + feclearexcept (FE_ALL_EXCEPT); + errno = 0; + double d = strtod (s, NULL); + int got_errno = errno; +#ifdef FE_UNDERFLOW + bool got_fe_underflow = fetestexcept (FE_UNDERFLOW) != 0; +#else + bool got_fe_underflow = false; +#endif + printf ("strtod (%s) (%s) returned %a, errno = %d, %sunderflow exception\n", + s, mode_name, d, got_errno, got_fe_underflow ? "" : "no "); + bool this_expect_underflow = expect_underflow (c, rm); + if (got_errno != 0 && got_errno != ERANGE) + { + puts ("FAIL: errno neither 0 nor ERANGE"); + result = 1; + } + else if (this_expect_underflow != (errno == ERANGE)) + { + puts ("FAIL: underflow from errno differs from expectations"); + result = 1; + } + if (support_underflow_exception && got_fe_underflow != this_expect_underflow) + { + puts ("FAIL: underflow from exceptions differs from expectations"); + result = 1; + } + return result; +} + +static int +do_test (void) +{ + int save_round_mode = fegetround (); + int result = 0; +#ifdef FE_TONEAREST + const int fe_tonearest = FE_TONEAREST; +#else + const int fe_tonearest = 0; +# if defined FE_DOWNWARD || defined FE_TOWARDZERO || defined FE_UPWARD +# error "FE_TONEAREST not defined, but another rounding mode is" +# endif +#endif +#ifdef FE_UNDERFLOW + feclearexcept (FE_ALL_EXCEPT); + dd = d * d; + if (fetestexcept (FE_UNDERFLOW)) + support_underflow_exception = true; + else + puts ("underflow exception not supported at runtime, only testing errno"); +#endif + for (size_t i = 0; i < sizeof (tests) / sizeof (tests[0]); i++) + { + result |= test_in_one_mode (tests[i].s, tests[i].c, fe_tonearest, + "default rounding mode"); +#ifdef FE_DOWNWARD + if (!fesetround (FE_DOWNWARD)) + { + result |= test_in_one_mode (tests[i].s, tests[i].c, FE_DOWNWARD, + "FE_DOWNWARD"); + fesetround (save_round_mode); + } +#endif +#ifdef FE_TOWARDZERO + if (!fesetround (FE_TOWARDZERO)) + { + result |= test_in_one_mode (tests[i].s, tests[i].c, FE_TOWARDZERO, + "FE_TOWARDZERO"); + fesetround (save_round_mode); + } +#endif +#ifdef FE_UPWARD + if (!fesetround (FE_UPWARD)) + { + result |= test_in_one_mode (tests[i].s, tests[i].c, FE_UPWARD, + "FE_UPWARD"); + fesetround (save_round_mode); + } +#endif + } + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/stdlib/tst-strtod.c b/stdlib/tst-strtod.c index 738e73ebba..670beb1e4d 100644 --- a/stdlib/tst-strtod.c +++ b/stdlib/tst-strtod.c @@ -60,10 +60,10 @@ static const struct ltest tests[] = { "0x00.0014p19", 160.0, '\0', 0 }, { "0x1p-1023", 1.11253692925360069154511635866620203210960799023116591527666e-308, - '\0', ERANGE }, + '\0', 0 }, { "0x0.8p-1022", 1.11253692925360069154511635866620203210960799023116591527666e-308, - '\0', ERANGE }, + '\0', 0 }, { "Inf", HUGE_VAL, '\0', 0 }, { "-Inf", -HUGE_VAL, '\0', 0 }, { "+InFiNiTy", HUGE_VAL, '\0', 0 }, diff --git a/stdlib/tst-tininess.c b/stdlib/tst-tininess.c new file mode 100644 index 0000000000..9312f16eec --- /dev/null +++ b/stdlib/tst-tininess.c @@ -0,0 +1,69 @@ +/* Test that tininess.h is correct for this architecture. + Copyright (C) 2012 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include + +volatile float a = 0x1.fffp-126; +volatile float b = 0x1.0008p-1; +volatile float c; +volatile float m = FLT_MIN; +volatile float mm; + +static int +do_test (void) +{ + int result = 0; +#ifdef FE_UNDERFLOW + feclearexcept (FE_ALL_EXCEPT); + mm = m * m; + if (!fetestexcept (FE_UNDERFLOW)) + { + puts ("underflow exception not supported at runtime, cannot test"); + return 0; + } + feclearexcept (FE_ALL_EXCEPT); + c = a * b; + if (fetestexcept (FE_UNDERFLOW)) + { + if (TININESS_AFTER_ROUNDING) + { + puts ("tininess.h says after rounding, " + "but detected before rounding"); + result = 1; + } + } + else + { + if (!TININESS_AFTER_ROUNDING) + { + puts ("tininess.h says before rounding, " + "but detected after rounding"); + result = 1; + } + } +#else + puts ("underflow exception not supported at compile time, cannot test"); +#endif + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/sysdeps/generic/tininess.h b/sysdeps/generic/tininess.h new file mode 100644 index 0000000000..fd01739950 --- /dev/null +++ b/sysdeps/generic/tininess.h @@ -0,0 +1,33 @@ +/* Specify architecture-specific rules for determining tininess of + floating-point results. Generic version. + Copyright (C) 2012 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef _TININESS_H +#define _TININESS_H 1 + +/* Under IEEE 754, an architecture may determine tininess of + floating-point results either "before rounding" or "after + rounding", but must do so in the same way for all operations + returning binary results. Define TININESS_AFTER_ROUNDING to 1 for + "after rounding" architectures, 0 for "before rounding" + architectures. The test stdlib/tst-tininess will fail if the + definition is incorrect. */ + +#define TININESS_AFTER_ROUNDING 0 + +#endif /* tininess.h */ diff --git a/sysdeps/i386/tininess.h b/sysdeps/i386/tininess.h new file mode 100644 index 0000000000..1db37790f8 --- /dev/null +++ b/sysdeps/i386/tininess.h @@ -0,0 +1 @@ +#define TININESS_AFTER_ROUNDING 1 diff --git a/sysdeps/sh/tininess.h b/sysdeps/sh/tininess.h new file mode 100644 index 0000000000..1db37790f8 --- /dev/null +++ b/sysdeps/sh/tininess.h @@ -0,0 +1 @@ +#define TININESS_AFTER_ROUNDING 1 diff --git a/sysdeps/x86_64/tininess.h b/sysdeps/x86_64/tininess.h new file mode 100644 index 0000000000..1db37790f8 --- /dev/null +++ b/sysdeps/x86_64/tininess.h @@ -0,0 +1 @@ +#define TININESS_AFTER_ROUNDING 1