Issue #3166: Make long -> float (and int -> float) conversions
correctly rounded, using round-half-to-even.  This ensures that the
value of float(n) doesn't depend on whether we're using 15-bit digits
or 30-bit digits for Python longs.
diff --git a/Lib/test/test_int.py b/Lib/test/test_int.py
index ce18ad2..514a98e 100644
--- a/Lib/test/test_int.py
+++ b/Lib/test/test_int.py
@@ -275,6 +275,40 @@
             self.assertEqual((a+1).bit_length(), i+1)
             self.assertEqual((-a-1).bit_length(), i+1)
 
+    @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"),
+                         "test requires IEEE 754 doubles")
+    def test_float_conversion(self):
+        # values exactly representable as floats
+        exact_values = [-2, -1, 0, 1, 2, 2**52, 2**53-1, 2**53, 2**53+2,
+                         2**53+4, 2**54-4, 2**54-2, 2**63, -2**63, 2**64,
+                         -2**64, 10**20, 10**21, 10**22]
+        for value in exact_values:
+            self.assertEqual(int(float(int(value))), value)
+
+        # test round-half-to-even
+        self.assertEqual(int(float(2**53+1)), 2**53)
+        self.assertEqual(int(float(2**53+2)), 2**53+2)
+        self.assertEqual(int(float(2**53+3)), 2**53+4)
+        self.assertEqual(int(float(2**53+5)), 2**53+4)
+        self.assertEqual(int(float(2**53+6)), 2**53+6)
+        self.assertEqual(int(float(2**53+7)), 2**53+8)
+
+        self.assertEqual(int(float(-2**53-1)), -2**53)
+        self.assertEqual(int(float(-2**53-2)), -2**53-2)
+        self.assertEqual(int(float(-2**53-3)), -2**53-4)
+        self.assertEqual(int(float(-2**53-5)), -2**53-4)
+        self.assertEqual(int(float(-2**53-6)), -2**53-6)
+        self.assertEqual(int(float(-2**53-7)), -2**53-8)
+
+        self.assertEqual(int(float(2**54-2)), 2**54-2)
+        self.assertEqual(int(float(2**54-1)), 2**54)
+        self.assertEqual(int(float(2**54+2)), 2**54)
+        self.assertEqual(int(float(2**54+3)), 2**54+4)
+        self.assertEqual(int(float(2**54+5)), 2**54+4)
+        self.assertEqual(int(float(2**54+6)), 2**54+8)
+        self.assertEqual(int(float(2**54+10)), 2**54+8)
+        self.assertEqual(int(float(2**54+11)), 2**54+12)
+
     def test_intconversion(self):
         # Test __int__()
         class ClassicMissingMethods:
diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py
index 1a0e33d..b41d270 100644
--- a/Lib/test/test_long.py
+++ b/Lib/test/test_long.py
@@ -645,6 +645,65 @@
                             else:
                                 self.assertRaises(TypeError, pow,longx, longy, long(z))
 
+    @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"),
+                         "test requires IEEE 754 doubles")
+    def test_float_conversion(self):
+        import sys
+        DBL_MAX = sys.float_info.max
+        DBL_MAX_EXP = sys.float_info.max_exp
+        DBL_MANT_DIG = sys.float_info.mant_dig
+
+        exact_values = [0L, 1L, 2L,
+                         long(2**53-3),
+                         long(2**53-2),
+                         long(2**53-1),
+                         long(2**53),
+                         long(2**53+2),
+                         long(2**54-4),
+                         long(2**54-2),
+                         long(2**54),
+                         long(2**54+4)]
+        for x in exact_values:
+            self.assertEqual(long(float(x)), x)
+            self.assertEqual(long(float(-x)), -x)
+
+        # test round-half-even
+        for x, y in [(1, 0), (2, 2), (3, 4), (4, 4), (5, 4), (6, 6), (7, 8)]:
+            for p in xrange(15):
+                self.assertEqual(long(float(2L**p*(2**53+x))), 2L**p*(2**53+y))
+
+        for x, y in [(0, 0), (1, 0), (2, 0), (3, 4), (4, 4), (5, 4), (6, 8),
+                     (7, 8), (8, 8), (9, 8), (10, 8), (11, 12), (12, 12),
+                     (13, 12), (14, 16), (15, 16)]:
+            for p in xrange(15):
+                self.assertEqual(long(float(2L**p*(2**54+x))), 2L**p*(2**54+y))
+
+        # behaviour near extremes of floating-point range
+        long_dbl_max = long(DBL_MAX)
+        top_power = 2**DBL_MAX_EXP
+        halfway = (long_dbl_max + top_power)/2
+        self.assertEqual(float(long_dbl_max), DBL_MAX)
+        self.assertEqual(float(long_dbl_max+1), DBL_MAX)
+        self.assertEqual(float(halfway-1), DBL_MAX)
+        self.assertRaises(OverflowError, float, halfway)
+        self.assertEqual(float(1-halfway), -DBL_MAX)
+        self.assertRaises(OverflowError, float, -halfway)
+        self.assertRaises(OverflowError, float, top_power-1)
+        self.assertRaises(OverflowError, float, top_power)
+        self.assertRaises(OverflowError, float, top_power+1)
+        self.assertRaises(OverflowError, float, 2*top_power-1)
+        self.assertRaises(OverflowError, float, 2*top_power)
+        self.assertRaises(OverflowError, float, top_power*top_power)
+
+        for p in xrange(100):
+            x = long(2**p * (2**53 + 1) + 1)
+            y = long(2**p * (2**53+ 2))
+            self.assertEqual(long(float(x)), y)
+
+            x = long(2**p * (2**53 + 1))
+            y = long(2**p * 2**53)
+            self.assertEqual(long(float(x)), y)
+
     def test_float_overflow(self):
         import math