가장 작은 소수 요소의 합


19

SF (n)은 주어진 수 n에 대해 가장 작은 소수를 계산하는 함수입니다.

우리는 모든 SF (n)의 합을 2 <= n <= N으로 T (N)이라고 부릅니다.

T (1) = 0 (합이 0보다 작음)

T (2) = 2 (2는 첫 번째 소수입니다)

T (3) = 5 = 2 + 3

T (4) = 7 = 2 + 3 + 2

T (5) = 12 = 2 + 3 + 2 + 5

...

T (10000) = 5786451

승자는 내 노트북 ​​(Toshiba Satellite L845, Intel Core i5, 8GB RAM)에서 60 초 안에 가장 큰 T (N)을 계산할 수있는 사람이됩니다.


Current top score: Nicolás Siplis - 3.6e13 points - Nim

Pf (2) = 2, Pf (3) = 3, 그래서 T (3) = 2 + 3 = 5. 맞습니까? 주요 요소를 찾도록 프로그래밍했지만 현재 요구 사항에 대해 자세히 설명해 줄 수 있습니다. 감사합니다
코더

1
@ToddLehman 내 자신의 랩톱 (Sony Vaio SVF14A16CLB)에서 각 코드를 실행 중이므로 60 초 미만이면 시간이 더 걸리면 숫자를 늘리고 줄입니다.
Nicolás Siplis

1
예, 내 컴퓨터에서 실행되고 60 초 이내에 정답을 출력하는 한 허용됩니다.
Nicolás Siplis

1
스레드가 4 개 있습니다.
Nicolás Siplis

1
타사 라이브러리가 허용됩니까? 프로그램이 스레드를 작성하는 것이 괜찮습니까?
코더

답변:


12

님, 3.6e13

메모리 요구 사항이 너무 높아 지므로 가능한 한 가장 높은 N을 계산하려고 할 때 단순히 체질하는 것이 최선의 방법은 아닙니다. 여기에 다른 접근 방식이 있습니다 (2 일 전에 Nim에서 시작하여 속도와 구문에 빠졌습니다. 더 빠르거나 더 읽기 쉬운 제안은 환영합니다!).

import math
import sequtils
import nimlongint # https://bitbucket.org/behrends/nimlongint/

proc s(n : int) : int128 =
    var x = toInt128(n)
    (x * x + x) div 2 - 1

proc sum_pfactor(N : int) : int128 =    
    var
        root = int(sqrt(float(N)))
        u = newSeqWith(root+1,false)
        cntA,cntB,sumA,sumB = newSeq[int128](root+1)
        pcnt,psum,ret : int128
        interval,finish,d,q,t : int

    for i in 0..root:
        cntA[i] = i-1
        sumA[i] = s(i)

    for i in 1..root:
        cntB[i] = N div i - 1
        sumB[i] = s(N div i)

    for p in 2..root:
        if cntA[p] == cntA[p-1]:
            continue

        pcnt = cntA[p - 1]
        psum = sumA[p - 1]
        q = p * p
        ret = ret + p * (cntB[p] - pcnt)
        cntB[1] = cntB[1] - cntB[p] + pcnt
        sumB[1] = sumB[1] - (sumB[p] - psum) * p
        interval = (p and 1) + 1
        finish = min(root,N div q)

        for i in countup(p+interval,finish,interval):

            if u[i]:
                continue

            d = i * p

            if d <= root:
                cntB[i] = cntB[i] - cntB[d] + pcnt
                sumB[i] = sumB[i] - (sumB[d] - psum) * p
            else:
                t = N div d
                cntB[i] = cntB[i] - cntA[t] + pcnt
                sumB[i] = sumB[i] - (sumA[t] - psum) * p

        if q <= root:
            for i in countup(q,finish-1,p*interval):
                u[i] = true

        for i in countdown(root,q-1):
            t = i div p
            cntA[i] = cntA[i] - cntA[t] + pcnt
            sumA[i] = sumA[i] - (sumA[t] - psum) * p

    sumB[1] + ret

var time = cpuTime()
echo(sum_pfactor(int(3.6e13))," - ",cpuTime() - time)

Nim 용 GMP 래퍼를 코드로 구현하려고 시도했지만 제대로 작동하지 못했습니다 (전에는 GMP를 사용하지 않았으므로 확실히 도움이되지 않았습니다).
Nicolás Siplis

