【问题标题】:Why is this Ruby code far faster than the equivalent C++ code?为什么这个 Ruby 代码比等效的 C++ 代码快得多?
【发布时间】:2023-03-05 00:19:01
【问题描述】:

最近我一直在处理一些简单的项目 Euler 问题并用 Ruby 和 C++ 解决它们。但是对于关于 Collat​​z 猜想的Problem 14,我的 C++ 代码运行了大约半个小时才终止它,但是当我将代码翻译成 Ruby 时,它在 9 秒内就解决了。

这种差异让我难以置信 - 我一直被认为 C++ 几乎总是比 Ruby 快,尤其是在数学处理方面。

我的代码如下。

C++:

#include <iostream>

using namespace std;

int main ()
{
    int a = 2;
    int b = 2;
    int c = 0;
    while (b < 1000000)
    {

        a = b;
        int d = 2;
        while (a != 4)
        {
            if (a % 2 == 0)
                a /= 2;
            else
                a = 3*a + 1;
            d++;
        }
        if (d > c)
        {
            cout << b << ' ' << d << endl;
            c=d;
        }
        b++;
    }
    cout << c;
    return 0;
}

运行时间 - 老实说,我不知道,但这真的很长。

和鲁比:

#!/usr/bin/ruby -w

    a = 0
    b = 2
    c = 0
    while b < 1000000
        a = b;
        d = 2
        while a != 4
            if a % 2 == 0
                a /= 2
            else
                 a = 3*a + 1
            end
            d+=1
        end
        if d > c
            p b,d
            c=d
        end
        b+=1
    end
    p c

运行时间 - 大约 9 秒。

知道这里发生了什么吗?

附:在达到 100,000 之前,C++ 代码的运行速度比 Ruby 代码快很多。

【问题讨论】:

  • 将 endl 更改为 "\n",因为它执行流的刷新并且无缓冲的 IO 真的很慢。
  • 如何编译 C++?
  • 可以,但是当它达到更高的数字时,打印之间的间隔可能长达几分钟,并且 endl 和 "\n" 的差异可以忽略不计
  • 我喜欢这个问题,因为假设不存在。展示了很多关于假设的内容!
  • 这段代码不等价,你甚至没有发布你的编译器设置。

标签: c++ math


【解决方案1】:

你正在溢出int,所以它没有终止。在您的 c++ 代码中使用 int64_t 而不是 int。 您可能需要为此添加 stdint.h..

【讨论】:

  • 据我所知,没有明显区别
  • 改进你的答案,解释他为什么会溢出 int。
  • buuuut,看起来 unsigned long 成功了,而且在 0.539 秒内。我想我应该对数据类型做更多的研究。
  • 具体来说,当a 大到足以溢出该循环中的数学运算时,while (a != 4) 将永远不会完成。
  • 更具体地说,当 b=901118 时的循环似乎达到了极限。
【解决方案2】:

在您的情况下,问题是 C++ 实现中的错误(数字溢出)。

但是请注意,在一些内存中进行交易可以获得比您正在做的更快的结果...

提示:假设您发现从数字 231 开始需要 127 步才能结束计算,并假设从另一个数字开始经过 22 步后您会到达 231...您还需要执行多少步?

【讨论】:

  • 是的,我想过在 d > 100 时将值保存到一个数组中,但后来我想,我真的要检查一个大数组,以检查每一个小于一百万的数字的每次迭代吗?我想如果我保持一切排序并使用二进制搜索并且只检查一次'a'低于阈值(可能是'b')它会使其运行得更快,但是当它在半秒内解决时不会吸引我,尽管如果这是一个更大的程序的一部分并且经常被调用,我会这样做
  • 如何将b 的计数存储到count[b] 中?无需“搜索”;-)
  • 整数溢出真的是C++实现中的一个错误吗?这不是未定义的行为吗?
  • @AlvinWong:这是算法实现中的一个bug。该错误没有考虑到这些数字会发生整数溢出。用 C 或 C++ 编写时,您根本不希望发生整数溢出,如果这样做,那么您的代码是错误的。
【解决方案3】:

对于 32 位算术,C++ 代码在 a = 3*a + 1 上溢出。使用带符号的 32 位算术,问题变得更加复杂,因为 a /= 2 行将保留符号位。

这使得a 更难等于 4,事实上,当b 达到 113383 时,a 溢出并且循环永远不会结束。

使用 64 位算术没有溢出,因为 a 在 56991483520 处达到最大值,而 b 为 704511。

不看数学,我推测无符号 32 位算术将“可能”工作,因为乘法和无符号除法都将以 2^32 为模。鉴于程序的运行时间很短,值不会覆盖太多的 64 位频谱,所以如果一个值等于 4 模 2^32,它“可能”实际上等于 4。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-26
    • 1970-01-01
    • 2014-02-19
    • 2011-08-22
    • 2021-01-24
    • 1970-01-01
    相关资源
    最近更新 更多