难以理解/可视化 SICP 流汉明数程序

2023-12-09

我基本上陷入了 SICP 练习 3.56 的困境。问题是这样的:

练习3.56。 R. Hamming 首先提出的一个著名问题是,按升序且不重复地枚举除 2、3 或 5 之外没有质因数的所有正整数。一种明显的方法是简单地测试每个整数反过来看看它是否还有除 2、3 和 5 之外的任何因子。但这非常低效,因为随着整数变大,符合要求的整数越来越少。作为替代方案,让我们将所需的数字流称为 S 并注意以下有关它的事实。

  • S begins with 1.
    • (scale-stream S 2) 的元素也是 S 的元素。
    • 对于(scale-stream S 3)和(scale-stream 5 S)也是如此。
    • 这些都是S的要素。

现在我们要做的就是结合这些来源的元素。为此,我们定义了一个过程 merge,它将两个有序流组合成一个有序结果流,从而消除重复:

(define (merge s1 s2)
   (cond ((stream-null? s1) s2)
         ((stream-null? s2) s1)
         (else
          (let ((s1car (stream-car s1))
                (s2car (stream-car s2)))
            (cond ((< s1car s2car)
                   (cons-stream s1car (merge (stream-cdr s1) s2)))
                  ((> s1car s2car)
                   (cons-stream s2car (merge s1 (stream-cdr s2))))
                  (else
                   (cons-stream s1car
                                (merge (stream-cdr s1)
                                       (stream-cdr s2)))))))))

然后可以通过 merge 构造所需的流,如下所示:

(define S (cons-stream 1 (merge <??> <??>)))

在上面标记的地方填写缺少的表达式。

在这个特定问题之前,我已经能够使用信号处理框图来可视化和理解这些隐式流定义,并将原始流反馈给过程。

但我基本上已经遇到了这个特定问题,我已经查找了解决方案,但我发现无法想象该解决方案在我的头脑/论文中如何工作。

有没有什么技巧可以帮助我们理解此类问题并提出解决方案?

这是有效的解决方案:

(define S 
  (cons-stream 1 (merge (scale-stream S 2)
                        (merge (scale-stream S 3)
                               (scale-stream S 5)))))

提前致谢。


作为正确命名的问题,merge不应该删除重复项,因为它的名字表明它是mergesort这应该保护它们。Union是此类操作的更好名称,它通过增加唯一数字列表来表示集合(此处),它应该通过删除只能来自的重复项来保留该约束both其论点。

回到问题本身,我们把它象征性地写成

S235 = {1} ∪ 2S235 ∪ 3S235 ∪ 5*S235

过早实施是万恶之母! (等等,什么?)我们甚至还不会尝试确定这些到底是如何发生的他们做自己的工作,甚至不按什么顺序。或者甚至有多少个术语:

S23 = {1} ∪ 2S23 ∪ 3S23

or even

S2 = {1} ∪ 2*S2

现在这看起来很简单。我们甚至可以假实现联盟A and B here simply首先,考虑所有元素A,然后——的B。在这里它会工作得很好,因为这里只有一个元素的左输入:

 {1} ----∪-->--->--S₂--.--->S₂
        /               \        
        \______*2_______/        
          ---<----<---         

这是如何运作的?1进入 combiner,先退出,无条件地(注意这个发现的需求很重要,因为如果必须立即检查它的两个参数,我们就会陷入无限循环,黑洞在 Haskell 行话中),被分成两部分. splitter,然后第一个副本1继续前进到输出点,而第二个副本1回到过去*2乘数,所得结果2输入返回这次在右边,无人反对左边的任何东西(此时已经是空的),并以同样的方式继续,所以2到达输出点,然后4, then 8等等等等。

换句话说,S₂包含所有元素{1};加上所有元素{1}那个经历了*2乘数一次;和两次;以及三次;等等——所有的权力2按递增顺序:

S2 = {1} ∪ 2*{1} ∪ 2*2*{1}                ;; == {1, 2, 4, 8, 16, 32, ...}
                 ∪ 2*2*2*{1}
                 ∪ 2*2*2*2*{1}
                 ∪ ..........

The two S₂图中的 是相同的,因为我们在分流点从它吸取的任何东西都不会影响它。

这不是很有趣吗?

那么我们如何去添加的倍数3到它?一种方法是

S23 = S2 ∪ 3*S23

 {1} ----∪-->--->--S₂--.---S₂----∪-->--->--S₂₃--.--->S₂₃
        /               \       /                \        
        \______*2_______/       \______*3________/        
          ---<----<---            ---<----<---         

