首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Ruby和stdin整数

Ruby和stdin整数
EN

Stack Overflow用户
提问于 2017-06-28 15:02:27
回答 2查看 245关注 0票数 3

我有:

代码语言:javascript
运行
复制
$ ruby -v
ruby 2.0.0p648 (2015-12-16 revision 53162) [universal.x86_64-darwin16]

假设您有一个整数序列,1..n,一个红宝石新手会把这个序列加起来如下:

代码语言:javascript
运行
复制
$ ruby -e 's=0
     for i in 1..500000
        s+=i
     end
     puts s'
125000250000

现在假设我有来自stdin的相同序列

代码语言:javascript
运行
复制
$ seq 1 500000 | ruby -lne 'BEGIN{s=0}
                            s+=$_.to_i
                            END{puts s} '   
125000250000

到目前一切尚好。

现在,终端价值从50万增加到500万:

代码语言:javascript
运行
复制
$ ruby -e 's=0
         for i in 1..5000000
            s+=i
         end
         puts s'
12500002500000   <=== CORRECT

$ seq 1 5000000 | ruby -lne 'BEGIN{s=0}
                             s+=$_.to_i
                             END{puts s} '
500009500025     <=== WRONG!

它产生了一个不同的总和。

awkperl都用相同的顺序产生正确的结果:

代码语言:javascript
运行
复制
$ seq 1 5000000 | awk '{s+=$1} END{print s}'
12500002500000
$ seq 1 5000000 | perl -nle '$s+=$_; END{print $s}'
12500002500000

为什么ruby产生不正确的和?我不认为它会溢出,因为awkperl在相同的输入上正确工作。

Conclusions:

谢谢大卫·奥尔德里奇的诊断。

  1. OS和BSD seq转换为1,000,000的浮点输出,而GNU seq则支持任意精度整数。OS seq作为大于1,000,000整数的源是无用的。OS X上的示例: $ seq 999999 1000002 999999 1e+06 1e+06 1e+06
  2. ruby方法.to_i静默地将部分字符串转换为整数,在本例中这就是“bug”。示例: :002:0>‘5E+06’..to_i #=> 5
  3. 脚本中的“正确”行是要么使用$_.to_f.to_i来使用浮点数,要么使用Integer($_)来避免脚本无声地失败。awkperl将5e+06解析为浮点数,而ruby不隐式地: $ echo '5e+06‘ruby awk '{print $1+0}’5000000美元echo '5e+06‘\ruby -lne 'print $_.to_i+0’5
  4. 感谢Stefan Schüler打开了一个关于.to_i行为的Ruby .to_i
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-06-28 15:18:26

我不确定这是否是百分之百的答案,但我注意到:

代码语言:javascript
运行
复制
seq 500000 500001 | ruby -lne 'BEGIN{}
                             puts $_
                             END{} '
500000
500001

..。但是..。

代码语言:javascript
运行
复制
seq 5000000 5000001 | ruby -lne 'BEGIN{}
                             puts $_
                             END{} '
5e+06
5e+06

..。因此,#to_i将值转换为整数的“轻松”方法仍然有效.

代码语言:javascript
运行
复制
seq 5000000 5000001 | ruby -lne 'BEGIN{}
                             puts $_.to_i
                             END{} '
5
5

..。但是更严格的#to_int不会

代码语言:javascript
运行
复制
seq 5000000 5000001 | ruby -lne 'BEGIN{}
                             puts $_.to_int
                             END{} '
-e:2:in `<main>': undefined method `to_int' for "5e+06":String (NoMethodError)

编辑:我还注意到:

代码语言:javascript
运行
复制
seq 5000000 5000001

5e+06
5e+06

因此,必须将-f标志传递给seq以获得整数格式。

再次编辑:

最后答案:

代码语言:javascript
运行
复制
seq -f %f 1 5000000 | ruby -lne 'BEGIN{s=0}
                                  s+=$_.to_i
                                 END{puts s} '

12500002500000
票数 5
EN

Stack Overflow用户

发布于 2017-06-30 09:55:53

为了解释e-表示法输出,seq的OS手册页给出了一些见解:

使用printf(3)样式的格式打印每个数字。..。默认情况是%g

因此,seq的输出相当于Ruby的:

代码语言:javascript
运行
复制
sprintf('%g', 100000)
#=> "100000"

sprintf('%g', 1000000)
#=> "1e+06"
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44806216

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档