我的问题的症结如下:
irb(main):001:0> "5,280".to_f
=> 5.0
为什么Ruby会这样做?
我几乎可以理解"5,280".to_i == 5
,因为,
在某些语言环境中是十进制类型的分隔符,但是这里的精度损失令我感到困惑,尤其是因为{{ 1}}按预期返回"5.280".to_f
。
这只是一个错误吗?
重要的Ruby版本:
5.28
答案 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实现有效。在其他版本/实现中,可能有所不同。