returnin f의 정의 도 필요하지 않습니다 . 단일 표현 프로세스가 자동으로 반환됩니다.
kirbyfan64sos

3
이것은 Nim이 눈에 띄는 마진으로 얻은 첫 번째 가장 빠른 코드 는 아닙니다 . 조사 할 가치가 있습니다.
primo

GMP를 사용할 때 어떻게 작동하는지 궁금하지만 노력에도 불구하고 올바르게 구현할 수 없었습니다.
Nicolás Siplis

Nim은 확실히 내 학습 목록에 올라갑니다!
Sp3000

5

C, 프라임 시브 : 5e9

결과 :

$ time ./sieve 
Finding sum of lowest divisors of n = 2..5000000000
572843021990627911

real    0m57.144s
user    0m56.732s
sys 0m0.456s 

프로그램:

그것은 다소 간결한 프로그램이지만 메모리 관리를 올바르게하는 방법을 알아내는 데 시간이 걸렸습니다. 범위의 숫자 당 1 바이트에 충분한 램이 있으므로 조심해야했습니다. 그것은 Erasthones의 표준 체입니다.

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<assert.h>

#define LIMIT ((unsigned long long)5e9 +1)
#define ROOT_LIMIT floor(sqrt(LIMIT))

int main()
{
    printf("Finding sum of lowest divisors of n = 2..%llu\n", LIMIT - 1);
    char * found_divisor;
    found_divisor = malloc(LIMIT * sizeof(char));
    if (found_divisor == NULL) {
        printf("Error on malloc");
        return -1;
    }
    unsigned long long i;
    unsigned long long trial_div;
    unsigned long long multiple;
    unsigned long long sum = 0;

    for (i = 0; i < LIMIT; ++i) {
        found_divisor[i] = 0;
    }

    for (trial_div = 2; trial_div <= ROOT_LIMIT; ++trial_div) {
        if (found_divisor[trial_div] == 0) {
            for (multiple = trial_div * trial_div; multiple < LIMIT; multiple += trial_div) {
                if (found_divisor[multiple] == 0) {
                    found_divisor[multiple] = 1;
                    sum += trial_div;
                }
            }
        }
    }

    for (i = 2; i < LIMIT; ++i) {
        if (found_divisor[i] == 0) {
            sum += i;
        }
    }

    free(found_divisor);
    printf("%lld\n", sum);
    return 0;
}

1
메모리가 중요한 경우 숫자 당 1 비트이면 충분합니다. 비트 마스크를 사용하여 플래그를 저장할 수 있습니다.
Reto Koradi

@RetoKoradi 불행히도, 아마도 1 분을 넘을 정도로 프로그램 속도가 느려질 것입니다.
isaacg

assert.h에 무엇이 필요합니까?
맥스 Ried

@MaxRied Earlie 버전에서 남았습니다.
isaacg

3

펄, 무차별 팩토링

use ntheory ":all";
sub T {
  my $sum=0;
  for (1..$_[0]) {
    $sum += !($_%2) ? 2 : !($_%3) ? 3 : !($_%5) ? 5 : (factor($_))[0];
  }
  $sum
}
T(90_000_000);

Linux 컴퓨터에서 약 25 초 만에 9e7에 도달 할 수 있습니다. 2/3/5를 확인한 후 숫자를 완전히 고려하여 C 코드를 파고 들면 더 빠를 수 있습니다.

체질을 사용하여이 작업을 수행하는 훨씬 더 영리한 방법이 있습니다. 나는 단순한 무차별 대입 방법이 시작이 될 것이라고 생각했다. 그건 그렇고 기본적으로 프로젝트 오일러 문제 521입니다.


아는 것이 유용하다면, 체가있는 파이썬에서는 T (47000) 만 관리 할 수 ​​있습니다. 나는 그것이 더 빠른지 확인하기 위해하고있는 것과 비슷한 것을 시도 할 것입니다.
Kade

체를 사용하지 않는 것이 더 빠릅니다 .. 나는 당신과 비슷한 방법으로 T (493900)를 계산할 수있었습니다.
Kade

전에는 Perl을 사용한 적이 없지만 답변을 확인했습니다. 목록에 추가하겠습니다.
Nicolás Siplis 1

공평하게, 이것은 C에서 팩토링을 수행하는 모듈을 사용합니다 (모든 것에 순수한 Perl을 사용하도록 강요 할 수는 있지만 물론 빠르지는 않습니다).
DanaJ

