Tổng các thừa số nguyên tố nhỏ nhất


19

SF (n) là hàm tính hệ số nguyên tố nhỏ nhất cho một số n đã cho.

Chúng tôi sẽ gọi T (N) tổng của mọi SF (n) với 2 <= n <= N

T (1) = 0 (tổng số trên 0 triệu)

T (2) = 2 (2 là số nguyên tố đầu tiên)

T (3) = 5 = 2 + 3

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

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

...

T (10000) = 5786451

Người chiến thắng sẽ là người quản lý để tính toán T (N) lớn nhất trong 60 giây trên máy tính xách tay của riêng tôi (Toshiba Satellite L845, Intel Core i5, RAM 8GB).


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

Pf (2) = 2, Pf (3) = 3, Vậy, T (3) = 2 + 3 = 5. Tôi có đúng không? Tôi đã lập trình để tìm các yếu tố chính, nhưng bạn có thể giải thích rõ hơn về yêu cầu hiện tại không. Cảm ơn bạn
Bộ giải mã

1
@ToddLehman Tôi đang chạy từng mã trong máy tính xách tay của riêng tôi (Sony Vaio SVF14A16CLB), vì vậy, nếu mất ít hơn 60 giây, tôi sẽ tăng số lượng và giảm khi mất nhiều thời gian hơn.
Nicolás Siplis

1
Có, miễn là nó chạy trên máy của chính tôi và đưa ra câu trả lời đúng trong 60 giây hoặc ít hơn, điều đó có thể chấp nhận được.
Nicolás Siplis

1
Nó có 4 chủ đề.
Nicolás Siplis

1
Thư viện của bên thứ ba có được phép không? Có ổn không nếu chương trình đang tạo chủ đề?
Bộ giải mã

Câu trả lời:


12

Nim, 3.6e13

Đơn giản là sàng không phải là câu trả lời tốt nhất khi cố gắng tính N cao nhất có thể vì yêu cầu bộ nhớ trở nên quá cao. Đây là một cách tiếp cận khác (bắt đầu với Nim vài ngày trước và yêu thích tốc độ và cú pháp, mọi đề xuất để làm cho nó nhanh hơn hoặc dễ đọc hơn đều được chào đón!).

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)

Tôi đã thử triển khai trình bao bọc GMP cho Nim vào mã của mình nhưng không thể làm cho nó hoạt động (trước đây chưa bao giờ sử dụng GMP nên chắc chắn không giúp được gì).
Nicolás Siplis

Bạn cũng không cần returnf's định nghĩa. Procs biểu thức đơn tự động trở lại.
kirbyfan64sos

3
Đây không phải là mã nhanh nhất đầu tiên mà Nim giành được bằng lãi suất đáng chú ý. Có thể đáng để điều tra.
primo

Tôi tò mò muốn xem nó hoạt động như thế nào khi sử dụng GMP, nhưng không thể thực hiện chính xác mặc dù tôi đã nỗ lực.
Nicolás Siplis

Nim chắc chắn đang đi vào danh sách cần học của tôi!
Sp3000

5

C, Sàng chính: 5e9

Các kết quả:

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

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

Chương trình:

Mặc dù đây là một chương trình khá nghiêm túc, nhưng tôi phải mất một thời gian để tìm ra cách quản lý bộ nhớ đúng - tôi chỉ có đủ ram cho 1 byte cho mỗi số trong phạm vi, vì vậy tôi phải cẩn thận. Đó là một cái rây tiêu chuẩn của 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
Nếu bộ nhớ là một mối quan tâm, một bit cho mỗi số là đủ. Bạn có thể sử dụng bitmask để lưu trữ các cờ.
Reto Koradi

@RetoKoradi Thật không may, điều đó có thể sẽ làm chậm chương trình xuống đủ để đưa nó qua mốc 1 phút.
isaacg

Bạn cần khẳng định.h để làm gì?
Max Ried

@MaxRied Nó còn sót lại từ một phiên bản Earlie.
isaacg

3

Perl, bao thanh toán vũ phu

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);

Tôi có thể nhận được khoảng 9e7 trong 25 giây trên máy Linux của mình. Nó có thể nhanh hơn bằng cách đào sâu vào mã C, vì nó đang nói sau khi kiểm tra 2/3/5, hoàn toàn là yếu tố số.

