Feature #13420
closedInteger#{round,floor,ceil,truncate} should always return an integer, not a float
Description
The current behavior of Integer#{round,floor,ceil,truncate} produces wrong results for large integers.
In the case of a positive precision argument, these methods return the receiver converted to a float, effectively doing the same as to_f
.
2.round(1) # => 2.0
This leads to errors for large integers:
(10**25).round(2).to_i # => 10000000000000000905969664
(10**400).round(2) # => Infinity
Mathematically speaking, the value of an integer should not be changed by #round, #floor, #ceil, or #truncate, regardless of the precision (when positive). An integer rounded to e.g. 2 decimal digits is still the same (and exact) integer.
The desired behavior should be to keep precision as high as possible by not needlessly converting to Float.
The provided patch fixes these methods to return self
for positive precision argument, similar to the behavior without a specified precision, i.e. precision 0.
Files
Updated by nobu (Nobuyoshi Nakada) over 7 years ago
Indeed.
And documents?
Updated by stomar (Marcus Stollsteimer) over 7 years ago
- File deleted (
0001-Integer-round-floor-ceil-truncate.patch)
Updated by stomar (Marcus Stollsteimer) over 7 years ago
- File 0001-Integer-round-floor-ceil-truncate.patch 0001-Integer-round-floor-ceil-truncate.patch added
Patch updated to include doc fixes.
Updated by mrkn (Kenta Murata) over 7 years ago
- Related to Bug #12780: BigDecimal#round returns different types depending on argument added
Updated by stomar (Marcus Stollsteimer) over 7 years ago
The patch has been updated to also include doc changes.
Any thoughts on this?
Updated by stomar (Marcus Stollsteimer) over 7 years ago
nobu, does this mean "Nice. Go ahead and apply!"?
(I fear I'm not too familiar with the ways around here, yet.)
And I noticed that while Integer#{floor,ceil,truncate} accept an ndigits
argument only since recently (Ruby 2.4), Integer#round has this option and the behavior of returning a float for quite some time, and it's also in the specs (spec/rubyspec/core/integer/round_spec.rb
). I guess they would need to get updated.
Updated by nobu (Nobuyoshi Nakada) over 7 years ago
- Status changed from Open to Assigned
- Assignee set to stomar (Marcus Stollsteimer)
stomar (Marcus Stollsteimer) wrote:
nobu, does this mean "Nice. Go ahead and apply!"?
Yes, of course.
And I noticed that while Integer#{floor,ceil,truncate} accept an
ndigits
argument only since recently (Ruby 2.4), Integer#round has this option and the behavior of returning a float for quite some time, and it's also in the specs (spec/rubyspec/core/integer/round_spec.rb
). I guess they would need to get updated.
Indeed, it needs a version guard.
Updated by stomar (Marcus Stollsteimer) over 7 years ago
- Status changed from Assigned to Closed
Applied in changeset trunk|r58586.
make Integer#{round,floor,ceil,truncate} always return integer
-
numeric.c (int_round): return integer (self) instead of float
for Integer#round with positive ndigits argument, because
conversion to float introduces errors for large integers. -
numeric.c (int_floor): ditto for Integer#floor.
-
numeric.c (int_ceil): ditto for Integer#ceil.
-
numeric.c (int_truncate): ditto for Integer#truncate.
-
test/ruby/test_integer.rb: adjust test cases and add some more.
[ruby-core:80645] [Bug #13420]
Updated by stomar (Marcus Stollsteimer) over 7 years ago
Applied.
I opened a PR for the specs: https://github.com/ruby/spec/pull/436 [merged]
Should I add a comment in NEWS
or not? [done]
Updated by Eregon (Benoit Daloze) over 7 years ago
stomar (Marcus Stollsteimer) wrote:
Applied.
I opened a PR for the specs: https://github.com/ruby/spec/pull/436
Thanks!
Should I add a comment in
NEWS
or not?
Yes, I think the rule is to add a NEWS entry for every user-visible behavior change.
Updated by usa (Usaku NAKAMURA) over 7 years ago
- Tracker changed from Bug to Feature