代码高尔夫:Collatz 猜想
受到 http://xkcd.com/710/ 的启发,这里有一个代码高尔夫。
挑战
给定一个大于 0 的正整数,打印出该数字的冰雹序列。
冰雹序列
有关更多详细信息,请参阅维基百科。
- 如果数字是甚至,将其除以二。
- 如果数字是奇数,则将其增加三倍并加一。
对产生的数字重复此操作,直到达到 1。(如果在 1 之后继续,则会进入 1 -> 4 -> 2 -> 1...
的无限循环)
有时代码是最好的解释方式,所以这里有一些来自维基百科的代码。
function collatz(n)
show n
if n > 1
if n is odd
call collatz(3n + 1)
else
call collatz(n / 2)
这段代码有效,但我添加了一个额外的挑战。 程序不能容易发生堆栈溢出。所以它必须使用迭代或尾递归。
另外,如果它可以计算大数并且该语言尚未实现它,则可以获得加分。 (或者如果您使用固定长度整数重新实现大数支持)
测试用例
Number: 21
Results: 21 -> 64 -> 32 -> 16 -> 8 -> 4 -> 2 -> 1
Number: 3
Results: 3 -> 10 -> 5 -> 16 -> 8 -> 4 -> 2 -> 1
此外,代码高尔夫必须包含完整的用户输入和输出。
Inspired by http://xkcd.com/710/ here is a code golf for it.
The Challenge
Given a positive integer greater than 0, print out the hailstone sequence for that number.
The Hailstone Sequence
See Wikipedia for more detail..
- If the number is even, divide it by two.
- If the number is odd, triple it and add one.
Repeat this with the number produced until it reaches 1. (if it continues after 1, it will go in an infinite loop of 1 -> 4 -> 2 -> 1...
)
Sometimes code is the best way to explain, so here is some from Wikipedia
function collatz(n)
show n
if n > 1
if n is odd
call collatz(3n + 1)
else
call collatz(n / 2)
This code works, but I am adding on an extra challenge. The program must not be vulnerable to stack overflows. So it must either use iteration or tail recursion.
Also, bonus points for if it can calculate big numbers and the language does not already have it implemented. (or if you reimplement big number support using fixed-length integers)
Test case
Number: 21
Results: 21 -> 64 -> 32 -> 16 -> 8 -> 4 -> 2 -> 1
Number: 3
Results: 3 -> 10 -> 5 -> 16 -> 8 -> 4 -> 2 -> 1
Also, the code golf must include full user input and output.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(30)
贝丰格
Befunge
Python -
95645146 char显然不会产生堆栈溢出。
Python -
95645146 charObviously does not produce a stack overflow.
LOLCODE:406 CHARAKTERZ
测试JUSTIN J. MEZA 的翻译。再见!
LOLCODE: 406 CHARAKTERZ
TESTD UNDR JUSTIN J. MEZA'S INTERPRETR. KTHXBYE!
Haskell,62 个字符
637683、86、97、137用户输入,打印输出,使用常量内存和堆栈,可处理任意大的整数。
此代码的示例运行,给定 80 位数字全“1”(!)的数量作为输入,看起来很有趣。
原始、仅函数版本:
Haskell 51 个字符
@&^# 到底谁需要条件?
(编辑:我很“聪明”并使用了修复。没有它,代码就会减少到 54 个字符。
edit2:通过分解
f()
降至 51)Haskell, 62 chars
637683,86,97,137User input, printed output, uses constant memory and stack, works with arbitrarily big integers.
A sample run of this code, given an 80 digit number of all '1's (!) as input, is pretty fun to look at.
Original, function only version:
Haskell 51 chars
Who the @&^# needs conditionals, anyway?
(edit: I was being "clever" and used fix. Without it, the code dropped to 54 chars.
edit2: dropped to 51 by factoring out
f()
)Perl
我决定采取一点反竞争的态度,并展示您通常如何在 Perl 中编写此类问题。
最后还有一个 46(总共)字符的代码高尔夫条目。
前三个示例都从此标头开始。
简单的递归版本
简单迭代版本
优化迭代版本
现在我将向您展示如何使用 v5.10.0
基准测试
之前的 Perl 版本执行最后一个示例。首先,IO 始终是缓慢的部分。因此,如果您实际上按原样对它们进行基准测试,那么您应该从每一个中获得大约相同的速度。
为了测试这些,我打开了
/dev/null
($null
) 的文件句柄,并编辑了每个say $n
以改为读取说 {$null} $n
。这是为了减少对IO的依赖。运行 10 次后,这是一个具有代表性的示例输出:
最后,一个真正的代码高尔夫条目:
总共 46 个字符
如果您不需要打印起始值,您可以再删除 5 个字符。
总共 41 个字符
31 个字符用于实际代码部分,但如果没有
-n
开关,代码将无法工作。因此,我将整个示例包含在我的计数中。Perl
I decided to be a little anticompetitive, and show how you would normally code such problem in Perl.
There is also a 46 (total) char code-golf entry at the end.
These first three examples all start out with this header.
Simple recursive version
Simple iterative version
Optimized iterative version
Now I'm going to show how you would do that last example with a version of Perl prior to v5.10.0
Benchmark
First off the IO is always going to be the slow part. So if you actually benchmarked them as-is you should get about the same speed out of each one.
To test these then, I opened a file handle to
/dev/null
($null
), and edited everysay $n
to instead readsay {$null} $n
. This is to reduce the dependence on IO.After having run it 10 times, here is a representative sample output:
Finally, a real code-golf entry:
46 chars total
If you don't need to print the starting value, you could remove 5 more characters.
41 chars total
31 chars for the actual code portion, but the code won't work without the
-n
switch. So I include the entire example in my count.Golfscript:20 个字符
这相当于
Golfscript : 20 chars
This is equivalent to
bc 41 chars
我想这种问题是什么
bc
发明的目的是:测试:
正确的代码:
bc
处理最多INT_MAX
位数字编辑: 维基百科文章提到此猜想已针对最高20x258的所有值进行了检查(大约5.76e18)。此程序:
在 68 秒内测试 220,000+1(大约 3.98e6,020), >144,404 周期。
bc 41 chars
I guess this kind of problems is what
bc
was invented for:Test:
Proper code:
bc
handles numbers with up toINT_MAX
digitsEdit: The Wikipedia article mentions this conjecture has been checked for all values up to 20x258 (aprox. 5.76e18). This program:
tests 220,000+1 (aprox. 3.98e6,020) in 68 seconds, 144,404 cycles.
Perl:31 个字符
编辑删除 2 个不必要的空格。
编辑删除 1 个不必要的空格。
Perl : 31 chars
Edited to remove 2 unnecessary spaces.
Edited to remove 1 unnecessary space.
MS Excel,35 个字符
取自维基百科:
直接 复制/粘贴公式 111 次以获得起始数字 1000 的结果。;)
MS Excel, 35 chars
Taken straight from Wikipedia:
It only took copy/pasting the formula 111 times to get the result for a starting number of 1000. ;)
C : 64 个字符
带大整数支持: 431 个(必要)字符
注意:在没有至少对 malloc/realloc 进行原型设计的情况下,请勿删除
#include
,如下这样做在 64 位平台上并不安全(64 位 void* 将转换为 32 位 int)。这个还没有经过严格测试。它也可以使用一些起酥油。
以前的版本:(
删除了 12 个字符,因为没有人遵循输出格式...:| )
C : 64 chars
With big integer support: 431 (necessary) chars
Note: Do not remove
#include <stdlib.h>
without at least prototyping malloc/realloc, as doing so will not be safe on 64-bit platforms (64-bit void* will be converted to 32-bit int).This one hasn't been tested vigorously yet. It could use some shortening as well.
Previous versions:
(removed 12 chars because no one follows the output format... :| )
另一个汇编版本。它不限于 32 位数字,它可以处理高达 1065534 的数字,尽管 MS-DOS 使用的“.com”格式仅限于 80 位数字。为 A86 汇编器编写,需要 Win-XP DOS 框才能运行。汇编为 180 字节:
Another assembler version. This one is not limited to 32 bit numbers, it can handle numbers up to 1065534 although the ".com" format MS-DOS uses is limited to 80 digit numbers. Written for A86 assembler and requires a Win-XP DOS box to run. Assembles to 180 bytes:
dc - 24 个字符
2528dc
是此序列的一个很好的工具:还有 24 个字符,使用 Golfscript 条目:
57 个字符以满足规范:
dc - 24 chars
2528dc
is a good tool for this sequence:Also 24 chars using the formula from the Golfscript entry:
57 chars to meet the specs:
方案:72
这使用递归,但调用是尾递归的,所以我认为它们将针对迭代进行优化。在一些快速测试中,我无法找到堆栈溢出的数字。例如:
(c 9876543219999999999000011234567898888777766665555444433332222
7777777777777777777777777777777798797657657651234143375987342987
5398709812374982529830983743297432985230985739287023987532098579
058095873098753098370938753987)
...运行得很好。 [这只是一个数字——我刚刚将其分解以适合屏幕。]
Scheme: 72
This uses recursion, but the calls are tail-recursive so I think they'll be optimized to iteration. In some quick testing, I haven't been able to find a number for which the stack overflows anyway. Just for example:
(c 9876543219999999999000011234567898888777766665555444433332222
7777777777777777777777777777777798797657657651234143375987342987
5398709812374982529830983743297432985230985739287023987532098579
058095873098753098370938753987)
...runs just fine. [that's all one number -- I've just broken it to fit on screen.]
Mathematica,45
50个字符Mathematica, 45
50charsRuby,50 个字符,无堆栈溢出
基本上是 makapuf 的 Python 解决方案的直接破解 :
Ruby,45个字符,会溢出
基本上是问题中提供的代码的直接破解:
Ruby, 50 chars, no stack overflow
Basically a direct rip of makapuf's Python solution:
Ruby, 45 chars, will overflow
Basically a direct rip of the code provided in the question:
Python 45 Char
从 makapuf 的答案中删除了一个字符。
Python 45 Char
Shaved a char off of makapuf's answer.
TI-BASIC
不是最短的方法,但却是一种新颖的方法。对于大序列来说肯定会大大减慢,但它不应该溢出。
TI-BASIC
Not the shortest, but a novel approach. Certain to slow down considerably with large sequences, but it shouldn't overflow.
哈斯克尔:50
Haskell : 50
不是最短的,而是一个优雅的 clojure 解决方案
not the shortest, but an elegant clojure solution
C#:216 个字符
长格式:
新版本,接受一个数字作为通过命令行提供的输入,无需输入验证。
173154 个字符。长格式:
我可以通过抄袭此 答案使用for循环而不是while。 150 个字符。
C#: 216 Characters
in long form:
New Version, accepts one number as input provided through the command line, no input validation.
173154 characters.in long form:
I am able to shave a few characters by ripping off the idea in this answer to use a for loop rather than a while. 150 characters.
Ruby,
支持 43 个字符 bignum,具有堆栈溢出敏感性:
...以及 50 个字符,支持 bignum,无堆栈溢出:
感谢 Jordan。我不知道“p”可以替代 put。
Ruby, 43 characters
bignum supported, with stack overflow susceptibility:
...and 50 characters, bignum supported, without stack overflow:
Kudos to Jordan. I didn't know about 'p' as a replacement for puts.
nroff1
使用
nroff -U hail.g
1 运行。 groff版本
nroff1
Run with
nroff -U hail.g
1. groff version
Scala + Scalaz
实际操作:
Scala 2.8
这还包括尾随的 1。
通过以下隐式
,可以将其缩短为
编辑 - 58 个字符 (包括输入和输出,但不包括初始数字)
如果不需要换行符可以减少2...
Scala + Scalaz
And in action:
Scala 2.8
This also includes the trailing 1.
With the following implicit
this can be shortened to
Edit - 58 characters (including input and output, but not including initial number)
Could be reduced by 2 if you don't need newlines...
F#,90 个字符
或者如果您不使用 F# 交互方式显示结果,则为 102 个字符:
F#, 90 characters
Or if you're not using F# interactive to display the result, 102 characters:
Common Lisp,141 个字符:
测试运行:
Common Lisp, 141 characters:
Test run:
Jerry Coffin 的程序有整数溢出,试试这个:用
进行测试。
小于 1 亿的数字,最长的总停止时间是 63,728,127,有 949 个步骤。
总停止时间最长的不到10亿的数字是670,617,279,有986步。
The program frm Jerry Coffin has integer over flow, try this one:
tested with
The number less than 100 million with the longest total stopping time is 63,728,127, with 949 steps.
The number less than 1 billion with the longest total stopping time is 670,617,279, with 986 steps.
ruby,43,可能满足 I/O 要求
使用
ruby -n hail
运行ruby, 43, possibly meeting the I/O requirement
Run with
ruby -n hail
C#:659 个字符,支持 BigInteger
Ungolfed
C# : 659 chars with BigInteger support
Ungolfed
x86 程序集,1337 个字符
x86 assembly, 1337 characters