Here 1 from S₂ enters the second combiner and proceeds to the output point S₂₃ as well as back through the *3 multiplier, turning into 3. Now the second has 2,4,8,... and 3,... as its inputs; 2 goes through as well as turning into 6. Next, has 4,8,16,... and 3,6,...; 3 goes through. Next, 4; etc., etc., and so on and so forth.

因此所有元素S₂是一部分S₂₃,但所有元素也是如此S₂那个经历了*3乘数一次、两次等等——所有的幂2 and 3按递增顺序相乘:

S23 = S2 ∪ 3*S2 ∪ 3*3*S2                   ;; = S2 ∪ 3*( S2 ∪ 3*S2 
                ∪ 3*3*3*S2                 ;;               ∪ 3*3*S2 
                ∪ 3*3*3*3*S2               ;;               ∪ 3*3*3*S2 
                ∪ ..........               ;;               ∪ ........ )   !!

为什么顺序递增?如何?为什么,这就是责任!你好,another 发现的需求。无论从任一侧进入它,它都必须先产生较小的元素,然后再产生较大的元素。

如果两者相等该怎么办?在这个方案中,我们是否需要关心这个问题?这会发生吗?

不可以。所以我们可以实施 here as a merge,不作为union (but 记住第一个发现的需求! ——现在还有效吗?需要吗?随着新病例的增加). Merge应该比union因为它不关心平等的情况。

对于的倍数5还?我们继续,作为

S235 = S23 ∪ 5*S235

 {1} ----∪-->--->--S₂--.---S₂----∪-->--->--S₂₃--.---S₂₃----∪-->--->--S₂₃₅--.--->S₂₃₅
        /               \       /                \         /                 \ 
        \______*2_______/       \______*3________/         \_______*5________/ 
          ---<----<---            ---<----<---                ---<----<---     
  • 这是否描述了书中的代码? _______
  • 这是否描述了一个比书中的代码快大约两倍的代码? _______
  • 为什么它比书中的代码快两倍左右? _______
  • 这个回答有吗your问题? _______
  • 这有帮助吗you回答你的问题吗? _______

(填空)。

也可以看看:

  • 无限生成汉明序列的最新技术

本书代码的信号处理框图是:

                                  1 --->---\
                                             cons-stream ->-- S ---.---> S
    /----->---->--- *2 --->---\            /                       |
   /                            union ->--/                        /
  .-->-- *3 -->--\            /                                   /
  |                union ->--/                                   /
  .-->-- *5 -->--/                                              /
  \                                                            /
   \__________<__________<__________<_________<_______________/

其中删除重复项的“联合”被称为merge在书里。

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

难以理解/可视化 SICP 流汉明数程序 的相关文章

