纵横比 - 为什么 Ruby 的 Rational 类对待字符串参数与数字参数不同?



我使用ruby的Rational库来转换宽度&图像与长宽比的高度。

我注意到字符串参数与数字参数的处理方式不同。

>> Rational('1.91','1')
=> (191/100)
>> Rational(1.91,1)
=> (8601875288277647/4503599627370496)
>> RUBY_VERSION
=> "2.1.5"
>> RUBY_ENGINE
=> "ruby"

仅供参考1.91:1是Facebook为其平台上的图像推荐的宽高比。

像191和100这样的值比8601875288277647和4503599627370496更方便存储在我的数据库中。但在决定使用哪种方法之前,我想先了解这种差异的来源。

Rational测试套件似乎没有涵盖这个确切的情况。

免责声明:这只是一个有根据的猜测,基于一些如何实现这样一个壮举的知识。

正如Kent Dahl已经说过的,float是不精确的,它们有一个固定的精度,这意味着1.91实际上是1.910000000000000000001或类似的东西,ruby"知道"应该显示为1.91。

"1.91"则是一个字符串,基本上是一个字符数组:'1','。', '9', '1'.

这就是说,这是你需要做的,从浮点数中构建有理数:

  1. 去掉。(数学上通过分子和分母乘以10^x,或者乘以10的次数,因为后面有数字。)
  2. 求最大公分母(gcd)
  3. 用gcd
  4. 除数和数

第1步对于Float和String有一点不同:

  • Float,我们将不得不与10^x相乘,其中x(由于精度)不是2(正如人们认为的1.91),而是更像16(记住:1.9100…1)。
  • 对于String,我们可以将其转换为浮点数并执行相同的技巧,但是嘿,有一种更简单的方法:我们只需计算点后面的字符数(这是2),删除点并将dom乘以10^2…这不仅更简单,而且更精确。

在应用步骤3时,大数字可能会再次消失,这就是为什么在处理浮点数的有理数时不会总是得到那些奇怪的结果。

TLDR:数字将根据参数是String或FLoat而不同地构建。浮点数可以产生很长的数字,因为精度。

Float 1.91存储为具有给定精度的双精度数,受二进制表示的限制。等效的Rational对象尽可能地保持这种精度,因此它是巨大的。没有办法将1.91完全存储在双精度类型中,但是您得到的值对于大多数用途来说已经足够接近了。

对于String,它代表了一个不同的值——确切的值1.91——并且当您创建Rational时,它会更好地保留它。它比Float更正确,UT需要更长的时间来进行计算。

这类似于1.0/3的问题,因为它"永远持续"0.333333…等等,但是Rational可以精确地表示它。

相关内容

  • 没有找到相关文章

最新更新