>Confidential: no >Synopsis: lround() result usually bad in range [1048576,2097152) >Severity: serious >Priority: medium >Category: libc >Class: sw-bug >Release: libc-2.3.2 >Environment: 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 Architecture: i686 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 >Description: 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)); ^^^^^^^^^^^^^^ BAD SHIFT In our case, j is a uint32_t, and j0 is 20, which makes the right shift undefined. >How-To-Repeat: long int j = lround( 1071930.0008 ); /* j should be 1071930, but instead is large neg value. */ >Fix: 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] Testprogram
Ok, verified with the programm t.c: gromit:~/tmp:[0]$ gcc -Wall t.c -lm gromit:~/tmp:[0]$ ./a.out 2150924286
Fixed with a patch with the description below, it will be in the next release. Thanks, Andreas 2004-02-01 Ulrich Drepper <drepper@redhat.com> * math/libm-test.inc (lround_test): Add new test. (llround_test): Likewise. (lrint_test): Likewise. (llrint_test): Likewise. * 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] Testprogram >#define _GNU_SOURCE 1 >#include <math.h> >#include <stdio.h> > >int >main (void) >{ > 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/