En küçük asal faktörlerin toplamı


19

SF (n), belirli bir n sayısı için en küçük asal çarpanı hesaplayan bir fonksiyondur.

T (N) 'ye 2 <= n <= N olan her SF (n) toplamı diyeceğiz.

T (1) = 0 (toplam 0 toplamın üzerindedir)

T (2) = 2 (2 ilk asal)

T (3) = 5 = 2 + 3

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

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

...

T (10000) = 5786451

Kazanan, kendi dizüstü bilgisayarımda (Toshiba Satellite L845, Intel Core i5, 8GB RAM) en büyük T (N) 'yi 60 saniyede hesaplamayı başaracak.


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

Pf (2) = 2, Pf (3) = 3, Yani, T (3) = 2 + 3 = 5. Haklı mıyım? Temel faktörleri bulmak için programladım, ancak mevcut gereksinim hakkında ayrıntılı bilgi verebilir misiniz? Teşekkür ederim
Coder

1
@ToddLehman Her kodu kendi dizüstü bilgisayarımda (Sony Vaio SVF14A16CLB) çalıştırıyorum, bu yüzden 60 saniyeden daha az sürerse sayıyı artıracağım ve daha uzun sürdüğünde azaltacağım.
Nicolás Siplis

1
Evet, kendi makinemde çalıştığı ve 60 saniye veya daha kısa sürede doğru cevabı verdiği sürece kabul edilebilir.
Nicolás Siplis

1
4 iş parçacığı vardır.
Nicolás Siplis

1
Üçüncü taraf Kütüphanelerine izin veriliyor mu? Program iş parçacıkları oluşturuyorsa sorun değil mi?
Coder

Yanıtlar:


12

Nim, 3.6e13

Hafıza gereksinimleri çok yüksek olduğu için mümkün olan en yüksek N'yi hesaplamaya çalışırken basit eleme en iyi cevap değildir. İşte farklı bir yaklaşım (Nim ile birkaç gün önce başladı ve hız ve sözdizimine aşık oldu, daha hızlı veya daha okunabilir hale getirmek için herhangi bir öneri bekliyoruz!).

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)

Koduma Nim için GMP sarmalayıcı uygulamayı denedim ama sadece işe yaramadı (kesinlikle yardımcı olmadı bu yüzden daha önce hiç GMP kullanılmadı).
Nicolás Siplis

Ayrıca gerek yok returniçinde fbireyin tanımı. Tek ifadeli işlemler otomatik olarak geri döner.
kirbyfan64sos

3
Bu, Nim'in gözle görülür bir farkla kazandığı en hızlı ilk kod değil . Araştırmaya değer olabilir.
primo

GMP kullanırken nasıl performans gösterdiğini merak ediyorum, ancak çabalarıma rağmen doğru bir şekilde uygulayamadım.
Nicolás Siplis

Nim kesinlikle öğrenme listeme gidiyor!
Sp3000

5

C, Ana Elek: 5e9

Sonuçlar:

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

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

Programı:

Oldukça sağlam bir program olsa da, bellek yönetimini nasıl doğru bir şekilde yapacağımı bulmak biraz zaman aldı - aralıktaki sayı başına sadece 1 bayt için yeterli koç var, bu yüzden dikkatli olmalıydım. Erasthones'un standart bir eleği.

#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
Bellek bir sorunsa, sayı başına bir bit yeterli olmalıdır. Bayrakları saklamak için bir bit maskesi kullanabilirsiniz.
Reto Koradi

@RetoKoradi Ne yazık ki, bu muhtemelen programı 1 dakika işareti koymak için yeterince yavaşlatmak olacaktır.
isaacg

Ne için assert.h adresine ihtiyacınız var?
Max Ried

@MaxRied Erken sürümden kaldı.
isaacg

3

Perl, kaba kuvvet faktörü

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 makinemde 25 saniyede 9e7'ye ulaşabilirim. 2/3/5 kontrolünden sonra söylediği gibi, C koduna girerek daha hızlı olabilir.

Eleme kullanarak bunu yapmanın çok daha akıllı yolları vardır. Basit bir kaba kuvvet yolunun bir başlangıç ​​olacağını düşündüm. Bu temelde Project Euler problemi 521'dir.


Python'da bir elek ile bilmek faydalıysa, sadece T'yi (47000) yönetebilirim. Daha hızlı olup olmadığını görmek için yaptıklarınıza benzer bir şey deneyeceğim.
Kade

Elek kullanmamanın daha hızlı olduğu anlaşılıyor .. Sizinkine benzer bir yöntemle T'yi (493900) hesaplayabildim.
Kade

Daha önce hiç Perl kullanmadım ama cevabınızı doğrulamayı başardım, sizi listeye ekleyeceğim!
Nicolás Siplis

Adil olmak gerekirse, bu, C'deki faktoringi yapan modülümü kullanır (her şey için saf Perl kullanmaya zorlayabilirsiniz, ancak elbette o kadar hızlı değildir).
DanaJ

