Feature #6973
openAdd an #integral? method to Numeric to test for whole-number values
Added by regularfry (Alex Young) almost 12 years ago. Updated over 6 years ago.
Description
Numeric#integer? checks whether an instance is an Integer. It is often useful to check whether the value of a non-Integer variable is actually a whole number, and the #integer? method doesn't help here.
This patch adds Numeric#integral?, which performs this check.
Files
integral.patch (2.43 KB) integral.patch | regularfry (Alex Young), 09/04/2012 06:03 AM |
Updated by jballanc (Joshua Ballanco) almost 12 years ago
Just a suggestion, but I don't think "integral" really explains what you want this method to do, and it is confusingly close to "integer?". Why not Numeric#whole_number?
Personally, I'm not entirely convinced this method is a good idea. With Floats, you can't really guarantee that "4.0" is the same as "4". It could actually be "4.00000000000000001" but the precision is lost. If you want to know if my_float.floor == my_float
, that check isn't so hard to do and also has a very specific meaning. I could maybe see including this sort of method in BigDecimal or Rational (though in that case it would essentially be the same as my_rational.denomenator == 1
). What sort of use case were you picturing?
Finally, just a note on the patch: there are easier (i.e. without allocation) ways to determine if a float, bigdecimal, or rational is a whole number. Why not give all of the subclasses in the stdlib specific implementations in addition to the generic implementation in Numeric?
Updated by regularfry (Alex Young) almost 12 years ago
On 04/09/12 11:01, jballanc (Joshua Ballanco) wrote:
Issue #6973 has been updated by jballanc (Joshua Ballanco).
Just a suggestion, but I don't think "integral" really explains what
you want this method to do, and it is confusingly close to
"integer?". Why not Numeric#whole_number?
I could live with that. I think the problem is actually that #integer?
is unfortunately-named, but let's put that to one side :-)
Personally, I'm not entirely convinced this method is a good idea.
With Floats, you can't really guarantee that "4.0" is the same as
"4". It could actually be "4.00000000000000001" but the precision is
lost.
This is actually not true. If you have a float with a value of 4.0,
then that genuinely is the same as 4. The whole number value "4" has
a precise representation in floating point format, and if you have that
value then it makes no sense to say that what you have might not be
equal to 4.
Floats are precise, just like Integers are. Operations on floats are
not accurate, and that's where the confusion comes from. That's
inherent to the representation and something you've got to deal with
anyway, so I certainly don't see this test as making that problem worse.
If you want to know if
my_float.floor == my_float
, that check
isn't so hard to do and also has a very specific meaning. I could
maybe see including this sort of method in BigDecimal or Rational
(though in that case it would essentially be the same as
my_rational.denomenator == 1
). What sort of use case were you
picturing?
This came up in #6958, specifically because BigDecimal's #integer? as
inherited from Numeric is confusing.
Finally, just a note on the patch: there are easier (i.e. without
allocation) ways to determine if a float, bigdecimal, or rational is
a whole number. Why not give all of the subclasses in the stdlib
specific implementations in addition to the generic implementation in
Numeric?
Sure. Interface before implementation.
--
Alex
---------------------------------------- Feature #6973: Add
an #integral? method to Numeric to test for whole-number values
https://bugs.ruby-lang.org/issues/6973#change-29171Author: regularfry (Alex Young) Status: Open Priority: Normal
Assignee: Category: Target version: 2.0.0Numeric#integer? checks whether an instance is an Integer. It is
often useful to check whether the value of a non-Integer variable is
actually a whole number, and the #integer? method doesn't help here.This patch adds Numeric#integral?, which performs this check.
Updated by jballanc (Joshua Ballanco) almost 12 years ago
=begin
Floats are precise, just like Integers are. Operations on floats are
not accurate, and that's where the confusion comes from. That's
inherent to the representation and something you've got to deal with
anyway, so I certainly don't see this test as making that problem worse.
Ok, fair point. Ruby already doesn't protect you from a lack of knowledge of floats, so I can accept that this method wouldn't either.
This came up in #6958, specifically because BigDecimal's #integer? as
inherited from Numeric is confusing.
...
Sure. Interface before implementation.
Actually, as I got to thinking about this, I think the variety of different ways this can be determined efficiently for different numeric types might justify having this as a method. That, of course, presupposes that each numeric type gets a concrete, efficient implementation.
=end
Updated by ko1 (Koichi Sasada) almost 12 years ago
- Category set to core
- Assignee set to mame (Yusuke Endoh)
mame-san, could you judge on it?
Updated by mame (Yusuke Endoh) almost 12 years ago
- Assignee changed from mame (Yusuke Endoh) to mrkn (Kenta Murata)
- Target version changed from 2.0.0 to 2.6
- Status changed from Open to Assigned
I think mrkn is eligible to handle this ticket.
The following is my personal comment.
regularfry (Alex Young) wrote:
Personally, I'm not entirely convinced this method is a good idea.
With Floats, you can't really guarantee that "4.0" is the same as
"4". It could actually be "4.00000000000000001" but the precision is
lost.This is actually not true. If you have a float with a value of 4.0,
then that genuinely is the same as 4. The whole number value "4" has
a precise representation in floating point format, and if you have that
value then it makes no sense to say that what you have might not be
equal to 4.Floats are precise, just like Integers are. Operations on floats are
not accurate, and that's where the confusion comes from. That's
inherent to the representation and something you've got to deal with
anyway, so I certainly don't see this test as making that problem worse.
Your points is valid as long as we can distinguish a Float that includes
error from a Float that includes no error, such as, just created by a
Float literal, or by only accurate operations (no overflow, no indivisible
division, ...).
But in fact, we cannot distinguish them. We conservatively have to think
that any Float object includes an error, I think.
--
Yusuke Endoh mame@tsg.ne.jp
Updated by regularfry (Alex Young) almost 12 years ago
On 27/10/12 05:26, mame (Yusuke Endoh) wrote:
Issue #6973 has been updated by mame (Yusuke Endoh).
Status changed from Open to Assigned
Assignee changed from mame (Yusuke Endoh) to mrkn (Kenta Murata)
Target version changed from 2.0.0 to next minorI think mrkn is eligible to handle this ticket.
The following is my personal comment.regularfry (Alex Young) wrote:
Personally, I'm not entirely convinced this method is a good idea.
With Floats, you can't really guarantee that "4.0" is the same as
"4". It could actually be "4.00000000000000001" but the precision is
lost.This is actually not true. If you have a float with a value of 4.0,
then that genuinely is the same as 4. The whole number value "4" has
a precise representation in floating point format, and if you have that
value then it makes no sense to say that what you have might not be
equal to 4.Floats are precise, just like Integers are. Operations on floats are
not accurate, and that's where the confusion comes from. That's
inherent to the representation and something you've got to deal with
anyway, so I certainly don't see this test as making that problem worse.Your points is valid as long as we can distinguish a Float that includes
error from a Float that includes no error, such as, just created by a
Float literal, or by only accurate operations (no overflow, no indivisible
division, ...).
But in fact, we cannot distinguish them. We conservatively have to think
that any Float object includes an error, I think.
So if I knowingly and correctly construct a calculation which cannot
contain such an error, Ruby should tell me that it's wrong?
--
Alex
Updated by alexeymuranov (Alexey Muranov) almost 12 years ago
Floats are precise, just like Integers are. Operations on floats are
not accurate, and that's where the confusion comes from. That's
inherent to the representation and something you've got to deal with
anyway, so I certainly don't see this test as making that problem worse.Your points is valid as long as we can distinguish a Float that includes
error from a Float that includes no error, such as, just created by a
Float literal, or by only accurate operations (no overflow, no indivisible
division, ...).
But in fact, we cannot distinguish them. We conservatively have to think
that any Float object includes an error, I think.So if I knowingly and correctly construct a calculation which cannot
contain such an error, Ruby should tell me that it's wrong?
I guess the question is: what would be a point in calling this method on a Float? A Float value is rarely exact in the sense that it rarely coincides with the real-world value or mathematical value which it models.
Updated by phluid61 (Matthew Kerwin) almost 12 years ago
On 30 October 2012 08:12, alexeymuranov (Alexey Muranov)
redmine@ruby-lang.org wrote:
Issue #6973 has been updated by alexeymuranov (Alexey Muranov).
Floats are precise, just like Integers are. Operations on floats are
not accurate, and that's where the confusion comes from. That's
inherent to the representation and something you've got to deal with
anyway, so I certainly don't see this test as making that problem worse.Your points is valid as long as we can distinguish a Float that includes
error from a Float that includes no error, such as, just created by a
Float literal, or by only accurate operations (no overflow, no indivisible
division, ...).
But in fact, we cannot distinguish them. We conservatively have to think
that any Float object includes an error, I think.So if I knowingly and correctly construct a calculation which cannot
contain such an error, Ruby should tell me that it's wrong?I guess the question is: what would be a point in calling this method on a Float? A Float value is rarely exact in the sense that it rarely coincides with the real-world value which it models.
What if it had an (optional?) parameter for precision? I know in the
past I've wanted to know whether the value stored in a float looked
like an integer to a certain number of places.
I believe that would make it more clear that we're not necessarily
saying that the real-world value we're modeling is exactly an integer;
rather that it is near enough for our current purposes.
If optional, I suppose the default would be "as many places as are
represented by this float," or (self.to_i == self)
--
Matthew Kerwin, B.Sc (CompSci) (Hons)
http://matthew.kerwin.net.au/
ABN: 59-013-727-651
"You'll never find a programming language that frees
you from the burden of clarifying your ideas." - xkcd
Updated by regularfry (Alex Young) almost 12 years ago
On 29/10/12 22:12, alexeymuranov (Alexey Muranov) wrote:
Issue #6973 has been updated by alexeymuranov (Alexey Muranov).
Floats are precise, just like Integers are. Operations on floats are
not accurate, and that's where the confusion comes from. That's
inherent to the representation and something you've got to deal with
anyway, so I certainly don't see this test as making that problem worse.Your points is valid as long as we can distinguish a Float that includes
error from a Float that includes no error, such as, just created by a
Float literal, or by only accurate operations (no overflow, no indivisible
division, ...).
But in fact, we cannot distinguish them. We conservatively have to think
that any Float object includes an error, I think.So if I knowingly and correctly construct a calculation which cannot
contain such an error, Ruby should tell me that it's wrong?I guess the question is: what would be a point in calling this method on a Float? A Float value is rarely exact in the sense that it rarely coincides with the real-world value which it models.
I explained this upthread. Float values are always exact. Float
operations are not.
--
Alex
Feature #6973: Add an #integral? method to Numeric to test for whole-number values
https://bugs.ruby-lang.org/issues/6973#change-31933Author: regularfry (Alex Young)
Status: Assigned
Priority: Normal
Assignee: mrkn (Kenta Murata)
Category: core
Target version: next minorNumeric#integer? checks whether an instance is an Integer. It is often useful to check whether the value of a non-Integer variable is actually a whole number, and the #integer? method doesn't help here.
This patch adds Numeric#integral?, which performs this check.
Updated by alexeymuranov (Alexey Muranov) almost 12 years ago
regularfry (Alex Young) wrote:
So if I knowingly and correctly construct a calculation which cannot
contain such an error, Ruby should tell me that it's wrong?
Alex, can you give an example, please?
Updated by regularfry (Alex Young) almost 12 years ago
On 31/10/12 13:03, alexeymuranov (Alexey Muranov) wrote:
Issue #6973 has been updated by alexeymuranov (Alexey Muranov).
regularfry (Alex Young) wrote:
So if I knowingly and correctly construct a calculation which cannot
contain such an error, Ruby should tell me that it's wrong?Alex, can you give an example, please?
Trivially? x * 2.0 for x small enough not to overflow.
There's a more interesting vein of examples where this sort of thing
crops up if you google for "error-free transformations", like the 2Sum
and Fast2Sum algorithms.
--
Alex
Feature #6973: Add an #integral? method to Numeric to test for whole-number values
https://bugs.ruby-lang.org/issues/6973#change-32110Author: regularfry (Alex Young)
Status: Assigned
Priority: Normal
Assignee: mrkn (Kenta Murata)
Category: core
Target version: next minorNumeric#integer? checks whether an instance is an Integer. It is often useful to check whether the value of a non-Integer variable is actually a whole number, and the #integer? method doesn't help here.
This patch adds Numeric#integral?, which performs this check.