답은 여러 언어 조합을 사용하여 계산할 수 있으므로 괜찮습니다.
Nicolás Siplis

3

이동, 21e9

각 숫자의 최소 인수 <= N을 찾기 위해 체를 수행합니다. 숫자 공간의 섹션을 계산하기 위해 고 루틴을 생성합니다.

"go run prime.go -P 4 -N 21000000000"으로 실행하십시오.

package main

import (
    "flag"
    "fmt"
    "runtime"
)

const S = 1 << 16

func main() {
    var N, P int
    flag.IntVar(&N, "N", 10000, "N")
    flag.IntVar(&P, "P", 4, "number of goroutines to use")
    flag.Parse()
    fmt.Printf("N = %d\n", N)
    fmt.Printf("P = %d\n", P)
    runtime.GOMAXPROCS(P)

    // Spawn goroutines to check sections of the number range.
    c := make(chan uint64, P)
    for i := 0; i < P; i++ {
        a := 2 + (N-1)*i/P
        b := 2 + (N-1)*(i+1)/P
        go process(a, b, c)
    }
    var sum uint64
    for i := 0; i < P; i++ {
        sum += <-c
    }
    fmt.Printf("T(%d) = %d\n", N, sum)
}

func process(a, b int, res chan uint64) {
    // Find primes up to sqrt(b).  Compute starting offsets.
    var primes []int
    var offsets []int
    for p := 2; p*p < b; p++ {
        if !prime(p) {
            continue
        }
        primes = append(primes, p)
        off := a % p
        if off != 0 {
            off = p - off
        }
        offsets = append(offsets, off)
    }

    // Allocate sieve array.
    composite := make([]bool, S)

    // Check factors of numbers up to b, a block of S at a time.
    var sum uint64
    for ; a < b; a += S {
        runtime.Gosched()
        // Check divisibility of [a,a+S) by our set of primes.
        for i, p := range primes {
            off := offsets[i]
            for ; off < S; off += p {
                if composite[off] {
                    continue // Divisible by a smaller prime.
                }
                composite[off] = true
                if a+off < b {
                    sum += uint64(p)
                }
            }
            // Remember offset for next block.
            offsets[i] = off - S
        }
        // Any remaining numbers are prime.
        for i := 0; i < S; i++ {
            if composite[i] {
                composite[i] = false // Reset for next block.
                continue
            }
            if a+i < b {
                sum += uint64(a + i)
            }
        }
    }
    res <- sum
}

func prime(n int) bool {
    for i := 2; i*i <= n; i++ {
        if n%i == 0 {
            return false
        }
    }
    return true
}

N = 21e9에 대한 답은 2 ^ 63과 2 ^ 64 사이이므로 부호없는 64 비트 정수를 사용하여 올바르게 계산해야합니다.


내 컴퓨터에서 실행되도록 수정해야했지만 (N에서 1e9로 감소) 런타임 자체는 매우 빠르고 훌륭합니다!
Nicolás Siplis

@ NicolásSiplis : 메모리 사용량이 수정되었습니다.
Keith Randall

런타임은 80 초이지만 1.6e10은 거의 정확히 60으로 계산되었습니다!
Nicolás Siplis

2

C ++, 1 << 34 ~ 1.7e10

Intel(R) Core(TM) i5-2410M CPU @ 2.30GHz

$ g++ -O2 test3.cpp 
$ time ./a.out 
6400765038917999291

real    0m49.640s
user    0m49.610s
sys 0m0.000s
#include <iostream>
#include <vector>

using namespace std;

const long long root = 1 << 17; // must be a power of two to simplify modulo operation
const long long rootd2 = root >> 1;
const long long rootd2m1 = rootd2 - 1;
const long long mult = root; // must be less than or equal to root
const long long n = root * mult; // unused constant (function argument)