Có nhiều cách thông minh hơn để làm điều này bằng cách sử dụng sàng. Tôi nghĩ rằng một cách vũ phu đơn giản sẽ là một sự khởi đầu. Về cơ bản, đây là vấn đề Project Euler 521.


Nếu nó hoàn toàn hữu ích để biết, trong Python với một cái rây tôi chỉ có thể quản lý T (47000). Tôi sẽ thử một cái gì đó tương tự như những gì bạn đang làm để xem nó có nhanh hơn không.
Kade

Có vẻ như không sử dụng rây nhanh hơn .. Tôi đã có thể tính T (493900) bằng một phương pháp tương tự như của bạn.
Kade

Chưa bao giờ sử dụng Perl trước đây nhưng tôi đã quản lý để xác minh câu trả lời của bạn, tôi sẽ thêm bạn vào danh sách!
Nicolás Siplis

Công bằng mà nói, điều này sử dụng mô-đun của tôi thực hiện bao thanh toán trong C (bạn có thể buộc nó sử dụng Perl thuần túy cho mọi thứ, nhưng tất nhiên nó không nhanh như vậy).
DanaJ

Câu trả lời có thể được tính bằng bất kỳ sự kết hợp ngôn ngữ nào, vì vậy điều đó không sao cả.
Nicolás Siplis

3

Đi, 21e9

Có một sàng để tìm hệ số tối thiểu của mỗi số <= N. Sinh ra các con khỉ đột để đếm các phần của không gian số.

Chạy với "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
}

Lưu ý rằng câu trả lời cho N = 21e9 nằm trong khoảng từ 2 ^ 63 đến 2 ^ 64, vì vậy tôi đã phải sử dụng số nguyên 64 bit không dấu để đếm chính xác ...


Tôi đã phải sửa đổi nó để chạy trên máy của mình (giảm N xuống còn 1e9) nhưng thời gian chạy khá nhanh, hoạt động tốt!
Nicolás Siplis

@ NicolásSiplis: việc sử dụng bộ nhớ đã được sửa.
Keith Randall

Thời gian chạy là 80 giây nhưng 1.6e10 đã được tính gần như chính xác là 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

Java 8: 1.8e8 2.4e8

Mục này không so sánh với một vài trong số những mục khác đã có, nhưng tôi muốn đăng câu trả lời của mình vì tôi rất vui khi làm việc này.

Các tối ưu hóa chính của phương pháp của tôi là như sau:

  • Mỗi số chẵn có hệ số nhỏ nhất là 2, vì vậy những số này có thể được thêm miễn phí sau mỗi số lẻ được xử lý. Về cơ bản, nếu bạn đã thực hiện công việc để tính toán T(N)khi nào N % 2 == 1, bạn biết điều đó T(N + 1) == T(N) + 2. Điều này cho phép tôi bắt đầu đếm ở ba và tăng dần theo số lần lặp.
  • Tôi lưu trữ các số nguyên tố của mình trong một mảng trái ngược với một Collectionloại. Điều này nhiều hơn gấp đôi Ntôi có thể đạt được.
  • Tôi sử dụng các số nguyên tố để tính một số thay vì thực hiện Sàng của Eratosthenes. Điều này có nghĩa là bộ nhớ lưu trữ của tôi bị hạn chế gần như hoàn toàn với mảng số nguyên tố của tôi.
  • Tôi lưu trữ căn bậc hai của số mà tôi đang cố gắng tìm yếu tố nhỏ nhất. Tôi đã thử cách tiếp cận bình phương của một người dùng @ user1354678, nhưng điều này làm tôi mất khoảng 1e7 từ điểm số của mình.

Đó là tất cả về nó. Mã của tôi lặp đi lặp lại từ 3 trở đi cho đến khi nó phát hiện ra rằng nó đã đạt hoặc vượt quá giới hạn thời gian, tại thời điểm đó, nó sẽ đưa ra câu trả lời.

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;
    }
}

Chạy trên một hệ thống khác (Windows 8.1, Intel core i7 @ 2.5 GHz, RAM 8 GB) với phiên bản Java 8 mới nhất có kết quả tốt hơn rõ rệt mà không có thay đổi mã:

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

