>Synopsis: lround() result usually bad in range [1048576,2097152)
Host type: i386-redhat-linux-gnu
System: Linux schween.jpl.nasa.gov 2.4.20-28.9 #1 Thu Dec 18 13:45:22 EST 2003
i686 i686 i386 GNU/Linux
Addons: linuxthreads c_stubs glibc-compat
Build CFLAGS: -march=i386 -DNDEBUG=1 -finline-limit=2000 -g -O3
Build CC: gcc
Compiler version: 3.2.2 20030222 (Red Hat Linux 3.2.2-5)
Kernel headers: 2.4.20
Symbol versioning: yes
Build static: yes
Build shared: yes
Build pic-default: no
Build profile: yes
Build omitfp: no
Build bounded: no
Build static-nss: no
lround() produces garbage for nearly all arguments greater
than or equal to 2**20 but less than 2**21. The problem
occurs because lround() attempts to right shift a 32-bit
unsigned integer by 32 bits, and that operation is undefined
according to the standard.
Within that range, some rare arguments, e.g. integers plus
one half, do actually lead to correct results, at least on
this machine. That's because the erroneous shift's result
just happens to be right for those bit patterns.
The problem appears in sysdeps/ieee754/dbl-64/s_lround.c, on
line 61, which is excerpted below:
result = ((long int) i0 << (j0 - 20)) | (j >> (52 - j0));
In our case, j is a uint32_t, and j0 is 20, which makes the
right shift undefined.
long int j = lround( 1071930.0008 );
/* j should be 1071930, but instead is large neg value. */
Change lround() code to handle this case, so it doesn't do
the bad shift. There are several system-dependent variations
of the s_lround.c file. We don't know if the other variations
are right or wrong.
Sibling file s_llround.c (long long int version) does check for
the j0==20 case, so it's probably okay.
Created attachment 1 [details]
Ok, verified with the programm t.c:
gromit:~/tmp:$ gcc -Wall t.c -lm
Fixed with a patch with the description below, it will be in the next release.
2004-02-01 Ulrich Drepper <email@example.com>
* math/libm-test.inc (lround_test): Add new test.
* sysdeps/ieee754/dbl-64/s_lround.c (__lround): Fix special case
with result taking up 20 bits.
* sysdeps/ieee754/dbl-64/s_lrint.c (__lrint): Likewise.
* sysdeps/ieee754/dbl-64/s_llrint.c (__llrint): Likewise..
* sysdeps/ieee754/ldbl-96/s_lroundl.c (__lroundl): Fix special
case with result taking up 31 bits.
* sysdeps/ieee754/ldbl-96/s_lrintl.c (__lrintl): Likewise.
Comment on attachment 1 [details]
>#define _GNU_SOURCE 1
> long int j = lround (1071930.0008);
> printf ("%ld\n", j);
> return 0;
Hello. Excuse me for posting a spam comment. But you have a very good site. And I really need this link. https://www.history-of-great-discoveries.com/