将科学计数法中的Ruby float转换为整数时,是否有任何数据丢失?

时间:2013-08-03 20:58:20

标签: ruby floating-point

例如,参加此IRB会议:

1.9.3-p385 :046 > float = func_that_creates_large_float
=> 1.5815450433041317e+51 
1.9.3-p385 :047 > float.to_i
=> 1581545043304131697954259018410479150921451567054848

我可以确定返回给我的整数表示与浮点数相同的值吗?我问主要是因为Ruby文档将Float类中的to_i方法描述为“返回将截断为整数的浮点数”。 “截断”这个词突然出现在我身上。

编辑:我认为描述我的情况会清楚说明我为什么要问这个问题。我试图取一个大整数的立方根,我知道它也会产生一个整数。立方根函数使用浮点数进行计算,将结果作为浮点数给出。我需要非科学符号值,不知道如何处理这个问题。

谢谢。

2 个答案:

答案 0 :(得分:1)

相反,(确定性但无意义的)数据已添加(如您在代码示例中所示)。您没有丢失任何信息。但它的价值并不相同。

您的float精度约为17位小数,您的int突然精确到51位数。这与Floating Point Arithmetic: Issues and Limitations有关。那"精度"由于十进制浮点值的二进制表示而产生,这导致了"发明"整数中的一系列数字。

考虑以下内容(在Python中,遵循相同的规则,可能所有编程语言都具有任意长整数):

>>> a = int(1.5815450433041317e+51)
>>> a
1581545043304131697954259018410479150921451567054848
>>> b = a + 10000000000000000
>>> a == b
False
>>> float(a) == float(b)
True
>>> a == 1.5815450433041317e+51
True

在Python中,decimal module将是一个很好的妥协:

>>> from decimal import Decimal, getcontext
>>> a = str(29873409852730498572309485723**3)  # just an arbitrary number
>>> getcontext().prec = 100
>>> cube = Decimal(a)
>>> cube ** Decimal("0.333333333333333333333333333333333333333333333333333333333
33333333333333333333")
Decimal('29873409852730498572309485722.99999999999999999999999999999999999999999
999998041297117811390088120595')

(由于将1/3表示为十进制浮点数的问题仍然存在轻微的舍入错误,但结果很明显,不是吗?)

答案 1 :(得分:1)

显然,如果有效数字的数量大于指数部分的数量,那么在浮动到整数转换期间,您将丢失信息。

Ruby(与许多其他编程语言一样)没有可变精度浮点。相反,有效数字的数量固定为常数Float::DIG,默认为15。这意味着,如果浮点数小于10 ^ 15,那么在浮点数到整数转换期间,您将丢失信息。

<小时/> 关于整数中立方根的问题,最好在Rational类中进行计算。您不必担心截断。

(8 ** Rational("1/3")).to_r
# => (2/1)