为什么Ruby会错误地将带有逗号的字符串解析为浮点数?

时间:2018-11-08 19:16:04

标签: ruby floating-point

我的问题的症结如下:

irb(main):001:0> "5,280".to_f
=> 5.0

为什么Ruby会这样做?

我几乎可以理解"5,280".to_i == 5,因为,在某些语言环境中是十进制类型的分隔符,但是这里的精度损失令我感到困惑,尤其是因为{{ 1}}按预期返回"5.280".to_f

这只是一个错误吗?

重要的Ruby版本:

5.28

3 个答案:

答案 0 :(得分:5)

fine 2.3.7 manual(但current docs说同样的话):

  

to_f→浮动
  返回将str中的前导字符解释为浮点数的结果。有效数字后的多余字符将被忽略。如果str开头没有有效数字,则返回0.0。此方法永远不会引发异常。

所以"5,280".to_f确实在做应该做的事情。直到(但不包括)逗号的所有内容都是有效数字,多余的字符(在这种情况下为",280")将被忽略。结果与调用'5'.to_f相同。

这不是错误,这是预期的行为并已记录在案。从至少Ruby 1.8.6开始,这就是String#to_f的行为。

答案 1 :(得分:1)

我不认为这是一个错误,我认为这与Ruby在调用to_f时考虑字符串的哪一部分有关。

Ruby会查看从左边开始的字符串,任何0-9的字符,第一个小数点以及后面的0-9的字符都将匹配并尝试转换为浮点数。右边的任何内容都会被忽略。

如果没有字符符合该条件,则返回0.0。

https://apidock.com/ruby/String/to_f

示例:

>>'5.5'.to_f 
=> 5.5

>>'5.5stuff'.to_f 
=> 5.5   

>>'5.stuff5'.to_f 
=> 5.0

>>'5,5'.to_f 
=> 5.0

>>'stuff5.5'.to_f 
=> 0.0

答案 2 :(得分:1)

Ruby只需调用strtod C函数https://github.com/ruby/ruby/blob/38caab29bc759be2694013fc3930116e64fcc1d4/object.c#L3278

d = strtod(p, &end);

和strtod函数具有以下内容:

/*
 * Count the number of digits in the mantissa (including the decimal
 * point), and also locate the decimal point.
 */

decPt = -1;
for (mantSize = 0; ; mantSize += 1)
{
c = *p;
if (!isdigit(c)) {
    if ((c != '.') || (decPt >= 0)) {
    break;
    }
    decPt = mantSize;
}
p += 1;
}

https://opensource.apple.com/source/tcl/tcl-10/tcl/compat/strtod.c

根据if ((c != '.') || (decPt >= 0)) { break;  strtod如果找到任何非点符号则停止,例如:

irb(main):002:0> "2;58".to_f
=> 2.0
irb(main):003:0> "2@58".to_f
=> 2.0
irb(main):004:0> 

UPD:此方法对mri 2.6 ruby​​实现有效。在其他版本/实现中,可能有所不同。