int main() {
  vector < int > sieve(rootd2, 0);
  vector < int > primes;
  vector < long long > nexts;
  primes.reserve(root);
  nexts.reserve(root);
  // initialize sum with result for even numbers
  long long sum = n / 2 * 2;
  // sieve of Erathosthenes for numbers less than root
  // all even numbers are skipped
  for(long long i = 1; i < rootd2; ++i){
    if(sieve[i]){
      sieve[i] = 0;
      continue;
    }
    const long long val = i * 2 + 1;
    primes.push_back(val);
    sum += val;
    long long j;
    for(j = (val + 1) * i; j < rootd2; j += val){
      sum += val * (1 - sieve[j]); // conditionals replaced by multiplication
      sieve[j] = 1;
    }
    nexts.push_back(j);
  }
  int k = primes.size();
  long long last = rootd2;
  // segmented sieve of Erathosthenes
  // all even numbers are skipped
  for(int segment = 2; segment <= mult; ++segment){
    last += rootd2;
    for(int i = 0; i < k; ++i){
      long long next = nexts[i];
      long long prime = primes[i];
      if(next < last){
        long long ptr = next & rootd2m1; // modulo replaced by bitmasking
        while(ptr < rootd2){
          sum += prime * (1 - sieve[ptr]); // conditionals replaced by multiplication
          sieve[ptr] = 1;
          ptr += prime;
        }
        nexts[i] = (next & ~rootd2m1) + ptr;
      }
    }
    for(int i = 0; i < rootd2; ++i){
      sum += ((segment - 1) * root + i * 2 + 1) * (1 - sieve[i]);
      sieve[i] = 0;
    }
  }
  cout << sum << endl;
}

2

자바 8 : 1.8e8 2.4e8

이 항목은 이미 다른 몇 가지 항목과 비교되지 않지만이 작업을 즐겁게했기 때문에 답변을 게시하고 싶었습니다.

내 접근 방식의 주요 최적화는 다음과 같습니다.

  • 모든 짝수의 최소 계수는 2이므로 모든 홀수를 처리 한 후 무료로 추가 할 수 있습니다. 당신이 계산하는 작업을 수행 한 경우 기본적으로 T(N)할 때 N % 2 == 1, 당신은 알고T(N + 1) == T(N) + 2 . 이를 통해 3에서 카운트를 시작하고 반복하여 2 씩 증가시킬 수 있습니다.
  • 소수와 Collection유형이 아닌 배열에 소수를 저장 합니다. 이 두 배 이상N 내가 도달 할 수있는 입니다.
  • 나는 에라토스테네스의 체를 수행하는 것과 달리 소수를 사용하여 숫자를 고려합니다. 이것은 내 메모리 스토리지가 거의 소수의 소수 배열로 제한됨을 의미합니다.
  • 가장 작은 요소를 찾으려고하는 숫자의 제곱근을 저장합니다. 매번 주요 요소를 제곱하는 @ user1354678의 접근 방식을 시도했지만 점수에서 1e7 이상이 소요되었습니다.

그게 전부입니다. 내 코드는 시간 제한에 도달하거나 초과 한 것을 감지 할 때까지 3에서 2까지 반복됩니다.이 시점에서 응답을 내 보냅니다.

package sum_of_smallest_factors;

public final class SumOfSmallestFactors {
    private static class Result {
        private final int number;
        int getNumber() {
            return number;
        }

        private final long sum;
        long getSum() {
            return sum;
        }


        Result(int number, long sum) {
            this.number = number;
            this.sum = sum;
        }
    }


    private static final long TIME_LIMIT = 60_000_000_000L; // 60 seconds x 1e9 nanoseconds / second


    public static void main(String[] args) {
        SumOfSmallestFactors main = new SumOfSmallestFactors();
        Result result = main.run();
        int number = result.getNumber();
        long sum = result.getSum();
        System.out.format("T(%,d) = %,d\n", number, sum);
    }


    private int[] primes = new int[16_777_216];
    private int primeCount = 0;
    private long startTime;


    private SumOfSmallestFactors() {}

    private Result run() {
        startClock();
        int number;
        long sumOfSmallestFactors = 2;
        for (number = 3; mayContinue(); number += 2) {
            int smallestFactor = getSmallestFactor(number);
            if (smallestFactor == number) {
                addPrime(number);
            }
            sumOfSmallestFactors += smallestFactor + 2;
        }
        --number;

        Result result = new Result(number, sumOfSmallestFactors);
        return result;
    }

    private void startClock() {
        startTime = System.nanoTime();
    }

    private boolean mayContinue() {
        long currentTime = System.nanoTime();
        long elapsedTime = currentTime - startTime;
        boolean result = (elapsedTime < TIME_LIMIT);
        return result;
    }