Cevap herhangi bir dil kombinasyonu kullanılarak hesaplanabilir, bu yüzden sorun değil.
Nicolás Siplis

3

Git, 21e9

Her bir sayının minimum faktörünü bulmak için bir elek yapar <= N. Sayı uzayının bölümlerini saymak için goroutinleri yumurtlar.

"Go run prime.go -P 4 -N 21000000000" ile çalıştırın.

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 için cevabın 2 ^ 63 ve 2 ^ 64 arasında olduğunu unutmayın, bu yüzden doğru saymak için imzasız 64-bit ints kullanmak zorundaydım ...


Ben makinemde çalıştırmak için değiştirmek zorunda kaldı (N 1e9 azaldı) ama çalışma zamanı oldukça hızlı, iyi bir iş!
Nicolás Siplis

@ NicolásSiplis: bellek kullanımı düzeltildi.
Keith Randall

Çalışma süresi 80 saniyeydi, ancak 1.6e10 neredeyse 60'da hesaplandı!
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

Bu giriş, şimdiye kadar olan diğer birkaç ile karşılaştırılamıyor, ancak bu konuda eğlendiğim için cevabımı göndermek istedim.

Yaklaşımımın ana optimizasyonları aşağıdaki gibidir:

  • Her çift sayı en küçük 2 faktörüne sahiptir, bu nedenle her tek sayı işlendikten sonra bunlar ücretsiz olarak eklenebilir. Temel olarak, T(N)ne zaman hesaplamak için iş yaptıysanız N % 2 == 1, bunu bilirsiniz T(N + 1) == T(N) + 2. Bu sayıma üçte başlamama ve yineleme ile iki kat artmamı sağlıyor.
  • Asal sayılarmı bir dizinin aksine bir dizide saklıyorum Collection. Bu iki katından fazla Nulaşabilirim.
  • Asal sayıları, Eratosthenes Elekleri yerine bir sayıyı çarpanlarına ayırmak için kullanıyorum. Bu, bellek depolamamın neredeyse tamamen primer dizimle sınırlı olduğu anlamına geliyor.
  • En küçük faktörü bulmaya çalıştığım sayının kare kökünü saklıyorum. @ User1354678'in her seferinde asal bir faktörün karesini alma yaklaşımını denedim, ancak bu puanımdan yaklaşık 1e7'ye mal oldu.

Tüm bunların hepsi bu. Kodum, zaman sınırını vurduğunu veya aştığını algılayana kadar 3'ten iki kez tekrarlar, bu noktada cevabı tükürür.

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'in en son sürümüyle farklı bir sistemde (Windows 8.1, Intel core i7 @ 2.5 GHz, 8 GB RAM) çalışan, kod değişikliği yapılmadan belirgin şekilde daha iyi sonuçlar elde edildi:

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

Değiştirmek olsaydı mayContinue()içinde for loop conditionsadece basit koşulu ile, daha yüksek bir sonuç elde edebiliriz. Ve hatta toplamı önceden hesaplama, sonra ikiye katlama yönteminizi seviyorum.
Coder

@ user1354678, Tavsiye için teşekkürler. Garip bir şekilde, işe yaramadı. Bu kodun varyasyonlarını farklı bir bilgisayarda denedim ve yayınlanan sürümün en hızlı olanı buldum. Saat çağrılarını koddan kaldırmak ve basit bir eşik numarası kullanmak bir saniyeden biraz fazla bir zamana mal oldu. Hatta ~ 2e7 çıkarma ortadan kaldırmak için benim startTimebir geçiş denedim endTime, ama bu benim puan 3e7 maliyeti!
sadakatsu

Bunu denedin mi System.nanoTime() - startTime < TIME_LIMIT, çünkü kodunu benim için biraz sıkıştırır. Şaşırtıcı derecede hızlı değil, bu durumun milyonlarca kez kontrol edildiği gerçeği göz önüne alındığında, biraz hızlı olacak. Kodunuzdan öğrendiğim bir şey, bir kodun foriçine koymayın for.. Kodumdaki forbaşka bir yönteme geçtikten sonra , kod hızım% 40 arttı, teşekkürler .. Hala anlamaya çalıştığım bir şey, diziler mi milyonlarca kez getirildiği gerçeği göz önüne alındığında ArrayList'ten çok etkilidir ..
Coder

Eğer x2uygularsanız sonuç elde edebilirsiniz MultiThreading. Ancak, Prime hesaplamasını çalıştırmadan önce dizinin tamamını yeniden hesaplamanız gerekir.
Coder

@ user1354678, mayContinue()yöntemi yöntemden for döngüsüne taşımak puanımdan 8e6'ya mal oluyor. Bu, yerel optimizasyonlarla ilgili bir sorun olabilir. Bu çözümü geliştirirken primerleri saklamak için çeşitli veri türlerini denedim. Sadece 8.8e7'ye ulaşabildim ArrayList, ama bir dizi kullanarak 1.8e8'e (şimdi 2.4e8) ulaştım. Arama ile ilgili bazı performans artışları olabilir, ancak bellek tahsisi için kesin artışlar vardır. Algoritmayı çok iş parçacıklı hale getirmeyi düşündüm, ama problemlerle karşılaştım.
sadakatsu

