开发者

Checking if a Float is equivalent to an integer value in Ruby

Say I have the following code:

x = 0.8
y = 1.0

What's the best way of checking that y is equivalent to an Integer? At the moment I'm doing:

y.to_int == y

which works, but I feel like there should be a better way.开发者_JAVA技巧


You mod the value with 1, and check if the value equals 0.

if y % 1 == 0


TL;DR

Generally, you should use == to compare numbers when you don't care about the numeric type, which should be most of the time. When you really do care about the type, you should use the object-equality comparison inherited from Numeric#eql?.

The Simplest Thing That Could Possibly Work

You can just ask a numeric object if it's an integer. For example, Numeric#integer? lets you ask a number to check itself and return a Boolean value:

[1, 1.2, 1.02e+1].map(&:integer?)
#=> [true, false, false]

If all you care about is finding out whether y is an integer, then this is the way to go. Using your own examples:

y = 1
y.integer?
#=> true

y = 1.0
y.integer?
#=> false

Other Solutions

If you're trying to do something more complicated, like trying to avoid automatic Numeric type conversions in equality comparisons, the only real limit is your imagination and the idea you're trying to express clearly in your code. There are many methods in Numeric, Float, Integer, Object, String, and other classes that would allow you to perform type-conversations and strict equality comparisons. A few examples follow.

Use #eql?

Use various methods to convert to an Integer, and then check with strict object equality:

y = 1.2

# All of these will return false.
y.eql? y.truncate
y.eql? y.floor
y.eql? y.to_i
y.eql? Integer(y)

Check for Remainders with #zero?

If you want to create a Boolean expression without the automatic numeric conversions made by ==, you can use the class-specific method inherited from Numeric#zero?. For example:

(y % 1).zero?
y.modulo(1).zero?

Use #ceil or #floor with Subtraction

If modulo doesn't do the trick for you with certain types of numbers, then you can use Float#ceil or Float#floor:

y = 1.2
(y - y.floor).zero?
#=> false

y = 1.02e+1
(y.floor - y).zero?
#=> false


You probably don't even want to do that. Floating point arithmetic is subject to rounding errors, and a series of operations that you would think gives e.g. 6.0 may actually give 5.9999999999999 . In that case, any check that the value is integer will fail, even though you probably intended it to succeed. Normally it is a better approach to compare the float to an integer version within a given precision, like if (x - x.to_i).abs < 0.001.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