我的代码中有一个奇怪的问题要回答这个问题:
为正整数集定义了以下迭代序列:
n→n / 2(n是偶数)
n→3n + 1(n为奇数)使用上面的规则并从13开始,我们生成以下序列:
13→40→20→10→5→16→8→4→2→1可以看出,该序列(从13开始,在1结束)包含10个术语。虽然尚未证实(Collatz问题),但据认为所有起始数字都以1结束。
哪个起始编号低于一百万,产生最长的链?
注意:一旦链条启动,条款允许超过一百万。
public class Problem14 extends Problem<Integer> {
private final int maximum;
public Problem14(final int maximum) {
this.maximum = maximum;
}
@Override
public void run() {
result = IntStream.range(1, maximum).boxed()
.peek(System.out::println)
.collect(Collectors.toMap(i -> i, i -> (int)Iterators.intStream(new CollatzGenerator(i)).count()))
.entrySet().stream()
.peek(System.out::println)
.max(Comparator.comparingInt(Map.Entry::getValue))
.get().getKey();
}
@Override
public String getName() {
return "Problem 14";
}
}
public abstract class Problem<T> implements Runnable {
protected T result;
public String getResult() {
return String.valueOf(result);
}
abstract public String getName();
}
public class CollatzGenerator implements PrimitiveIterator.OfInt {
private int current;
public CollatzGenerator(final int start) {
if (start < 1) {
throw new IllegalArgumentException("generators.CollatzGenerator: start < 1: start = " + start);
}
this.current = start;
}
@Override
public boolean hasNext() {
return (current != 1);
}
@Override
public int nextInt() {
int returnInt = current;
if (current % 2 == 0) {
current /= 2;
}
else {
current = 3 * current + 1;
}
return returnInt;
}
}
public abstract class Iterators {
//...
public static IntStream intStream(final PrimitiveIterator.OfInt iterator) {
return StreamSupport.intStream(
Spliterators.spliteratorUnknownSize(iterator, 0), false
);
}
//...
}
调用代码的方式如下:
new Problem14(1_000_000).run();
所以重新说一下,问题是程序永远不会终止,我所看到的是它打印的所有整数从1到113383,可能是从第一次.peek(System.out::println)
调用。
另外一个问题是,目前我将IntStream
打包到Stream<Integer>
,以便能够.collect(Collectors.toMap(i -> i, i -> (int)Iterators.intStream(new CollatzGenerator(i)).count()))
...
我想摆脱拳击并使用IntStream::collect
方法,但我不明白该怎么做。
答案 0 :(得分:3)
所以重新说一下,问题是程序永远不会终止,我所看到的是它打印的所有整数从1到113383,可能是从第一次
.peek(System.out::println)
调用。
这种情况正在发生,因为您假设将在collatz中生成的所有数字都在int
类型的范围内。但事实并非如此。这就是失败的原因。尝试将所有内容设为long
- PrimitiveIterator.OfLong
,StreamSupport.longStream
等,这样就可以了。
我想摆脱拳击并使用
IntStream::collect
方法,但我不明白该怎么做。
我不明白你为什么要那样做。拳击仍将在某处完成,因为您无法创建原始Map
的{{1}}。不过,如果你愿意,你实际上还需要做更多的工作。这是你如何做到的:
int
答案 1 :(得分:0)
我用C编写了短代码,可以使用大数字“无限”运行(我以104282959结尾,在这里我杀死了它)。它检查数字是否收敛到一个(证明有效,继续下一个未检查)。
优化很少,可能会有点混乱。但是我还没有读过任何论文,因此可以进行更多优化。
没有保证它能很好地工作。
//gcc main.c -lgmp
#include <stdio.h>
#include <stdlib.h>
#include <gmp.h>
void collatz_conjucture(mpz_t *res, mpz_t n)
{
mpz_mod_ui(*res, n, 1UL);
if(mpz_cmp_ui(*res, 1UL) == 0) {
mpz_mul_ui(*res, n, 3UL);
mpz_add_ui(*res, *res, 1UL);
//mpz_fdiv_q_ui(*res, *res, 2UL); //Posible to uncomment, skip one step of computation (always odd after even), but it will slow down increment of next
} else {
mpz_fdiv_q_ui(*res, n, 2UL);
}
}
int main(int argc, char **argv)
{
// Init
mpz_t current_b, next_b;
mpz_init_set_str(current_b, "1", 10);
mpz_init_set(next_b, current_b);
//Starts computation - i means step
for (unsigned long i = 0; i < 0xFFFFF; ++i) {
//for (;;) { // replace above for infinite
mpz_set(current_b, next_b);
do {
if(mpz_cmp(current_b, next_b) == 0) {
mpz_add_ui(next_b, next_b, 1UL);
}
collatz_conjucture(¤t_b, current_b);
} while (mpz_cmp(current_b, next_b) > 0);
char *result = mpz_get_str(NULL, 10, next_b);
printf("%s\n", result);
free(result);
result = NULL;
}
mpz_clear(current_b);
mpz_clear(next_b);
return 0;
}