[Bug math/19869] New: floor and fmod not consistent with each other
robert.dodier at gmail dot com
sourceware-bugzilla@sourceware.org
Sat Mar 26 05:52:00 GMT 2016
https://sourceware.org/bugzilla/show_bug.cgi?id=19869
Bug ID: 19869
Summary: floor and fmod not consistent with each other
Product: glibc
Version: 2.23
Status: NEW
Severity: normal
Priority: P2
Component: math
Assignee: unassigned at sourceware dot org
Reporter: robert.dodier at gmail dot com
Target Milestone: ---
Created attachment 9130
--> https://sourceware.org/bugzilla/attachment.cgi?id=9130&action=edit
program to find x and y s.t. floor(x/y) and fmod(x,y) are inconsistent
When x is very close to an integer multiple of y, floor and fmod can give
inconsistent results in the sense that floor(x/y)*y + fmod(x,y) is not anywhere
close to x.
For example, with x = 8e0 and y = 1.6e0, fmod(x,y) = 1.5999999999999996e+0 but
floor(x/y) = 5e0, so floor(x/y)*y + fmod(x,y) = 9.6e0 approximately.
The problem is that y is very slightly larger than x/floor(x/y), so
floor(x/y)*y is a little bigger than x. It appears that fmod(x, y) is returned
as y + (x - floor(x/y)*y) so fmod(x, y) is positive (it is a little smaller
than y). But floor(x/y) is not likewise adjusted.
It seems like either fmod(x,y) should not be adjusted, and returned as a small
negative number (the choice of some other libraries) or zero (the choice of
still others), or else floor(x/y) should be reduced by 1, and fmod(x,y)
returned as it is now. There are probably other possibilities. I won't try to
sort out the arguments for different options.
There are many other examples; see attached program test-fmod.c to find them.
I am working with glibc 2.23. uname -a says: Linux freekbox 3.13.0-44-generic
#73-Ubuntu SMP Tue Dec 16 00:23:46 UTC 2014 i686 i686 i686 GNU/Linux
I only tried it with doubles.
PS. Here is some detailed output.
$ cat test-fmod-1.log
gnu_get_libc_version => 2.23
8.0000000000000000e+00/1.6000000000000001e+00 = 5.0000000000000000e+00
floor(8.0000000000000000e+00/1.6000000000000001e+00) = 5.0000000000000000e+00
floor(8.0000000000000000e+00/1.6000000000000001e+00)*1.6000000000000001e+00 =
8.0000000000000000e+00
8.0000000000000000e+00 -
floor(8.0000000000000000e+00/1.6000000000000001e+00)*1.6000000000000001e+00 =
-4.4408920985006262e-16
fmod(8.0000000000000000e+00, 1.6000000000000001e+00) = 1.5999999999999996e+00
8.0000000000000000e+00 -
(floor(8.0000000000000000e+00/1.6000000000000001e+00)*1.6000000000000001e+00 +
fmod(8.0000000000000000e+00, 1.6000000000000001e+00)) = -1.6000000000000001e+00
PPS. Here's the program to generate the above output.
#include <stdio.h>
#include <math.h>
#include <gnu/libc-version.h>
int main (int argc, char** argv)
{
double x = 8e0, y = 1.6e0;
double xy, floor_xy, fmod_xy, r;
printf ("gnu_get_libc_version => %s\n", gnu_get_libc_version ());
xy = x/y;
floor_xy = floor(xy);
fmod_xy = fmod(x, y);
r = x - (floor_xy*y + fmod_xy);
printf ("%.16le/%.16le = %.16le\n", x, y, xy);
printf ("floor(%.16le/%.16le) = %.16le\n", x, y, floor_xy);
printf ("floor(%.16le/%.16le)*%.16le = %.16le\n", x, y, y, floor_xy*y);
printf ("%.16le - floor(%.16le/%.16le)*%.16le = %.16le\n", x, x, y, y, x -
floor_xy*y);
printf ("fmod(%.16le, %.16le) = %.16le\n", x, y, fmod_xy);
printf ("%.16le - (floor(%.16le/%.16le)*%.16le + fmod(%.16le, %.16le)) =
%.16le\n", x, x, y, y, x, y, r);
return 0;
}
--
You are receiving this mail because:
You are on the CC list for the bug.
More information about the Glibc-bugs
mailing list