GHC 优化:Collat​​z 猜想

2023-11-24

我已经编写了代码欧拉计划的挑战 14, 同时Haskell and C++(ideone 链接)。他们都记得之前在数组中进行的任何计算。

Using ghc -O2 and g++ -O3C++ 的运行速度分别比 Haskell 版本快 10-15 倍。

虽然我知道 Haskell 版本可能运行得更慢,并且 Haskell 是一种更好编写的语言,但如果知道我可以对 Haskell 版本进行一些代码更改以使其运行得更快(理想情况下在 2 或 2 倍以内),那就太好了C++ 版本的 3)?


哈斯克尔代码在这里:

import Data.Array
import Data.Word
import Data.List

collatz_array = 
  let
    upperbound = 1000000
    a = array (1, upperbound) [(i :: Word64, f i :: Int) | i <- [1..upperbound]]
    f i = i `seq`
      let
        check_f i = i `seq` if i <= upperbound then a ! i else f i
      in
        if (i == 1) then 0 else (check_f ((if (even i) then i else 3 * i + 1) `div` 2)) + 1
  in a

main = 
  putStrLn $ show $ 
   foldl1' (\(x1,x2) (y1,y2) -> if (x2 >= y2) then (x1, x2) else (y1, y2)) $! (assocs collatz_array)

Edit:

我现在还使用未装箱的可变数组完成了一个版本。它仍然比 C++ 版本慢 5 倍,但已经有了显着的改进。代码在ideone上here.

我想知道可变数组版本的改进,使其更接近 C++ 版本。


您的(可变数组)代码存在一些问题:

  • 您使用折叠来查找最大链长度,因为数组必须转换为关联列表,这需要 C++ 版本不需要的时间和分配。
  • You use even and div用于测试 resp 除以 2。这些都很慢。 g++ 将这两个操作优化为更快的位操作(至少在据说更快的平台上),但 GHC 还没有执行这些低级优化,因此目前,它们必须手动完成。
  • You use readArray and writeArray。 C++ 代码中未完成的额外边界检查也需要时间,一旦处理了其他问题,这相当于运行时间的很大一部分(在我的机器上大约为 25%),因为已经完成了算法中有大量的读取和写入。

将其纳入实施中,我得到

import Data.Array.ST
import Data.Array.Base
import Control.Monad.ST
import Data.Bits

collatz_array :: ST s (STUArray s Int Int)
collatz_array = do
    let upper = 10000000
    arr <- newArray (0,upper) 0
    unsafeWrite arr 2 1
    let check i
            | upper < i = return arr
            | i .&. 1 == 0 = do
                l <- unsafeRead arr (i `shiftR` 1)
                unsafeWrite arr i (l+1)
                check (i+1)
            | otherwise = do
                let j = (3*i+1) `shiftR` 1
                    find k l
                        | upper < k = find (next k) $! l+1
                        | k < i     = do
                            m <- unsafeRead arr k
                            return (m+l)
                        | otherwise = do
                            m <- unsafeRead arr k
                            if m == 0
                              then do
                                  n <- find (next k) 1
                                  unsafeWrite arr k n
                                  return (n+l)
                              else return (m+l)
                          where
                            next h
                                | h .&. 1 == 0 = h `shiftR` 1
                                | otherwise = (3*h+1) `shiftR` 1
                l <- find j 1
                unsafeWrite arr i l
                check (i+1)
    check 3

collatz_max :: ST s (Int,Int)
collatz_max = do
    car <- collatz_array
    (_,upper) <- getBounds car
    let find w m i
            | upper < i = return (w,m)
            | otherwise = do
                l <- unsafeRead car i
                if m < l
                  then find i l (i+1)
                  else find w m (i+1)
    find 1 0 2

main :: IO ()
main = print (runST collatz_max)

以及时间(均为 1000 万):

$ time ./cccoll
8400511 429

real    0m0.210s
user    0m0.200s
sys     0m0.009s
$ time ./stcoll
(8400511,429)

real    0m0.341s
user    0m0.307s
sys     0m0.033s

看起来还不错。

