3

我的代码中有一个奇怪的问题来回答这个问题:

为正整数集定义了以下迭代序列:

n → n/2(n 为偶数)
n → 3n + 1(n 为奇数)

使用上述规则并从 13 开始,我们生成以下序列:
13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1

可以看出,这个序列(从 13 开始,到 1 结束)包含 10 个术语。尽管尚未证明(科拉茨问题),但人们认为所有起始数字都以 1 结束。

哪个起始数字(低于 100 万)产生最长的链?

注意:一旦链启动,条款允许超过一百万。

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方法,但是我不明白该怎么做。

4

2 回答 2

4

换句话说,问题在于程序永远不会终止,我所看到的是它打印了从 1 到 113383 的所有整数,大概是从第一次.peek(System.out::println)调用开始的。

发生这种情况是因为您假设将在 collat​​z 中生成的所有数字都在一个int类型的范围内。但事实并非如此。这就是它失败的原因。尝试将所有内容都设置为long- PrimitiveIterator.OfLongStreamSupport.longStream等,它会起作用。

我想摆脱拳击并使用该IntStream::collect方法,但是我不明白该怎么做。

我不明白你为什么要这样做。拳击仍然会在某个地方完成,因为你不能创建一个Map原始的int。尽管如此,如果你愿意,你实际上还需要做更多的工作。这是你如何做到的:

@Override
public void run() {

    ObjIntConsumer<Map<Integer, Long>> objIntConsumer = 
            (map, value) -> map.put(value, Iterators.longStream(new CollatzGenerator(value)).count());

    BiConsumer<Map<Integer, Long>, Map<Integer, Long>> biConsumer = 
            (targetMap, accumulatorMap) -> targetMap.putAll(accumulatorMap);

    result = IntStream.range(1, maximum)
            .collect(LinkedHashMap::new, objIntConsumer, biConsumer)
            .entrySet().stream()
            .peek(System.out::println)
            .max(Comparator.<Entry<Integer, Long>>comparingLong(entry -> entry.getValue()))
            .get().getKey();
}
于 2014-02-25T18:33:53.833 回答
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(&current_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;
}
于 2019-07-26T06:20:16.850 回答