首页 > 解决方案 > Ruby 中的浮点值是立即数吗?

问题描述

根据Ruby FAQfixnum(hold integer)booleannil是立即值。在我的理解中,一个拥有立即数的对象总是完全相同的,不管它被分配了多少个变量。这在 Ruby 中很容易验证:

# Immediate values
i1 = 1
i2 = 1
i1.object_id  # the same as i2's id
i2.object_id  # the same as i1's id

# Not immediate values
s1 = "1"
s2 = "1"
s1.object_id  # NOT the same as s2's id
s2.object_id  # NOT the same as s1's id

float似乎也是即时值:

f1 = 2.1
f2 = 2.1
f1.object_id  # the same as f2's id
f2.object_id  # the same as f1's id

但是,我找不到任何float直接值的参考。Ruby 中的浮点值是立即数吗?如何float在 Ruby 中工作?

标签: rubyfloating-point

解决方案


Ruby 中不存在立即值的概念

现在,您可能会问“当Ruby没有立即值时,为什么Ruby常见问题解答谈论立即值?” 这个问题的答案是,不幸的是,Ruby 社区中的许多文档混淆了称为“Ruby”的编程语言的概念和许多 Ruby 实现之一,不幸的是,它也经常被称为“Ruby”,尽管它“官方”名称是“ YARV ”。

例如,如果您查看ISO/IEC 30170:2012信息技术 — 编程语言 — Ruby规范,您将发现没有提及立即值,无论是在该名称下,还是在任何其他名称下的类似概念。它们根本不存在。

另请注意有关链接到的立即值部分中的以下警告:

此部分或部分内容可能已过时或需要确认。

所以,我们有两个问题:

  1. 本节讨论Ruby 的一个特定实现,在众多实现中,但并没有说明这一点,并且
  2. 甚至特定于实现的信息也已过时。

在当前版本的 YARV 中,Fixnum不再存在。过去,Integer是一个具有两个具体子类的抽象类:FixnumBignum. Fixnums 是直接值,Bignums 不是。

但是,根据您是在 32 位还是 64 位中运行,完全相同的文字可能是 a Fixnum,即立即数,或者是 a Bignum。32 位Fixnum可以存储 31 位,64 位Fixnum可以存储 63 位。请注意,这仅适用于 YARV,不过,例如JRuby将32 位和 64 位平台上存储 64 位(不仅是 63 位) 。

如今,FixnumBignum不再存在,并且Integer是一个具体的类,而不是一个抽象的类。但是,实际上优化还在进行中:YARV在 32 位系统上仍然优化 31 位IntegerfixnumInteger ,在 64 位系统上优化为 63 位,JRuby仍然优化 64 位Integer

JRuby 优化Floats 已经很长时间了。在 JRuby 中,Floats 是立即数。然而,在 YARV 中,没有这样的优化。Floats 不是直接值。然而,最近,YARV 引入了flonum的概念。FlonumFloat适合 62 位的 s。Flonum是立即数。此外,此优化仅在 64 位平台上执行,在 32 位平台上完全禁用flonum 。

另请注意,FAQ 完全忽略了Symbol在许多实现(包括 YARV)中是立即值的 s。

所以,回答你的问题:

Ruby 中的浮点值是立即数吗?

不,也许。其中一些,有时。

不,Floats 不是 Ruby 中的直接值,如果“Ruby”是指“Ruby 编程语言”。Ruby语言没有立即值的概念。

也许,Floats 是 Ruby 中的直接值,也许不是,如果“Ruby”是指“所有现有 Ruby 实现的集合”。在某些实现中,在某些情况下,某些Float值可能是也可能不是立即值。

有些Floats 有时是直接值,如果“Ruby”是指“YARV”。在 64 位平台上,Floats 的一个子集是立即数,但不是全部。在 32 位平台上,没有一个是立即数。

这无关紧要

你只能通过改变它来判断一个值是否是立即的。但是,执行此类优化的所有值都是不可变的,不能有实例变量,也不能有单例方法或单例类。

因此,实际上不可能判断某物是否是直接值。这是一个私有的内部优化细节。

这意味着您可以完全忽略该概念,因为它无法使您的程序以不同的方式运行。

怎么样object_id

首先:Object#object_id是可憎的。它不应该存在。只需忘记您曾经听说过它。

它违反了面向对象的基本原则之一,即模拟另一个对象的对象应该与该对象无法区分。(同样适用于BasicObject#equal?。)

但其次,这是一个反例:

# frozen_string_literal: true

# Not immediate values
s1 = '1'
s2 = '1'

s1.object_id
#=> 60
# SAME as `s2`'s id

s2.object_id
#=> 60
# SAME as `s1`'s id

哎呀。我打破了你的测试:冻结String文字不是直接对象,但它们会自动重复数据删除。


推荐阅读