重要的提示:该代码仅适用于 64 位 GHC(因此,特别是在 Windows 上,您需要 ghc-7.6.1 或更高版本,以前的 GHC 即使在 64 位 Windows 上也是 32 位),因为中间链元素超过 32 位范围。在 32 位系统上,必须使用Integer或 64 位整数类型 (Int64 or Word64)用于跟踪链,但性能成本极高,因为原始 64 位操作(算术和移位)是作为对 32 位 GHC 中 C 函数的外部调用来实现的(fast外部调用,但仍然比直接机器操作慢得多)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

GHC 优化:Collat​​z 猜想 的相关文章

  • SQL 中的最佳 LIKE 搜索

    我有一个零件数据库 我将不断查询该数据库以获取报价系统 零件数据库有超过 1 400 000 条记录 用户将开始输入零件号 他们希望系统能够在仅几个字符后找到这些零件号 因此我需要能够进行通配符搜索 例如 SELECT NeededFiel
  • JavaScript:document.getElementById 性能缓慢?

    我反复使用document getElementById很多关于commonCSS 元素 如果我创建一个global array存储我所有的document getElementById元素而不是每次重新获取元素 示例 而不是 docume
  • 我应该使用什么递归方案来重复有效的操作,直到其结果符合某些标准?

    也就是说 我要问的是一个循环 effectful Int gt IO Int effectful n do putStrLn Effect show n return n condition 3 final Int gt IO final
  • 管道中缺少 ResourceT 实例

    我在尝试使用时遇到奇怪的错误ResourceT http hackage haskell org package conduit 1 0 9 1 docs Data Conduit html t 3aResourceT来自管道 1 0 9
  • Haskell 中的类型化抽象语法和 DSL 设计

    我正在 Haskell 中设计 DSL 我想要进行赋值操作 像这样的东西 下面的代码只是为了在有限的上下文中解释我的问题 我没有类型检查 Stmt 类型 data Stmt forall a Assign String Exp a Assi
  • 使用 Haskell 将函数注入到 Java .class 文件中

    我使用 Haskell 编写了一个 Java 字节码解析器 它工作得很好 然而下一步让我完全难住了 我的 Haskell 程序需要修改 class 文件 以便在执行时 Java 程序打印 输入 此处的方法名称 在执行方法之前 并且 退出 此
  • 地图不是接受一个函数而列表返回一个列表吗?

    map2 List a gt b gt c gt a gt b gt c map2 List f map2 List f a as bs map f a bs map2 List f as bs 这是我的讲座中的一个示例 它尝试将二元函数应
  • 简单的秒差距示例会产生类型错误

    我正在尝试编译这个简单的秒差距代码 import Text Parsec simple letter 但我不断收到此错误 No instance for Stream s0 m0 Char arising from a use of let
  • 相当于 min() 的 rowMeans()

    我在 R 邮件列表上多次看到这个问题 但仍然找不到满意的答案 假设我有一个矩阵m m lt matrix rnorm 10000000 ncol 10 我可以通过以下方式获得每行的平均值 system time rowMeans m use
  • 如何使用 Haskell 提交 html 表单

    我知道如何使用http 管道 http hackage haskell org package http conduit 2 1 0包的 simplehttp 从 URL 检索页面 现在如果那样的话怎么办 网页有一个输入文本字段和一个提交按
  • 没有由文字“1”产生的 Num String 实例

    main do putStrLn myLast 1 2 3 4 myLast a gt a myLast x x myLast xs myLast xs 当我尝试运行此代码时 我收到此消息 没有由文字 1 产生的 Num String 实例
  • 如何处理或避免BlockedIndefinitelyOnSTM异常?

    我花了很多时间来解决我正在处理的应用程序中遇到的问题 该应用程序是一个 Web 应用程序 使用 scotty 公开 REST 端点 它使用一个TVar保持其更新的状态STM a由前端层触发的动作 由于该应用程序基于事件溯源原则 因此业务层生
  • 优化我的表现

    我正在开发一个使用 Zend Framework 1 11 Doctrine 2 一些 Symfony 2 组件以及其他工具和库的项目 我正在尝试使用 Xdebug 和 Webgrind 优化性能 我已经发现了一些瓶颈 例如解析 Ini 配
  • 生成尽可能最快的可执行文件

    我有一个非常大的程序 我一直在 Visual Studio 下编译 v6 然后迁移到 2008 我需要可执行文件尽可能快地运行 该程序大部分时间都花在处理各种大小的整数上 并且执行很少的 IO 显然 我会选择最大优化 但似乎可以做很多不属于
  • 错误优化器参数在 Keras 函数中不合法

    我使用以下代码来计算数据生成质量指标的拟合优度研究的概率标签 from sklearn model selection import StratifiedKFold from sklearn model selection import K
  • 数据类型变体之间的转换

    假设我想创建一种数据类型的两种变体 一种具有特定的构造函数 另一种没有它 否则它们是相同的 我想出了这个 LANGUAGE KindSignatures LANGUAGE DataKinds LANGUAGE GADTs data Foo
  • 打印数字时添加千位分隔符[重复]

    这个问题在这里已经有答案了 我真的不知道这个问题的 名称 所以它可能是一个不正确的标题 但问题很简单 如果我有一个数字 例如 number 23543 second 68471243 我想要它使print 像这样 23 54368 471
  • 为什么 Haskell (Hugs) 中的 Show 实例会导致堆栈溢出错误?

    下面是 Haskell 中的多态数据类型 由 Hugs 解释 我正在尝试创建一个 Show for Equality 的实例 实例声明表示 如果类型 a 在 Show 中 则相等 a 在 Show 中 它应该以 a b 的形式打印构造函数
  • 如何在 GHCJS 程序中定期执行操作?

    应该有人使用setInterval通过Javascript 或者使用一些更惯用的基于线程的解决方案 Using setInterval posed 一些挑战 https stackoverflow com questions 3357661
  • 使用属性和性能

    我正在优化我的代码 我注意到使用属性 甚至自动属性 对执行时间有深远的影响 请参阅下面的示例 Test public void GetterVsField PropertyTest propertyTest new PropertyTest