    private int getSmallestFactor(int number) {
        int smallestFactor = number;
        int squareRoot = (int) Math.ceil(Math.sqrt(number));

        int index;
        int prime = 3;
        for (index = 0; index < primeCount; ++index) {
            prime = primes[index];

            if (prime > squareRoot) {
                break;
            }

            int remainder = number % prime;
            if (remainder == 0) {
                smallestFactor = prime;
                break;
            }
        }

        return smallestFactor;
    }

    private void addPrime(int prime) {
        primes[primeCount] = prime;
        ++primeCount;
    }
}

최신 버전의 Java 8이 설치된 다른 시스템 (Windows 8.1, Intel 코어 i7 @ 2.5GHz, 8GB RAM)에서 실행하면 코드를 변경하지 않고도 훨씬 더 나은 결과를 얻을 수 있습니다.

T(240,308,208) = 1,537,216,753,010,879

당신이를 대체 할 수있는 경우 mayContinue()for loop condition단순한 조건으로, 당신은 더 높은 결과를 얻을 수 있습니다. 그리고 나는 심지어 합계를 미리 계산 한 다음 2 씩 증가시키는 방법을 좋아합니다.
Coder

@ user1354678, 추천 해 주셔서 감사합니다. 이상하게도 작동하지 않았습니다. 다른 컴퓨터 에서이 코드의 변형을 시도한 결과 게시 된 버전이 가장 빠릅니다. 코드에서 시계 호출을 제거하고 간단한 임계 값을 사용하면 1 초가 조금 걸립니다. 난 내 전환 시도 startTimeendTime~ 2e7 뺄셈을 제거하기 위해,하지만 내 점수에서 3e7 그 비용을 나에게!
sadakatsu

당신이 그것을 시도 했습니까 System.nanoTime() - startTime < TIME_LIMIT , coz 그것은 나를 위해 코드를 조금 고정시킵니다. 사실이 조건을 수백만 번 확인하면 조금 빠르다는 사실을 고려하면 엄청나게 빠르지는 않습니다. 난 당신의 코드에서 배운 한 가지는, 넣지 마십시오된다 for돌며 for이동 한 후 ... for, 내 코드에서 다른 방법으로, 내 코드 속도가 40 % 증가됩니다 감사합니다 .. 난 아직도 파악하고있어 한 가지이며, 배열나요 수백만 번을 가져온다는 사실을 고려할 때 ArrayList보다 훨씬 효율적입니다.
코더

x2구현하면 결과를 얻을 수 있습니다 MultiThreading. 그러나 Prime 계산을 실행하기 전에 전체 배열을 미리 계산해야합니다.
코더

@ user1354678, mayContinue()메소드 에서 수표를 for 루프로 이동하면 점수에서 8e6이 소요됩니다. 로컬 최적화 문제 일 수 있습니다. 이 솔루션을 개발할 때 소수를 저장하기 위해 여러 데이터 유형을 실험했습니다. 로 8.8e7에 도달 할 수 ArrayList있었지만 배열을 사용하여 1.8e8 (현재 2.4e8) 에 도달했습니다 . 조회와 관련하여 일부 성능 향상이있을 수 있지만 메모리 할당에 대한 확실한 향상이 있습니다. 알고리즘을 멀티 스레딩하는 것에 대해 생각했지만 문제가 발생했습니다.
sadakatsu

1

R, 2.5e7

에라토스테네스의 단순한 마음의 체, 가능한 한 벡터화. R은 실제로 이런 종류의 문제를 위해 설계되지 않았으며 더 빨리 만들 수 있다고 확신합니다.

MAX <- 2.5e7
Tot <- 0
vec <- 2:MAX 
while(TRUE) {
    if (vec[1]*vec[1] > vec[length(vec)]) {
        Tot <- Tot + sum(as.numeric(vec))
        break
    }

    fact <- which(vec %% vec[1] == 0)
    Tot <- Tot + vec[1]*length(vec[fact])
    vec <- vec[-fact]
}
Tot

T에 대한 페어 포인트 2 : MAX는 정수로 구성된 벡터이므로 MAX의 큰 값에 대해서는 sum(vec)정수 오버플로가 발생하고 NA를 반환합니다. sum(as.numeric(vec))넘치지 않는 복식의 벡터를 합산합니다 (올바른 대답을 줄 수는 없지만)
mawir

1

파이썬, ~ 7e8

