From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2155) id 11E253887F58; Thu, 27 Jul 2023 09:38:54 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 11E253887F58 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1690450734; bh=X7gS3x1Lr0gp2Cx7Z7n68X5YsVB3vUy1oBXyxnokt2U=; h=From:To:Subject:Date:From; b=vB10bnzJedKzGJubW/nTRj2d8T7FEiaq6x4VUaQ1D0zS8kZNnrtUulo23LUkW+eAK zlYjUvmSHV93hhw6iAzooYtf7sU04IdS7HmwLHu/F1B+6Z16qEiQfxWQAJtYbrCpag 60BBBwZM3kzmKbi20XbXzPfszPcCMLWrcEMvUg7Q= Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Corinna Vinschen To: newlib-cvs@sourceware.org Subject: [newlib-cygwin/main] Fix rounding results in lrint() & llrint() when close to 0 X-Act-Checkin: newlib-cygwin X-Git-Author: Jesse Huang via Newlib X-Git-Refname: refs/heads/main X-Git-Oldrev: 4fbcc8c5fe7d655de4bf04f2f123e77506011030 X-Git-Newrev: 9e329b544ac04b389e12984362e06b92e1506399 Message-Id: <20230727093854.11E253887F58@sourceware.org> Date: Thu, 27 Jul 2023 09:38:54 +0000 (GMT) List-Id: https://sourceware.org/git/gitweb.cgi?p=3Dnewlib-cygwin.git;h=3D9e329b544ac= 04b389e12984362e06b92e1506399 commit 9e329b544ac04b389e12984362e06b92e1506399 Author: Jesse Huang via Newlib AuthorDate: Thu Jul 27 01:49:41 2023 -0700 Commit: Corinna Vinschen CommitDate: Thu Jul 27 11:14:12 2023 +0200 Fix rounding results in lrint() & llrint() when close to 0 =20 soft-fp should round floating pointer numbers according to the current rounding mode. However, in the current code of lrint() and llrint(), there are if statements before the actual rounding computation =20 if(j0 < -1) return 0; =20 Where j0 is the exponent of the floating point number. =20 It means any number having a exponent less than -1 (i.e. interval (-0.5, 0.5)) will be rounded to 0 regardeless of the rounding mode. =20 The bug already fixed in glibc in 2006 by moving the check afterwards the rounding computation, but still persists in newlib. =20 This patch fixed it in a similar way to glibc Ref Commit in glibc: 6624dbc07b5a9fb316ed188ef01f65b8eea8b47c Diff: --- newlib/libm/common/s_llrint.c | 31 +++++++++++-------------------- newlib/libm/common/s_lrint.c | 31 +++++++++++-------------------- newlib/libm/common/sf_llrint.c | 6 ++---- newlib/libm/common/sf_lrint.c | 6 ++---- 4 files changed, 26 insertions(+), 48 deletions(-) diff --git a/newlib/libm/common/s_llrint.c b/newlib/libm/common/s_llrint.c index 72452dbe9342..f2c48766e47c 100644 --- a/newlib/libm/common/s_llrint.c +++ b/newlib/libm/common/s_llrint.c @@ -66,26 +66,17 @@ long long int if(j0 < 20) { /* j0 in [-1023,19] */ - if(j0 < -1) - return 0; - else - { - /* j0 in [0,19] */ - /* shift amt in [0,19] */ - w =3D TWO52[sx] + x; - t =3D w - TWO52[sx]; - GET_HIGH_WORD(i0, t); - /* Detect the all-zeros representation of plus and - minus zero, which fails the calculation below. */ - if ((i0 & ~((__int32_t)1 << 31)) =3D=3D 0) - return 0; - /* After round: j0 in [0,20] */ - j0 =3D ((i0 & 0x7ff00000) >> 20) - 1023; - i0 &=3D 0x000fffff; - i0 |=3D 0x00100000; - /* shift amt in [20,0] */ - result =3D i0 >> (20 - j0); - } + w =3D TWO52[sx] + x; + t =3D w - TWO52[sx]; + GET_HIGH_WORD(i0, t); + /* Detect the all-zeros representation of plus and + minus zero, which fails the calculation below. */ + if ((i0 & ~((__int32_t)1 << 31)) =3D=3D 0) + return 0; + j0 =3D ((i0 & 0x7ff00000) >> 20) - 1023; + i0 &=3D 0x000fffff; + i0 |=3D 0x00100000; + result =3D (j0 < 0 ? 0 : i0 >> (20 - j0)); } else if (j0 < (int)(8 * sizeof (long long int)) - 1) { diff --git a/newlib/libm/common/s_lrint.c b/newlib/libm/common/s_lrint.c index b37f50fd4d52..b37b93affa26 100644 --- a/newlib/libm/common/s_lrint.c +++ b/newlib/libm/common/s_lrint.c @@ -103,26 +103,17 @@ TWO52[2]=3D{ if(j0 < 20) { /* j0 in [-1023,19] */ - if(j0 < -1) - return 0; - else - { - /* j0 in [0,19] */ - /* shift amt in [0,19] */ - w =3D TWO52[sx] + x; - t =3D w - TWO52[sx]; - GET_HIGH_WORD(i0, t); - /* Detect the all-zeros representation of plus and - minus zero, which fails the calculation below. */ - if ((i0 & ~(1L << 31)) =3D=3D 0) - return 0; - /* After round: j0 in [0,20] */ - j0 =3D ((i0 & 0x7ff00000) >> 20) - 1023; - i0 &=3D 0x000fffff; - i0 |=3D 0x00100000; - /* shift amt in [20,0] */ - result =3D i0 >> (20 - j0); - } + w =3D TWO52[sx] + x; + t =3D w - TWO52[sx]; + GET_HIGH_WORD(i0, t); + /* Detect the all-zeros representation of plus and + minus zero, which fails the calculation below. */ + if ((i0 & ~(1L << 31)) =3D=3D 0) + return 0; + j0 =3D ((i0 & 0x7ff00000) >> 20) - 1023; + i0 &=3D 0x000fffff; + i0 |=3D 0x00100000; + result =3D (j0 < 0 ? 0 : i0 >> (20 - j0)); } else if (j0 < (int)(8 * sizeof (long int)) - 1) { diff --git a/newlib/libm/common/sf_llrint.c b/newlib/libm/common/sf_llrint.c index 7558e89acd56..905a5b21d040 100644 --- a/newlib/libm/common/sf_llrint.c +++ b/newlib/libm/common/sf_llrint.c @@ -60,9 +60,7 @@ TWO23[2]=3D{ =20 if (j0 < (int)(sizeof (long long int) * 8) - 1) { - if (j0 < -1) - return 0; - else if (j0 >=3D 23) + if (j0 >=3D 23) result =3D (long long int) ((i0 & 0x7fffff) | 0x800000) << (j0 - 2= 3); else { @@ -76,7 +74,7 @@ TWO23[2]=3D{ j0 =3D ((i0 >> 23) & 0xff) - 0x7f; i0 &=3D 0x7fffff; i0 |=3D 0x800000; - result =3D i0 >> (23 - j0); + result =3D (j0 < 0 ? 0 : i0 >> (23 - j0)); } } else diff --git a/newlib/libm/common/sf_lrint.c b/newlib/libm/common/sf_lrint.c index 3c58c5d10121..7fe47aefb264 100644 --- a/newlib/libm/common/sf_lrint.c +++ b/newlib/libm/common/sf_lrint.c @@ -60,9 +60,7 @@ TWO23[2]=3D{ =20 if (j0 < (int)(sizeof (long int) * 8) - 1) { - if (j0 < -1) - return 0; - else if (j0 >=3D 23) + if (j0 >=3D 23) result =3D (long int) ((i0 & 0x7fffff) | 0x800000) << (j0 - 23); else { @@ -76,7 +74,7 @@ TWO23[2]=3D{ j0 =3D ((i0 >> 23) & 0xff) - 0x7f; i0 &=3D 0x7fffff; i0 |=3D 0x800000; - result =3D i0 >> (23 - j0); + result =3D (j0 < 0 ? 0 : i0 >> (23 - j0)); } } else