随机推荐

  • EnableSessionState = ReadOnly - 可能的副作用?

    我们有一个相当大的基于 Web 的解决方案 在 Net 4 5 上运行 最近 当我们检查一个性能问题时 系统似乎在任何给定时间 每个客户端 只服务一个请求 我们了解到造成这种情况的原因是会话状态 通过将 EnableSessionState
  • Android 应用在 Google Play 上自动更新和权限更改

    我知道 当至少添加一项新权限时 该应用程序将不会自动更新 用户必须手动更新它 当应用程序的权限发生更改时 您将可以 手动更新 删除权限怎么样 我当前的应用程序N版发行了 在下一个版本中 删除了一项权限 用户是否会N版获得自动更新 Edit
  • 如何在groovy中检索嵌套属性

    我想知道在 Groovy 中检索嵌套属性的最佳方法是什么 采用给定的对象和任意 属性 字符串 我想要这样的事情 someGroovyObject getProperty property1 property2 我很难找到其他人想要这样做的例
  • Toast.show() 未在模拟器中显示消息

    这似乎适用于 Android 6 Marshmallow 设备小米红米 3S 看起来像是模拟器问题 但在任何其他意义上它并不是真正的行为不当 我是Android开发的初学者 了解不多 我已经确认我的应用程序的通知已打开 眼镜 API 级别
  • 如何在 Pandas 中连接包含列表(系列)的两列

    我想连接 pandas 中的两列 每列由 1x4 元素的浮点列表组成 我想合并两列 使输出为 1x8 的向量 下面显示了数据框的片段 ue bs 1 27932459e 01 7 83234197e 02 3 24789420e 02 4
  • 使用 XSL 对 XML 文件进行哈希处理

    我正在尝试找到一种方法来 散列 XML 文件的内容 其根源是需要比较传入的一些文本节点与我希望确保校验和相同的文本节点 传入的文本节点已从表单提交返回 我需要确保它们没有更改 在合理范围内 排除冲突 建筑很糟糕 所以请不要问它 我被锁定在给
  • 如何将div垂直换行然后水平换行

    我需要水平显示我的网站中的搜索结果数据 我的网站遵循 Metro UI 方法 因此我希望数据水平流动而不是垂直流动 我的要求如下图所示 结果数据是动态的 我想首先根据父 div 高度垂直绘制 div 然后水平绘制 类似于WPF包裹面板的东西
  • 如何使用Spring表达式语言获取作业ID?

    我想使用 spring 表达语言获取工作 ID 我试过 jobExecutionContext jobId 但它不起作用 单独使用 SpEL 无法访问作业 ID 您可以使用 JobExecutionListener 将其添加到executi
  • System.currentTimeMillis() 如何获取时间

    是方法吗System currentTimeMillis 是否实现对底层操作系统进行系统调用以接收当前时间 我之所以这么问 是因为据我所知 该方法运行得相当快 只需要 6 个 CPU 时钟 但这没有意义 因为众所周知系统调用很慢 我在这里缺
  • 如何在 Android 上进行异步 URL 连接?

    我正在使用以下类连接到我的网络服务 我想让这个异步 我怎样才能做到这一点 package org stocktwits helper import java io BufferedReader import java io IOExcept
  • tmux 绑定分号

    有什么办法可以绑定吗 059 到 tmux 中的命令 默认绑定到last pane 但是 我想将其重新绑定到 select pane R 我尝试将以下内容放入我的 tmux conf 中 但似乎都不起作用 bind 059 select p
  • 在 Html.BeginForm() 中使用 DELETE 表单方法?

    我想尽可能使用适当的 HTTP 方法 在这种情况下 当单击按钮删除某些内容时 我想使用属性触发控制器操作 HttpDelete 但是 我似乎无法使用此方法创建表单 使用 Razor 语法 这FormMethod枚举没有选项Delete并且执
  • 如何在Makefile中添加#define?

    我有一个 C 项目 我需要在一些 CXX 文件中定义一个变量 我有近 800 个文件 我需要为其中 200 个文件定义一个变量 所以我想在 makefile 中定义它 那么我们怎样才能做到这一点呢 只需添加 Dxxx yy在命令行上 xxx
  • 在AppDelegate.m中获取屏幕当前显示的UIViewController

    目前的UIViewController屏幕上的应用程序需要通过设置一些徽章视图来响应来自 APN 的推送通知 但我怎样才能得到UIViewController在方法中application didReceiveRemoteNotificat
  • 每次点击取消按钮时,搜索栏都会向下跳一行

    我已经实现了一个 UISearchBar 来搜索来自外部 API 的项目目录 搜索功能按预期工作 但问题是 每次我按下搜索栏文本字段右侧的取消按钮时 整个搜索栏都会向下移动一行 看起来就像推动了整个搜索栏一样 表格视图也向下 因此 如果我在
  • Android studio:UnsatisfiedLinkError:findLibrary 返回 null - 加载本机库

    我正在 Android Studio 中制作一个使用两个库的应用程序 带有 Android 包装器和 jar 库的本机库 由于某种原因 如果将其他 jar 库编译到项目中 则本机库将不会加载 因此 如果我仅使用本机库运行应用程序 则一切正常
  • 如何让图片连续旋转? [关闭]

    很难说出这里问的是什么 这个问题模棱两可 含糊不清 不完整 过于宽泛或言辞激烈 无法以目前的形式合理回答 如需帮助澄清此问题以便重新打开 访问帮助中心 我的屏幕左上角有一个星星图像想要连续旋转 那么谁能告诉我如何让图片在 Mozilla F
  • 如何使用 FFT 绘制 wav 文件的频谱?

    注意 这不是重复的 除了相关问题之外 我还有其他特定要求 首先 我想绘制音频文件 wav 的频谱 就像 audacity 所做的那样 类似 如何从傅里叶变换绘制频谱 到目前为止我已经能够读取和写入 wav 文件了 但我的问题是我不确切知道需
  • python 函数中的动态默认参数

    我需要具有必须在函数运行时设置的默认参数的函数 例如空列表 从其他参数派生的值或从数据库获取的数据 我目前正在使用以下模式来处理此问题 def foo bar baz None baz baz if baz else blar Stuff
  • GHC 优化:Collat​​z 猜想

    我已经编写了代码欧拉计划的挑战 14 同时Haskell and C ideone 链接 他们都记得之前在数组中进行的任何计算 Using ghc O2 and g O3C 的运行速度分别比 Haskell 版本快 10 15 倍 虽然我知