1

R, 2.5e7

Eratosthenes'in basit fikirli eleği, mümkün olduğunca vektörleştirildi. R, bu tür bir sorun için gerçekten tasarlanmamıştır ve daha hızlı yapılabileceğinden eminim.

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 hakkında adil bir nokta 2: MAX, tamsayıların bir vektörüdür, bu nedenle MAX'un büyük değerleri sum(vec)için bir tamsayı taşmasına yol açar ve NA değerini döndürür. sum(as.numeric(vec))
taşmıyor

1

Python, ~ 7e8

Artımlı Erathostenes Elek Kullanımı. Belirgin bir değerin en düşük böleniyle işaretlendiğine dikkat etmek gerekir, ancak uygulama aksi halde oldukça basittir.

Zamanlama PyPy 2.6.0 ile alındı, girdi bir komut satırı argümanı olarak kabul edildi.

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

Örnek Kullanımı

$ pypy sum-lpf.py 10000
5786451

$ pypy sum-lpf.py 100000000
279218813374515

0

Julia, 5e7

Elbette Julia daha iyisini yapabilir ama şimdilik elimde olan bu. Bu JuliaBox üzerinde yaklaşık 60 saniye içinde 5e7 yok ama henüz yerel olarak test edemez. Umarım o zamana kadar daha akıllı bir yaklaşım düşünürüm.

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

Burada lpfsıralı asallar boyunca yinelenen ve her biri tarafından bölünebilirlik için girdiyi kontrol eden bir işlev oluşturuyoruz . Fonksiyon karşılaşılan ilk böleni döndürür, böylece en küçük asal çarpanı elde eder.

Ana işlev lpf, 2'den girişe paralel tamsayıları hesaplar ve toplayarak sonucu azaltır.


0

Yaygın Lisp, 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)))))

İlk önce 2'den asal sayıların bir listesini oluşturmayı seçtim (sqrt input), daha sonra her bir değeri asallarla test ettim (sqrt input), daha önce anlamsız olan her sayıya karşı test ederdim (örneğin, bir sayı 4'e bölünebilirse, ayrıca 2'ye bölünebilir, bu yüzden zaten hesaba katılmıştır.)

Ben yanınızdayken yan etkiler için şükürler olsun. Remove-if hem listenin boyutunu düşürür hem de kaç öğenin kaldırıldığını sayar, bu yüzden döngüde hangi değerle olursa olsun bunu çarparak toplam toplama eklemeliyim.

(Eğlenceli gerçek: deleteyıkıcı eşdeğeridir remove, ancak her ne sebeple olursa olsun, bu durumda deleteolduğundan daha yavaştır remove.)


Daha önce hiç Lisp kullanmadım, kodunuzu çalıştırmaya çalışırken bir derleyici hatası alıyorum: (defvar toplam 0) (defvar sayacı 0) (defvar giriş 10000) (defvar numaraları (2'den giriş toplama i'ye döngü)) ( i için 2'den (kat (sqrt girişi)) (setf sayacı 0) toplaması (prog2 (nsubstitute-if 0 # '(lambda (x)) (if (eq (mod xi) 0)) ))) sayılar) (* i sayacı) (setf sayıları (0 sayılarını kaldır))) nihayetinde toplam (dönüş (+ toplam (# '+ sayıları azalt)))))
Nicolás Siplis

SBCL 1.0.38 kullanıyorum, ancak eve geldiğimde en son sürüme güncelleyeceğim ve nasıl gittiğini göreceğim. Bir dosyaya kaydederseniz, dosyayı "sbcl --script <filename>" ile çalıştırabilirsiniz.
Mumlar

Denedim ama hala şans yok, sadece Ideone ile çevrimiçi derlemeyi denedim ama bu da işe yaramadı.
Nicolás Siplis

Oh, özür dilerim, 6. satırdaki "do" anahtar kelimesini unuttum. Şimdi çalıştırılmalı, başka bir çekim yapmalı.
Mumlar

Harika, makinemde 60 saniyede 6e6 hesaplıyor! Bu arada, kendi kodumu girmeye karar verirsem, cevap olarak göndermem gerekip gerekmediğini biliyor musunuz? Bunun yeni gönderimlere izin verip vermeyeceğinden emin değilim.
Nicolás Siplis

0

Pas 1.5e9

Çok naif bir Eratosthene eleği, ama Rust'un burada hiç sevgi almadığını hissettim!

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

BitSet'in avantajı ile Saf Eratosthenes Elek

Ben kadar küçük Prime faktör toplamı hesapladılar Integer.MAX_VALUE - 1sadece 33.89 s. Ama daha büyük ilerleyemem çünkü daha fazlası Bitset'in Boyutunda Tamsayı Taşmasına neden olacak. Bu yüzden bir sonraki Aralık kümesi için başka bir Bitset oluşturmaya çalışıyorum. O zamana kadar üretebildiğim en hızlı şey bu.


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

}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.