Nếu bạn có thể thay thế mayContinue()trong for loop conditionchỉ với một điều kiện đơn giản, bạn có thể đạt được kết quả cao hơn. Và tôi thích cách tính toán trước của bạn, thậm chí tăng dần lên hai.
Bộ giải mã

@ user1354678, Cảm ơn bạn đã giới thiệu. Kỳ lạ thay, nó đã không hoạt động. Tôi đã thử các biến thể của mã này trên một máy tính khác và thấy rằng phiên bản được đăng là phiên bản nhanh nhất. Loại bỏ các cuộc gọi đồng hồ khỏi mã và sử dụng một số ngưỡng đơn giản khiến tôi mất hơn một giây. Tôi thậm chí đã thử chuyển đổi startTimesang một endTimeđể loại bỏ các phép trừ ~ 2e7, nhưng điều đó làm tôi mất 3e7 từ điểm số của mình!
sadakatsu ngày 16/07/2015

Bạn đã thử nó chưa System.nanoTime() - startTime < TIME_LIMIT, vì nó làm nhanh mã của bạn một chút cho tôi. Nó không nhanh như vậy, vì thực tế, tình trạng này được kiểm tra hàng triệu lần, nó sẽ nhanh hơn một chút. Một điều tôi học được từ mã của bạn là, đừng đặt forvào bên trong for.. Sau khi chuyển forsang phương thức khác trong mã của tôi, tốc độ mã của tôi tăng 40%, Cảm ơn .. Một điều tôi vẫn nhận ra là, Đã làm mảng hiệu quả hơn nhiều so với ArrayList khi xem xét thực tế rằng nó đã được tải hàng triệu lần ..
Bộ giải mã

Bạn có thể đạt được x2kết quả nếu bạn thực hiện MultiThreading. Nhưng nó sẽ cần phải tính toán trước toàn bộ mảng trước khi chạy phép tính Prime.
Bộ giải mã

@ user1354678, chuyển séc từ mayContinue()phương thức vào vòng lặp for làm tôi mất 8e6 từ điểm số của tôi. Đây có thể là một vấn đề tối ưu hóa địa phương. Tôi đã thử nghiệm với một số loại dữ liệu để lưu trữ các số nguyên tố khi tôi đang phát triển giải pháp này. Tôi chỉ có thể đạt được 8,8e7 ArrayList, nhưng tôi đã đạt 1,8e8 (hiện là 2,4e8) bằng cách sử dụng một mảng. Có thể có một số tăng hiệu suất liên quan đến việc tra cứu, nhưng có những tăng rõ ràng cho việc cấp phát bộ nhớ. Tôi đã nghĩ về thuật toán đa luồng, nhưng tôi gặp vấn đề.
sadakatsu 16/07/2015

1

R, 2,5e7

Sàng có đầu óc đơn giản của Eratosthenes, véc tơ càng nhiều càng tốt. R không thực sự được thiết kế cho loại vấn đề này và tôi khá chắc chắn rằng nó có thể được thực hiện nhanh hơn.

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

Điểm công bằng về T. 2: MAX là một vectơ số nguyên vì vậy đối với các giá trị lớn của MAX, sum(vec)dẫn đến tràn số nguyên và trả về NA. sum(as.numeric(vec))đang tóm tắt một vectơ nhân đôi không tràn (mặc dù nó có thể không đưa ra câu trả lời đúng)
mawir

1

Con trăn, ~ 7e8

Sử dụng một sàng của Erathostenes tăng dần. Một số lưu ý cần phải lưu ý là một giá trị được đánh dấu được đánh dấu bằng ước số thấp nhất của nó, nhưng việc thực hiện lại khá đơn giản.

Thời gian được thực hiện với PyPy 2.6.0, đầu vào được chấp nhận làm đối số dòng lệnh.

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

Sử dụng mẫu

$ pypy sum-lpf.py 10000
5786451

$ pypy sum-lpf.py 100000000
279218813374515

0

Julia, 5e7

Chắc chắn Julia có thể làm tốt hơn nhưng đây là những gì tôi có bây giờ. Điều này thực hiện 5e7 trong khoảng 60 giây trên JuliaBox nhưng tôi chưa thể kiểm tra cục bộ. Hy vọng rằng sau đó tôi sẽ nghĩ ra một cách tiếp cận thông minh hơn.

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

