在Ruby中检查Float是否等效于整数值

wz1wpwve  于 2023-02-18  发布在  Ruby
关注(0)|答案(4)|浏览(126)

假设我有以下代码:

x = 0.8
y = 1.0

检查y是否等价于Integer的最佳方法是什么?目前我正在做的是:

y.to_int == y

这很有效但我觉得应该有更好的办法。

bgibtngc

bgibtngc1#

用1对该值进行mod,然后检查该值是否等于0。

if y % 1 == 0
xkftehaa

xkftehaa2#

靶区; DR

一般来说,当你不关心数值类型时,你应该使用==来比较数字,这应该是大多数时候。当你真正关心类型时,你应该使用从Numeric #eql?继承的对象相等比较。

最简单的事情可能工作

你可以只问一个数字对象它是否是一个整数。例如,Numeric #integer?让你问一个数字检查它自己并返回一个布尔值:

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

如果你关心的只是 * y * 是否是整数,那么这就是你要做的。

y = 1
y.integer?
#=> true

y = 1.0
y.integer?
#=> false

其他解决方案

如果你想做一些更复杂的事情,比如在相等比较中避免自动的Numeric类型转换,唯一真正的限制是你的想象力和你想在代码中清晰表达的想法。Numeric、Float、Integer、Object、String和其他类中有很多方法可以让你执行类型转换和严格的相等比较。下面是一些例子。

使用#eql?

使用各种方法转换为Integer,然后严格检查对象是否相等:

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)

是否检查带有#zero的余数?

如果要创建一个布尔表达式,而不使用==进行的自动数字转换,则可以使用从Numeric #zero?继承的类特定方法。例如:

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

将#ceil或#floor用于减法

如果对某些类型的数字,模运算无法完成,那么可以使用Float #ceil或Float #floor:

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

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

7lrncoxx3#

你可能根本不想这么做。浮点运算容易产生舍入误差,你认为得到6.0的一系列运算实际上可能得到5.9999999999999。在这种情况下,任何检查值是否为整数的操作都将失败。即使你可能希望它成功。通常比较浮点数和给定精度内的整数版本是更好的方法,比如if (x - x.to_i).abs < 0.001

wfveoks0

wfveoks04#

虽然有各种各样的方法可以做到这一点,但有一种方法在其他答案中没有提到,但对我来说似乎是直观的:

简单的解决方案

y == y.truncate

Monkey-patch添加:

您也可以将“monkey-patch“作为一个方法:

class Numeric
  def is_int?
    self == self.truncate
  end
end

之后您可以拨打:

y.is_int?

备注:

1.对于monkey-patch选项,请注意不要将y.is_int?y.integer?混淆,因为y.integer?是不同的(后者对于1是正确的,但对于1.0不是,而前者对于两者都是正确的)。
1.在某些情况下,数字的内部浮点表示可能会导致错误的结果(例如,(10*(0.2+0.1)).is_int?(在monkey-patch之后)返回false,因为10*(0.2+0.1)给出3.0000000000000004)。不管是好是坏,我认为这类问题的完整解决方案超出了本答案的范围,因为我不相信它会突然出现在你表达问题的特定方式中。对于任何人来说,这确实很重要,存在对这个问题的更详细的分析,例如here,应该在适当的时候参考。
1.您还可以选择不同的名称来代替is_int?--也许integer_equivalent?会更好?

相关问题