Below is the list of changes that have just been committed into a local
5.0 repository of kaa. When kaa does a push these changes
will be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
ChangeSet@stripped, 2008-03-14 13:25:37+03:00, kaa@kaamos.(none) +4 -0
Fix for bug #15936: "round" differs on Windows to Unix
Both of our own implementations of rint(3) were inconsistent with the
most common behavior of rint() on those platforms that have it: round
to nearest, break ties by rounding to nearest even.
Fixed by leaving just one implementation of rint() in our source tree,
and changing its behavior to match the most common native
implementations on other platforms.
include/config-win.h@stripped, 2008-03-14 13:25:36+03:00, kaa@kaamos.(none) +0 -9
Removed the incorrect implementation of rint() for Windows.
include/my_global.h@stripped, 2008-03-14 13:25:36+03:00, kaa@kaamos.(none) +35 -2
Added an rint() implementation for platforms that do not have it.
mysql-test/r/func_math.result@stripped, 2008-03-14 13:25:36+03:00, kaa@kaamos.(none) +30 -0
Added a test case for bug #15936.
mysql-test/t/func_math.test@stripped, 2008-03-14 13:25:36+03:00, kaa@kaamos.(none) +20 -0
Added a test case for bug #15936.
diff -Nrup a/include/config-win.h b/include/config-win.h
--- a/include/config-win.h 2007-10-23 17:48:54 +04:00
+++ b/include/config-win.h 2008-03-14 13:25:36 +03:00
@@ -31,7 +31,6 @@ functions */
#include <sys/locking.h>
#include <windows.h>
-#include <math.h> /* Because of rint() */
#include <fcntl.h>
#include <io.h>
#include <malloc.h>
@@ -225,13 +224,6 @@ typedef uint rf_SetTimer;
#define inline __inline
#endif /* __cplusplus */
-inline double rint(double nr)
-{
- double f = floor(nr);
- double c = ceil(nr);
- return (((c-nr) >= (nr-f)) ? f :c);
-}
-
#ifdef _WIN64
#define ulonglong2double(A) ((double) (ulonglong) (A))
#define my_off_t2double(A) ((double) (my_off_t) (A))
@@ -328,7 +320,6 @@ inline double ulonglong2double(ulonglong
#define HAVE_FLOAT_H
#define HAVE_LIMITS_H
#define HAVE_STDDEF_H
-#define HAVE_RINT /* defined in this file */
#define NO_FCNTL_NONBLOCK /* No FCNTL */
#define HAVE_ALLOCA
#define HAVE_STRPBRK
diff -Nrup a/include/my_global.h b/include/my_global.h
--- a/include/my_global.h 2007-11-30 03:37:04 +03:00
+++ b/include/my_global.h 2008-03-14 13:25:36 +03:00
@@ -483,9 +483,42 @@ typedef unsigned short ushort;
#define test_all_bits(a,b) (((a) & (b)) == (b))
#define set_bits(type, bit_count) (sizeof(type)*8 <= (bit_count) ? ~(type) 0 : ((((type) 1) << (bit_count)) - (type) 1))
#define array_elements(A) ((uint) (sizeof(A)/sizeof(A[0])))
+
#ifndef HAVE_RINT
-#define rint(A) floor((A)+(((A) < 0)? -0.5 : 0.5))
-#endif
+/**
+ All integers up to this number can be represented exactly as double precision
+ values (DBL_MANT_DIG == 53 for IEEE 754 hardware).
+*/
+#define MAX_EXACT_INTEGER ((1LL << DBL_MANT_DIG) - 1)
+
+/**
+ rint(3) implementation for platforms that do not have it.
+ Always rounds to the nearest integer with ties being rounded to the nearest
+ even integer to mimic glibc's rint() behavior in the "round-to-nearest"
+ FPU mode. Hardware-specific optimizations are possible (frndint on x86).
+ Unlike this implementation, hardware will also honor the FPU rounding mode.
+*/
+
+inline double rint(double x)
+{
+ double f, i;
+ f = modf(x, &i);
+
+ /*
+ All doubles with absolute values > MAX_EXACT_INTEGER are even anyway,
+ no need to check it.
+ */
+ if (x > 0.0)
+ i += (double) ((f > 0.5) || (f == 0.5 &&
+ i <= (double) MAX_EXACT_INTEGER &&
+ (longlong)i % 2));
+ else
+ i -= (double) ((f < -0.5) || (f == -0.5 &&
+ i >= (double) -MAX_EXACT_INTEGER &&
+ (longlong)i % 2));
+ return i;
+}
+#endif /* HAVE_RINT */
/* Define some general constants */
#ifndef TRUE
diff -Nrup a/mysql-test/r/func_math.result b/mysql-test/r/func_math.result
--- a/mysql-test/r/func_math.result 2007-10-01 13:51:58 +04:00
+++ b/mysql-test/r/func_math.result 2008-03-14 13:25:36 +03:00
@@ -360,4 +360,34 @@ SELECT a DIV 2 FROM t1 UNION SELECT a DI
a DIV 2
0
DROP TABLE t1;
+CREATE TABLE t1 (a DOUBLE);
+INSERT INTO t1 VALUES (-1.1), (1.1),
+(-1.5), (1.5),
+(-1.9), (1.9),
+(-2.1), (2.1),
+(-2.5), (2.5),
+(-2.9), (2.9),
+# Check numbers with absolute values > 2^53 - 1
+# (see comments for MAX_EXACT_INTEGER)
+(-1e16 - 0.5), (1e16 + 0.5),
+(-1e16 - 1.5), (1e16 + 1.5);
+SELECT a, ROUND(a) FROM t1;
+a ROUND(a)
+-1.1 -1
+1.1 1
+-1.5 -2
+1.5 2
+-1.9 -2
+1.9 2
+-2.1 -2
+2.1 2
+-2.5 -2
+2.5 2
+-2.9 -3
+2.9 3
+-1e+16 -10000000000000000
+1e+16 10000000000000000
+-1e+16 -10000000000000002
+1e+16 10000000000000002
+DROP TABLE t1;
End of 5.0 tests
diff -Nrup a/mysql-test/t/func_math.test b/mysql-test/t/func_math.test
--- a/mysql-test/t/func_math.test 2007-10-01 13:51:58 +04:00
+++ b/mysql-test/t/func_math.test 2008-03-14 13:25:36 +03:00
@@ -229,5 +229,25 @@ INSERT INTO t1 VALUES ('a');
SELECT a DIV 2 FROM t1 UNION SELECT a DIV 2 FROM t1;
DROP TABLE t1;
+#
+# Bug #15936: "round" differs on Windows to Unix
+#
+
+CREATE TABLE t1 (a DOUBLE);
+
+INSERT INTO t1 VALUES (-1.1), (1.1),
+ (-1.5), (1.5),
+ (-1.9), (1.9),
+ (-2.1), (2.1),
+ (-2.5), (2.5),
+ (-2.9), (2.9),
+# Check numbers with absolute values > 2^53 - 1
+# (see comments for MAX_EXACT_INTEGER)
+ (-1e16 - 0.5), (1e16 + 0.5),
+ (-1e16 - 1.5), (1e16 + 1.5);
+
+SELECT a, ROUND(a) FROM t1;
+
+DROP TABLE t1;
--echo End of 5.0 tests