随机推荐

  • InternalsVisibleTo 属性不起作用

    我正在尝试使用InternalsVisibleToassembly 属性 使 NET 类库中的内部类对我的单元测试项目可见 由于某种原因 我不断收到一条错误消息 MyClassName 由于其保护级别而无法访问 两个程序集都已签名 并且我在
  • 将表单结果从联系表单 7 导出到 PDF (fPDF)

    我正在尝试将用户在 WordPress 中的联系表单 7 中输入的值通过 fpdf 导出为 PDF 这就是我所设置的 我可以生成 PDF 但没有从表单动态生成的值 函数 php add action wpcf7 before send ma
  • 角度 $setPristine() 不起作用

    我正在尝试使用 Angular 的内置表单函数 特别是setPristine 清除用户提交时的表单 我的控制器可以访问 scope newForm 我的形式 及其所有方法 但正在运行 scope newForm setPristine 没有
  • Stringify C 预处理器

    这是我的第一篇文章 所以如果我太含糊或提供了每个人都会直观地假设的信息 请告诉我 我对写作很陌生C我只是想更好地了解预处理 我正在编写一个简单的程序 可以使用直接从控制台接收参数gcc Wall std c99 DSEED argument
  • 如何在 JFreechart 中获取点的菱形形状

    我需要在 JFreechart 中的时间序列上获得 A 菱形形状 但我无法做到这一点 有人可以指导应该在下面的代码中添加哪些代码来实现钻石形状点以及如何更改线条的颜色吗 该程序使用 rs 和 stmt 以及其他从数据库派生并在其他地方定义的
  • Firebase 实时数据库写入/上传数据是否收费?

    还有一个问题与这个类似here 但答案并不能满足我的问题 我具体询问实时数据库中的写入操作 我知道读取 下载将被计费 但是 那实时定价没有提到 上传 或 写入 它只提到 下载 存储和同时连接 但是上传 又名写入 怎么样 这是否意味着它是免费
  • 创建参考 y 值的垂直堆叠条形图(岩性/地层柱)

    我想制作一个堆积条形图 其中 y axis md litho x axis litho 数据 我已经尝试使用我修改过的代码来实现它另一个问题在堆栈溢出上 path pd ExcelFile F Backup JN Litologi lito
  • 在 Javascript 中覆盖 undefined 和 IIFE

    我一直在阅读 你不懂Js 系列 并发现了这一点 此模式的另一个应用解决了默认值的 次要利基 问题undefined标识符的值可能会被错误地覆盖 从而导致意外结果 通过命名参数undefined 但不为该参数传递任何值 我们可以保证undef
  • 单击“管理解决方案的 nuget 包”Visual Studio 2015 时 Nuget 包管理器崩溃

    因此 当单击 管理解决方案的 nuget 包 按钮时 我的 Visual Studio 崩溃了 如果我选择调试我会收到此消息 PresentationFramework dll 中发生 System Windows Markup XamlP
  • 之间的区别

    当我使用malloc在 C 程序中 我收到警告 warning incompatible implicit declaration of built in function malloc enabled by default 然后我可以包括
  • 用于提取特定 XML 标记值的批处理文件

    我需要一个批处理文件来检索Data仅标记值 不带标记名称 并将其写入 txt 文件 该文件可能具有比列出的更多的 XML 标签 所以输出应该是 资本收益是美国收入差距的关键因素 而胜利者背后的力量是我们经济体系的全部准则 如果您想平衡在美国
  • 使用 EL 和 JSTL 访问枚举值

    我有一个名为 Status 的枚举 定义如下 public enum Status VALID valid OLD old private final String val Status String val this val val pu
  • Spring - 如何对单个资源应用投影?

    我正在尝试对名为的实体类应用投影Institute 我定义了以下投影类 Projection name instituteProjection types Institute class public interface Institute
  • 使用 I-Beacon 的室内导航 - 准确性正在迅速变化

    我正在使用 I Beacon 做一个室内导航应用程序 为此 我使用信标给出的精度 但情况正在迅速改变 由于该值正在变化 因此即使当我处于静态时 必须计算的用户位置的 X 和 Y 坐标也会变化 因此 请帮助我在我不移动时使精度保持不变 提前致
  • 在 Java 中如何在修改对象时迭代该对象? [复制]

    这个问题在这里已经有答案了 可能的重复 Java 高效相当于在迭代集合时进行删除 在java中迭代集合时从集合中删除项目 我正在尝试循环HashMap Map
  • 运行时 GPU 执行还是 CPU 执行?

    我觉得必须有一种方法来编写代码 使其可以在 CPU 或 GPU 中运行 也就是说 我想编写一些具有 例如 CPU FFT 实现的东西 如果没有 GPU 该实现可以执行 但当 GPU 存在时默认为 GPU FFT 我无法提出正确的问题来让互联
  • 我的 JavaScript 代码只打印一行。我需要它打印 10 行,每行 20 个字符。

    这是一个抛硬币随机发生器 我需要打印 10 行 20 列 这就是我被困住的地方 每次我单击按钮时 我的代码似乎都会正确随机化 它显示 20 列 但我似乎无法让它打印第二行 这可能是一些简单的事情 我只是没有抓住 任何事情都会受到赞赏 Jav
  • 确定 viewWillAppear 是来自打开应用程序,还是取消选择模式

    我目前正在初始屏幕上加载应用程序加载数据 在我看来这会发生 我还有一个在此屏幕上弹出的模式 关闭时执行与 viewWillAppear 中加载数据相同的逻辑 如何仅在应用程序打开时加载数据 而不是在模式关闭时加载数据 UIViewContr
  • std::vector 中的数据存储是连续的吗? [复制]

    这个问题在这里已经有答案了 我有一个字符向量 我想将其内容作为 char 传递给另一个函数 void foo boost shared ptr
  • 难以理解/可视化 SICP 流汉明数程序

    我基本上陷入了 SICP 练习 3 56 的困境 问题是这样的 练习3 56 R Hamming 首先提出的一个著名问题是 按升序且不重复地枚举除 2 3 或 5 之外没有质因数的所有正整数 一种明显的方法是简单地测试每个整数反过来看看它是