Erathostenes의 증분 체를 사용합니다. 표시된 값이 가장 작은 제수로 표시되도록 일부주의를 기울여야하지만 구현 방식은 상당히 간단합니다.

타이밍은 PyPy 2.6.0에서 가져 왔으며 입력은 명령 행 인수로 허용됩니다.

from sys import argv
from math import sqrt

n = int(argv[1])
sieve = {}
imax = int(sqrt(n))

t = n & -2
i = 3
while i <= n:
  divs = sieve.pop(i, [])
  if divs:
    t += divs[-1]
    for v in divs:
      sieve.setdefault(i+v+v, []).append(v)
  else:
    t += i
    if i <= imax: sieve[i*i] = [i]
  i += 2

print t

샘플 사용법

$ pypy sum-lpf.py 10000
5786451

$ pypy sum-lpf.py 100000000
279218813374515

0

줄리아, 5e7

확실히 줄리아가 더 잘할 수 있지만 이것이 내가 지금 가진 것입니다. 이것은 JuliaBox에서 약 60 초 만에 5e7을 수행하지만 아직 로컬에서 테스트 할 수는 없습니다. 잘만되면 나는 더 영리한 접근법을 생각할 것입니다.

const PRIMES = primes(2^16)

function lpf(n::Int64)
    isprime(n) && return n
    for p in PRIMES
        n % p == 0 && return p
    end
end

function T(N::Int64)
    local x::Int64
    x = @parallel (+) for i = 2:N
        lpf(i)
    end
    x
end

여기 우리는 함수를 만들고 있습니다 lpf 순차적 인 소수를 반복하고 각각의 분할성에 대한 입력을 검사 를 . 이 함수는 첫 번째 제수를 반환하여 가장 작은 소수를 얻습니다.

main 함수 lpf는 2에서 입력까지의 정수를 병렬로 계산하고 합산하여 결과를 줄입니다.


0

커먼 리스프, 1e7

(defvar input 10000000)
(defvar numbers (loop for i from 2 to input collect i))
(defvar counter)
(defvar primes)

(setf primes (loop for i from 2 to (floor (sqrt input))
    when (loop for j in primes
        do (if (eq (mod i j) 0) (return nil))
        finally (return t))
    collect i into primes
    finally (return primes)))