Ở đây chúng ta đang tạo một hàm lpflặp qua các số nguyên tố liên tiếp và kiểm tra đầu vào để phân chia từng cái. Hàm trả về ước số đầu tiên gặp phải, do đó có được thừa số nguyên tố nhỏ nhất.

Hàm chính tính toán lpftrên các số nguyên từ 2 đến đầu vào song song và giảm kết quả bằng cách tính tổng.


0

Lisp thường gặp, 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)))))

Trước tiên tôi đã chọn tạo một danh sách các số nguyên tố từ 2 đến (sqrt input), sau đó kiểm tra mọi giá trị với các số nguyên tố, trong khi trước đó tôi sẽ kiểm tra mọi số lên tới (sqrt input), sẽ vô nghĩa (ví dụ: nếu một số chia hết cho 4, nó cũng chia hết cho 2, vì vậy nó đã được tính đến.)

Cảm ơn Chúa vì tác dụng phụ trong khi tôi đang ở đó. Loại bỏ-nếu cả hai làm giảm kích thước của danh sách và tính xem có bao nhiêu phần tử đã bị xóa, vì vậy tôi chỉ cần nhân số đó với bất kỳ giá trị nào của vòng lặp và thêm nó vào tổng số đang chạy.

(Sự thật thú vị: deletelà tương đương phá hoại remove, nhưng vì bất kỳ lý do gì, deletetất cả đều chậm hơn so với removetrong trường hợp này.)


Chưa bao giờ sử dụng Lisp trước đây, tôi gặp lỗi trình biên dịch khi cố chạy mã của bạn: (defvar Total 0) (defvar counter 0) (defvar input 10000) (số defvar (lặp cho i từ 2 đến đầu vào thu thập i)) ( vòng lặp cho i từ 2 đến (tầng (đầu vào sqrt)) (bộ đếm 0) tổng hợp (prog2 (nsubstolarship-if 0 # '(lambda (x) (if (eq (mod xi) 0) (progn (incf counter) t ))) số) (* i bộ đếm) (số setf (loại bỏ 0 số))) thành tổng cuối cùng (trả về (+ tổng (giảm # '+ số))))
Nicolás Siplis

Tôi đang sử dụng SBCL 1.0,38, nhưng khi về nhà tôi sẽ cập nhật lên phiên bản mới nhất và xem nó hoạt động như thế nào. Nếu bạn lưu nó vào một tệp, bạn có thể chạy nó với "sbcl --script <filename>".
Nến

Tôi đã thử nhưng vẫn không gặp may, chỉ trong trường hợp tôi đã thử biên dịch trực tuyến với Ideone nhưng điều đó cũng không hiệu quả.
Nicolás Siplis

Ồ, xin lỗi, tôi đã quên từ khóa "làm" trên dòng 6. Mặc dù vậy, nó sẽ chạy ngay bây giờ, cho nó một lần nữa.
Nến

Thật tuyệt, nó tính 6e6 sau 60 giây trên máy của tôi! Nhân tiện, nếu tôi quyết định nhập mã của riêng mình, bạn có biết tôi có nên gửi nó dưới dạng câu trả lời không? Tôi không chắc chắn nếu điều đó sẽ cho phép đệ trình mới.
Nicolás Siplis

0

Rỉ 1,5e9

Một cái rây Eratosthene rất ngây thơ, nhưng tôi cảm thấy Rust không nhận được bất kỳ tình yêu nào ở đây!

// 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

Java 2.14e9

Sàng tinh khiết của Eratosthenes với lợi thế của BitSet

Tôi đã tính toán tổng yếu tố Thủ nhỏ tối đa Integer.MAX_VALUE - 1chỉ trong 33.89 s. Nhưng tôi không thể tiến hành lớn hơn bởi vì bất kỳ điều gì nữa sẽ dẫn đến tràn số nguyên trên kích thước của bit. Vì vậy, tôi đang làm việc để tạo ra một Bitset khác cho bộ Ranges tiếp theo. Cho đến lúc đó, đây là cách nhanh nhất tôi có thể tạo.


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());
    }

}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.