Bug #17037
closedrounding of Rational#to_f
Description
I found a doubtful rounding behavior of Rational#to_f.
% ./ruby -ve '
a = 1r
e = Float::EPSILON.to_r
puts "e=#{e}"
n = 100
(0..n).each {|i|
r = a + e * i / n
f = r.to_f
p [i, f, r]
}
'
ruby 2.8.0dev (2020-07-20T06:39:31Z master 935d0b3d05) [x86_64-linux]
e=1/4503599627370496
[0, 1.0, (1/1)]
[1, 1.0, (450359962737049601/450359962737049600)]
[2, 1.0, (225179981368524801/225179981368524800)]
[3, 1.0, (450359962737049603/450359962737049600)]
[4, 1.0, (112589990684262401/112589990684262400)]
[5, 1.0, (90071992547409921/90071992547409920)]
[6, 1.0, (225179981368524803/225179981368524800)]
[7, 1.0, (450359962737049607/450359962737049600)]
[8, 1.0, (56294995342131201/56294995342131200)]
[9, 1.0, (450359962737049609/450359962737049600)]
[10, 1.0, (45035996273704961/45035996273704960)]
[11, 1.0, (450359962737049611/450359962737049600)]
[12, 1.0, (112589990684262403/112589990684262400)]
[13, 1.0, (450359962737049613/450359962737049600)]
[14, 1.0, (225179981368524807/225179981368524800)]
[15, 1.0, (90071992547409923/90071992547409920)]
[16, 1.0, (28147497671065601/28147497671065600)]
[17, 1.0, (450359962737049617/450359962737049600)]
[18, 1.0, (225179981368524809/225179981368524800)]
[19, 1.0, (450359962737049619/450359962737049600)]
[20, 1.0, (22517998136852481/22517998136852480)]
[21, 1.0, (450359962737049621/450359962737049600)]
[22, 1.0, (225179981368524811/225179981368524800)]
[23, 1.0, (450359962737049623/450359962737049600)]
[24, 1.0, (56294995342131203/56294995342131200)]
[25, 1.0, (18014398509481985/18014398509481984)]
[26, 1.0, (225179981368524813/225179981368524800)]
[27, 1.0, (450359962737049627/450359962737049600)]
[28, 1.0, (112589990684262407/112589990684262400)]
[29, 1.0, (450359962737049629/450359962737049600)]
[30, 1.0, (45035996273704963/45035996273704960)]
[31, 1.0, (450359962737049631/450359962737049600)]
[32, 1.0, (14073748835532801/14073748835532800)]
[33, 1.0000000000000002, (450359962737049633/450359962737049600)]
[34, 1.0000000000000002, (225179981368524817/225179981368524800)]
[35, 1.0, (90071992547409927/90071992547409920)]
[36, 1.0000000000000002, (112589990684262409/112589990684262400)]
[37, 1.0000000000000002, (450359962737049637/450359962737049600)]
[38, 1.0000000000000002, (225179981368524819/225179981368524800)]
[39, 1.0000000000000002, (450359962737049639/450359962737049600)]
[40, 1.0, (11258999068426241/11258999068426240)]
[41, 1.0000000000000002, (450359962737049641/450359962737049600)]
[42, 1.0000000000000002, (225179981368524821/225179981368524800)]
[43, 1.0000000000000002, (450359962737049643/450359962737049600)]
[44, 1.0000000000000002, (112589990684262411/112589990684262400)]
[45, 1.0000000000000002, (90071992547409929/90071992547409920)]
[46, 1.0000000000000002, (225179981368524823/225179981368524800)]
[47, 1.0000000000000002, (450359962737049647/450359962737049600)]
[48, 1.0000000000000002, (28147497671065603/28147497671065600)]
[49, 1.0000000000000002, (450359962737049649/450359962737049600)]
[50, 1.0, (9007199254740993/9007199254740992)]
[51, 1.0000000000000002, (450359962737049651/450359962737049600)]
[52, 1.0000000000000002, (112589990684262413/112589990684262400)]
[53, 1.0000000000000002, (450359962737049653/450359962737049600)]
[54, 1.0000000000000002, (225179981368524827/225179981368524800)]
[55, 1.0000000000000002, (90071992547409931/90071992547409920)]
[56, 1.0000000000000002, (56294995342131207/56294995342131200)]
[57, 1.0000000000000002, (450359962737049657/450359962737049600)]
[58, 1.0000000000000002, (225179981368524829/225179981368524800)]
[59, 1.0000000000000002, (450359962737049659/450359962737049600)]
[60, 1.0000000000000002, (22517998136852483/22517998136852480)]
[61, 1.0000000000000002, (450359962737049661/450359962737049600)]
[62, 1.0000000000000002, (225179981368524831/225179981368524800)]
[63, 1.0000000000000002, (450359962737049663/450359962737049600)]
[64, 1.0000000000000002, (7036874417766401/7036874417766400)]
[65, 1.0000000000000002, (90071992547409933/90071992547409920)]
[66, 1.0000000000000002, (225179981368524833/225179981368524800)]
[67, 1.0000000000000002, (450359962737049667/450359962737049600)]
[68, 1.0000000000000002, (112589990684262417/112589990684262400)]
[69, 1.0000000000000002, (450359962737049669/450359962737049600)]
[70, 1.0000000000000002, (45035996273704967/45035996273704960)]
[71, 1.0000000000000002, (450359962737049671/450359962737049600)]
[72, 1.0000000000000002, (56294995342131209/56294995342131200)]
[73, 1.0000000000000002, (450359962737049673/450359962737049600)]
[74, 1.0000000000000002, (225179981368524837/225179981368524800)]
[75, 1.0000000000000002, (18014398509481987/18014398509481984)]
[76, 1.0000000000000002, (112589990684262419/112589990684262400)]
[77, 1.0000000000000002, (450359962737049677/450359962737049600)]
[78, 1.0000000000000002, (225179981368524839/225179981368524800)]
[79, 1.0000000000000002, (450359962737049679/450359962737049600)]
[80, 1.0000000000000002, (5629499534213121/5629499534213120)]
[81, 1.0000000000000002, (450359962737049681/450359962737049600)]
[82, 1.0000000000000002, (225179981368524841/225179981368524800)]
[83, 1.0000000000000002, (450359962737049683/450359962737049600)]
[84, 1.0000000000000002, (112589990684262421/112589990684262400)]
[85, 1.0000000000000002, (90071992547409937/90071992547409920)]
[86, 1.0000000000000002, (225179981368524843/225179981368524800)]
[87, 1.0000000000000002, (450359962737049687/450359962737049600)]
[88, 1.0000000000000002, (56294995342131211/56294995342131200)]
[89, 1.0000000000000002, (450359962737049689/450359962737049600)]
[90, 1.0000000000000002, (45035996273704969/45035996273704960)]
[91, 1.0000000000000002, (450359962737049691/450359962737049600)]
[92, 1.0000000000000002, (112589990684262423/112589990684262400)]
[93, 1.0000000000000002, (450359962737049693/450359962737049600)]
[94, 1.0000000000000002, (225179981368524847/225179981368524800)]
[95, 1.0000000000000002, (90071992547409939/90071992547409920)]
[96, 1.0000000000000002, (14073748835532803/14073748835532800)]
[97, 1.0000000000000002, (450359962737049697/450359962737049600)]
[98, 1.0000000000000002, (225179981368524849/225179981368524800)]
[99, 1.0000000000000002, (450359962737049699/450359962737049600)]
[100, 1.0000000000000002, (4503599627370497/4503599627370496)]
This sample program tries to convert rationals between
1.0 and 1.0 + Float::EPSILON to float.
Since there is no representable float values between them
(except 1.0 and 1.0 + Float::EPSILON),
I expect that
r.to_f returns 1.0 for r < X and
1.0 + Float::EPSILON for r > X
for some X.
But my expectation is not valid:
[34, 1.0000000000000002, (225179981368524817/225179981368524800)]
[35, 1.0, (90071992547409927/90071992547409920)]
I.e.
1 + Float::EPSILON.to_r * 34 / 100 < 1 + Float::EPSILON.to_r * 35 / 100
but
(1 + Float::EPSILON.to_r * 34 / 100).to_f > (1 + Float::EPSILON.to_r * 35 / 100).to_f
I guess Rational#to_f should round the rational value to a nearest representable float value.
Updated by akr (Akira Tanaka) over 4 years ago
Gauche scheme interpreter has same issue and Kawai-san (the author of Gauche) investigate it.
http://blog.practical-scheme.net/gauche/20200722-ratnum-flonum
Updated by JesseJohnson (Jesse Johnson) about 1 year ago
Test case:
def test_rational_with_large_integer_components_to_f
r = 450359962737049649/450359962737049600r
assert_equal(1.0, r.to_f)
end
The issue is that large integers, abs > 2 ** 53 - 1, are truncated when converting to double precision floating point and this affects which floating point value is closest after division. This can be fixed by using BigDecimal but I'm not sure that is an appropriate dependency for Rational.
Updated by nobu (Nobuyoshi Nakada) about 1 year ago
- Status changed from Open to Closed
Applied in changeset git|8e93bf8e1fbac73b677c333b19a8b55ae9daddc3.
[Bug #17037] Improve accuracy of division near precision limits
When dividing near the precision limit of double
, use Bignum
division to get rid of rounding errors.