(format t "~A~%"    
    (loop for i in primes
        do (setf counter 0)
        summing (progn (setf numbers (remove-if #'(lambda (x) (if (eq (mod x i) 0) (progn (incf counter) t))) numbers))
                (* i counter)) into total
        finally (return (+ total (reduce #'+ numbers)))))

먼저 2에서까지 소수 목록을 생성 한 (sqrt input)다음 소수를 사용하여 모든 값을 테스트하는 반면 이전에는 모든 숫자를 테스트합니다.(sqrt input) 할 것입니다. 예를 들어 숫자를 4로 나눌 수있는 경우 또한 2로 나눌 수 있으므로 이미 설명되어 있습니다.)

내가있는 동안 부작용에 대해 하나님 께 감사드립니다. remove-if 둘 다 목록의 크기를 낮추고 제거 된 요소 수를 계산하므로 루프에있는 값을 곱하고 누적 합계에 추가해야합니다.

(재미있는 사실 : delete은 파괴적인 것과 동일 remove하지만 어떤 이유로 든 이 경우 delete보다 모든 종류가 느립니다 remove.)


전에 Lisp을 사용하지 않았으므로 코드를 실행하려고 할 때 컴파일러 오류가 발생합니다. 2에서 (바닥 (sqrt 입력))까지 i 루프 (setf 카운터 0) 합산 (prog2 (nsubstitute-if 0 # '(lambda (x) (if (eq (mod xi) 0) ))) 숫자) (* i 카운터) (setf 숫자 (0 숫자 제거))) 마지막으로 (반환 (+ 합계 (# '+ 숫자 줄이기))))
Nicolás Siplis 1

SBCL 1.0.38을 사용하고 있지만 집에 도착하면 최신 버전으로 업데이트하고 어떻게 진행되는지 확인합니다. 파일로 저장하면 "sbcl --script <filename>"으로 실행할 수 있습니다.
촛불

Ideone으로 온라인 컴파일을 시도했지만 작동하지 않는 경우를 대비하여 시도했지만 여전히 운이 없습니다.
Nicolás Siplis

죄송합니다. 6 행의 "do"키워드를 잊어 버렸습니다. 이제 다시 실행해야합니다.
촛불

내 컴퓨터에서 60 초 안에 6e6을 계산합니다. 그런데 내 코드를 입력하기로 결정한 경우 답변으로 제출해야하는지 알고 있습니까? 새 제출이 허용되는지 잘 모르겠습니다.
Nicolás Siplis

0

녹 1.5e9

매우 순진한 에라 토 스테 네 (Eratosthene) 체이지만 Rust가 여기에서 어떤 사랑도받지 못했다고 느꼈습니다!

// Expected (approximate) number of primes
fn hint(n:usize) -> usize {
    if n < 2 { 
        1
    } else {
        n / ((n as f64).ln() as usize) + 1
    }
}

fn main() {
    let n:usize = match std::env::args().nth(1) {
        Some(s) => s.parse().ok().expect("Please enter a number !"),
        None => 10000,
    };
    let mut primes = Vec::with_capacity(hint(n));
    let mut sqrt = 2;
    let s = (2..).map(|n:u32| -> u32 {
        if (sqrt * sqrt) < n {
            sqrt += 1;
        }
        let (div, unseen) = match primes.iter().take_while(|&p| *p <= sqrt).filter(|&p| n % p == 0).next() {
            Some(p) => (*p, false),
            None => (n, true),
        };
        if unseen {
            primes.push(div);
        }
        div
    }).take(n-1).fold(0, |acc, p| acc + p);
    println!("{}", s);
}

0

자바 2.14e9

BitSet을 활용 한 순수한 에라토스테네스 (Eratosthenes) 체

에서 가장 작은 소수 요인 합계를 계산 Integer.MAX_VALUE - 1했습니다 33.89 s. 그러나 더 이상 비트 세트 크기에 정수 오버플로가 발생하기 때문에 더 이상 진행할 수 없습니다. 그래서 다음 범위 세트에 대한 다른 비트 세트를 작성하기 위해 노력하고 있습니다. 그때까지, 이것은 내가 생성 할 수있는 가장 빠른 방법입니다.


T(214,74,83,646) = 109931450137817286 in 33.89 s
aka
T(2,147,483,646) = 109931450137817286 in 33.89 s

import java.util.BitSet;

public class SmallPrimeFactorSum {

    static int    limit     = Integer.MAX_VALUE - 1;

    // BitSet is highly efficient against boolean[] when Billion numbers were involved
    // BitSet uses only 1 bit for each number
    // boolean[] uses 8 bits aka 1 byte for each number which will produce memory issues for large numbers
    static BitSet primes    = new BitSet(limit + 1);
    static int    limitSqrt = (int) Math.ceil(Math.sqrt(limit));

    static long   start     = System.nanoTime();

    static long   sum       = 0;

    public static void main(String[] args) {
        genPrimes();
    }

    // Generate Primes by Sieve of Eratosthenes
    // Sieve of Eratosthenes is much efficient than Sieve of Atkins as
    // Sieve of Atkins involes Division, Modulus, Multiplication, Subtraction, Addition but
    // Sieve of Eratosthenes involves only addition
    static void genPrimes() {

        // Inverse the Bit values
        primes.flip(0, limit + 1);

        // Now all Values in primes will now be true,
        // True  represents     prime number 
        // False represents not prime number

        // Set 0 and 1 as not Prime number
        primes.clear(0, 2);

        // Set all multiples of each Prime as not Prime;
        for ( int prime = 2; prime > 0 && prime <= limit && prime > 0; prime = primes.nextSetBit(prime + 1) ) {
            // Add Current Prime as its Prime factor
            sum += prime;
            // Skip marking if Current Prime > SQRT(limit)
            if ( prime > limitSqrt ) {
                continue;
            }
            // Mark Every multiple of current Prime as not Prime
            for ( int multiple = prime + prime; multiple <= limit && multiple > 0; multiple += prime ) {
                // Mark as not Prime only if it's true already
                if ( primes.get(multiple) ) {
                    // Add Current Prime as multiple's Prime factor
                    sum += prime;
                    primes.clear(multiple);
                }
            }
        }

        System.out.printf("T(%d) = %d in %.2f s", limit, sum, (System.nanoTime() - start) / 1000000000.0);
        //System.out.printf("Total Primes upto %d : %d\n", limit, primes.cardinality());
    }

}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.