再次感谢那些参与的人,并感谢您对这篇迟到的帖子的耐心等待。 每个人都能够完成挑战。 对于非 JMP 员工来说,最大的添加数字(约 200 万位数字)和最大的 1,000 位数字列表(约 2,000 个项目)挑战均被以下方法击败: @大卫_伯纳姆。 对于员工条目,5秒内添加的最大两个数字约为2200万( @brady_brady和@Craige_Hales )最大的列表大约有 61,500 个元素(挑战3 示例3.JSL )。 这些脚本已发布在下面。
以下是三个挑战的总得分:
让我们从涉及两个数字的运算开始。 挑战 3 示例 1 – Slow.JSL提供了与大多数条目类似的实现:
- 确定数字是否相同(加法)或相反(减法)。
- 解析数字字符串。
- 执行加法/减法运算。
- 连接结果以构建答案。
加法和减法运算是在单个函数还是多个函数中执行是一个风格问题,并且只影响程序的清晰度和可读性,而不影响执行时间。 然而,产生巨大差异的是如何解析输入数字并将其重新组合在一起。 在循环各个数字之前解析输入字符串(挑战 3 示例 1 – Faster.JSL )而不是在循环内,运算速度提高了约 5 倍(2.28 秒 vs. 2 个 16,000 位数字相加的 0.464 秒)。 通过将结果收集到列表中,然后连接末尾的项目,从循环内部删除单个字符串连接,从而将速度提高 10 倍以上(0.04054 秒) - 请参阅(挑战 3 示例 1 -fastest.JSL)。
在我们讨论如何使其更快之前,我们应该讨论在列表中添加数字。 几乎每个人都通过一次迭代列表中的一项,并将每一项添加到运行总计中来处理这个问题。 虽然这最终不是最快的方法,但它可以变得异常快(挑战 3 - Hales.JSL在 5 秒内添加了 51,000 个 1000 位数字)。 与大多数操作一样,提高速度的关键是在所有条件相同的情况下最大限度地减少操作数量。 在提供的示例中,挑战3 示例2.JSL ,解决方案是将进位/借位操作从每对数字一次设置减少到总共三组。 这是通过以下方式完成的:
- 将输入数字加载到两个矩阵中,一个用于正数,一个用于负数。
- 使用分别添加每个矩阵电压总和,对两个结果矩阵执行一组进位运算。
- 从较大的数字中减去较小的数字。 对结果执行一次借用操作。 最后的减法是使用上面讨论的二数算法来执行的。
通过在进位/借位操作期间一次考虑多于一位数字,可以使两位数和列表操作变得更快。 这在两个地方都完成了挑战 3 - Hales.JSL和挑战 3 - Brady.JSL 。 虽然自然倾向是用一个数字进行加/减/进位/借位,但只要不发生溢出,只要稍加巧妙,该过程就可以推广到尽可能多的数字。 在联合管理计划,对于两个数字的情况,这将是 14 位数字,并且14 – 楼层(Log10(列表大小– 1))数字, 在哪里列表大小在列表情况下,是输入列表中的项目数。 要理解为什么会这样,请回想一下溢出发生在大约 9e16 处。 将两个最大的 15 位数字(15 个 9)相加会导致溢出错误。 将两个最大的 14 位数字相加则不会。 类似地,当执行 11 到 100 次(准确地说是 91 次)时,将 9,999,999,999,999 添加到自身将导致溢出。
作为其工作原理的示例,请考虑添加三个数字,其中每个数字排列在 14 个寄存器中:
11 99999999999999
22 99999999999999
33 99999999999999
将第一个寄存器(14 个 9)的值相加得出
2 99999999999997
携带 2 并对第二个寄存器求和得到
68
最终的数字是
68 99999999999997
这种方法的应用在挑战3 示例3.JSL 。 添加两个 200 万位数字的平均处理时间从 4.7 秒缩短到 0.82 秒,速度提高了 5 倍以上。 额外的调整可以将速度提高 2 倍,如下所示挑战 3 - Hales.JSL和挑战 3 - Brady.JSL添加 10,000 个 1000 位数字所需的时间从 4.5 秒减少到 0.88 秒 (5 倍)。 这导致最快的列表添加方法。
2020 年 7 月 20 日:又修复了一个错误,这次是挑战3 示例3.JSL 。 添加了对所有三个示例 1 文件使用矩阵参数时的警告消息(直到示例 2 才实现)。
2020 年 7 月 17 日:我在挑战 3 示例 1 脚本中发现了另一个错误,所有三个错误均已得到修复和替换。
2020 年 7 月 16 日: 我更换了脚本挑战 3 示例 1 - Slow.JSL和挑战 3 示例 1 - Faster.JSL因为它们末尾包含一行会导致问题(它们引用了我用来测试代码的表)。 如果您已下载这些文件但尚未自行解决问题,请替换旧副本。