Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/xamarin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby Fixnum#to#u的性能问题_Ruby - Fatal编程技术网

Ruby Fixnum#to#u的性能问题

Ruby Fixnum#to#u的性能问题,ruby,Ruby,我有以下算法(它搜索二进制表示也是回文的回文): 但如果我改变 while current <= @max string = current.to_s if string == string.reverse && current.to_s(2) == current.to_s(2).reverse 虽然我希望它会更快(所需的计算更少),但速度要慢两倍。同时#to#s不带参数按预期工作,如果我删除变量并执行两次计算: while cu

我有以下算法(它搜索二进制表示也是回文的回文):

但如果我改变

    while current <= @max
      string = current.to_s
      if string == string.reverse && current.to_s(2) == current.to_s(2).reverse
虽然我希望它会更快(所需的计算更少),但速度要慢两倍。同时#to#s不带参数按预期工作,如果我删除变量并执行两次计算:

    while current <= @max
      if current.to_s == current.to_s.reverse && current.to_s(2) == current.to_s(2).reverse

查看没有帮助理解它,除非问题与
else
条件分支有关。但我找不到任何问题。有人能解释为什么它是这样工作的吗(我使用的是MRI 2.1.1p76)?

在Ruby中,当你有一个类似

a && b
首先计算
a
,如果为false,则不计算
b

Base10回文很少,因此对于循环中的绝大多数循环,原始代码只检查
string==string.reverse
为false,然后继续循环的下一次迭代。因此,您只需对s执行一次
,对s(2)
执行一对


其他更改集都会更频繁地调用
到_
,从而做更多的工作,因此速度较慢。对我来说并不奇怪。

在您的原始版本中,
当前.to_s(2)
仅在
字符串==string.reverse
时计算,因为
&&
短路。相当于:

while current <= @max
  string = current.to_s
  if string == string.reverse
    string_b = current.to_s(2)
    if string_b == string_b.reverse

当前在探查器中分析此代码时,似乎大部分时间都花在
fix\u to_s()
C调用中

跳转到
fix_to_s()
的汇编代码中,我们看到它的大部分时间都花在一条指令上
movslq%edx,%rdx
。显然,
movslq
is将长(32位)移动到四位(64位)中

在您记忆
string2
的代码版本中,我们有3027个
movslq
样本,而在非记忆版本中,我们只有700个样本!有什么好处

在记忆版本中,似乎分配了更多的字符串对象,从而被ruby解释器释放。请注意创建和释放字符串对象所花费的时间

我使用
allocation\u stats
gem运行了一些关于对象分配的统计数据,它们表明在非记忆版本中分配的字符串确实更少。大约是总数的三分之二

test.rb字符串20032954

vs

test.rb字符串30010967

当您显式设置
string2=current.to_s(2)
时,他们必须为您分配内存,因为您可能需要它。但是,在您的代码中,它不一定要执行
&&
语句的第二部分,因此您可以完全避免这种分配


显然,增加分配量会在许多方面降低速度,包括使缓存未命中的可能性更大、垃圾收集更多,以及更多的
free()
ing和
malloc()
ing,这解释了为什么分配/时间的关系不是线性的。

trushkevich,你能报告这次修改的时间吗?我猜是2.52秒,是的,我忽略了。当然,当我写剧本时,我一直在思考这个问题。很抱歉,我接受了托德·阿古尼克的说法,只是因为他的名声不好。卡里·斯沃夫兰,仅运行一次脚本就很难准确判断,它的大小从
2.48s.
2.62s.
。我认为结论是,将
字符串b=current.to_s(2)
添加到
几乎没有什么区别。你有三个好答案,你真幸运。啊,当然!一点也不奇怪!不久前我写了这个脚本,后来当我打开文件时,出于某种原因,我没有考虑
&&
,并开始认为有什么问题。无论如何谢谢你!谢谢你的分析!很有帮助,而且赏心悦目。
Time spent: 6.25 s.
    while current <= @max
      if current.to_s == current.to_s.reverse && current.to_s(2) == current.to_s(2).reverse
Time spent: 4.17 s.
a && b
while current <= @max
  string = current.to_s
  if string == string.reverse
    string_b = current.to_s(2)
    if string_b == string_b.reverse