Somma dei più piccoli fattori primi


19

SF (n) è una funzione che calcola il fattore primo più piccolo per un dato numero n.

Chiameremo T (N) la somma di ogni SF (n) con 2 <= n <= N.

T (1) = 0 (la somma è superiore a 0 somme)

T (2) = 2 (2 è il primo primo)

T (3) = 5 = 2 + 3

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

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

...

T (10000) = 5786451

Il vincitore sarà colui che riuscirà a calcolare la più grande T (N) in 60 secondi sul mio laptop (Toshiba Satellite L845, Intel Core i5, 8GB RAM).


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

Pf (2) = 2, Pf (3) = 3, So, T (3) = 2 + 3 = 5. Ho ragione? Ho programmato per trovare i fattori primi, ma potresti approfondire il requisito attuale. Grazie
The Coder,

1
@ToddLehman Sto eseguendo ogni codice sul mio laptop (Sony Vaio SVF14A16CLB), quindi se impiega meno di 60 secondi aumenterò il numero e lo diminuirò quando ci vorrà più tempo.
Nicolás Siplis,

1
Sì, purché funzioni sulla mia macchina e produca la risposta corretta in 60 secondi o meno, è accettabile.
Nicolás Siplis,

1
Ha 4 discussioni.
Nicolás Siplis,

1
Sono consentite librerie di terze parti? Va bene se il programma sta creando thread?
The Coder,

Risposte:


12

Nim, 3.6e13

Il semplice setacciamento non è la risposta migliore quando si cerca di calcolare la N più alta possibile poiché i requisiti di memoria diventano troppo elevati. Ecco un approccio diverso (iniziato con Nim un paio di giorni fa e innamorato della velocità e della sintassi, qualsiasi suggerimento per renderlo più veloce o più leggibile è il benvenuto!).

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)

Ho provato a implementare il wrapper GMP per Nim nel mio codice ma non sono riuscito a farlo funzionare (non ho mai usato GMP prima, quindi sicuramente non ha aiutato).
Nicolás Siplis,

Inoltre non è necessario il returndi f's definizione. I proc a espressione singola ritornano automaticamente.
Kirbyfan64sos,

3
Questo non è il primo codice più veloce che Nim ha vinto con un notevole margine. Potrebbe valere la pena indagare.
primo

Sono curioso di vedere come si comporta quando si utilizza GMP, ma non sono riuscito a implementarlo correttamente nonostante i miei sforzi.
Nicolás Siplis,

Nim sta sicuramente andando nella mia lista di apprendimenti!
Sp3000,

5

C, setaccio principale: 5e9

risultati:

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

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

Programma:

Sebbene sia un programma piuttosto intuitivo, mi ci è voluto un po 'di tempo per capire come gestire correttamente la memoria: ho solo ram sufficiente per 1 byte per numero nell'intervallo, quindi ho dovuto fare attenzione. È un setaccio standard di 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
Se la memoria è un problema, dovrebbe essere sufficiente un bit per numero. È possibile utilizzare una maschera di bit per memorizzare i flag.
Reto Koradi,

@RetoKoradi Sfortunatamente, questo probabilmente rallenterebbe il programma abbastanza da metterlo oltre il segno di 1 minuto.
Isaacg,

Per cosa hai bisogno di assert.h?
Max Ried,

@MaxRied È stato lasciato da una versione earlie.
Isaacg,

3

Perl, factoring a forza bruta

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

Posso arrivare a circa 9e7 in 25 secondi sul mio computer Linux. Potrebbe essere più veloce scavando nel codice C, come sta dicendo dopo un controllo per 2/3/5, fattore completamente il numero.

Ci sono modi molto più intelligenti per farlo usando il setaccio. Ho pensato che un semplice modo di forza bruta sarebbe stato un inizio. Questo è fondamentalmente il problema del Project Euler 521, comunque.


Se è utile saperlo, in Python con un setaccio posso solo gestire T (47000). Proverò qualcosa di simile a quello che stai facendo per vedere se è più veloce.
Kade,

Sembra che non usare un setaccio sia più veloce .. Sono stato in grado di calcolare T (493900) con un metodo simile al tuo.
Kade,

Non ho mai usato Perl prima ma sono riuscito a verificare la tua risposta, ti aggiungerò alla lista!
Nicolás Siplis,

Ad essere sinceri, questo usa il mio modulo che fa il factoring in C (puoi forzarlo ad usare il Perl puro per tutto, ma ovviamente non è così veloce).
DanaJ,

La risposta può essere calcolata usando qualsiasi combinazione di lingue, quindi va bene.
Nicolás Siplis,

3

Vai, 21e9

Fa un setaccio per trovare il fattore minimo di ogni numero <= N. Genera goroutine per contare sezioni dello spazio numerico.

Esegui con "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
}

Nota che la risposta per N = 21e9 è compresa tra 2 ^ 63 e 2 ^ 64, quindi ho dovuto usare ints a 64 bit senza segno per contare correttamente ...


Ho dovuto modificarlo per funzionare sulla mia macchina (ridotto da N a 1e9) ma l'autonomia stessa è piuttosto veloce, buon lavoro!
Nicolás Siplis,

@ NicolásSiplis: l'utilizzo della memoria è stato corretto.
Keith Randall,

Il tempo di esecuzione è stato di 80 secondi, ma 1.6e10 è stato calcolato in quasi esattamente 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

Questa voce non è paragonabile a molte altre già presenti, ma ho voluto pubblicare la mia risposta poiché mi sono divertito a lavorarci su.

Le principali ottimizzazioni del mio approccio sono le seguenti:

  • Ogni numero pari ha un fattore minimo di 2, quindi questi possono essere aggiunti gratuitamente dopo l'elaborazione di ogni numero dispari. Fondamentalmente, se hai fatto il lavoro per calcolare T(N)quando N % 2 == 1, lo sai T(N + 1) == T(N) + 2. Questo mi permette di iniziare il mio conteggio da tre e di aumentare di iterazione per due.
  • Conservo i miei numeri primi in un array anziché in un Collectiontipo. Questo è più che raddoppiato Nche posso raggiungere.
  • Uso i numeri primi per fattorizzare un numero anziché eseguire il setaccio di Eratostene. Ciò significa che la mia memoria è limitata quasi completamente al mio array di numeri primi.
  • Conservo la radice quadrata del numero per il quale sto cercando di trovare il fattore più piccolo. Ho provato l'approccio di @ user1354678 di quadrare un fattore primo ogni volta, ma questo mi è costato circa 1e7 dal mio punteggio.

Questo è tutto quello che c'è da fare. Il mio codice scorre da 3 in poi fino a quando non rileva che ha raggiunto o superato il limite di tempo, a quel punto sputa la risposta.

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

L'esecuzione su un altro sistema (Windows 8.1, Intel Core i7 a 2,5 GHz, 8 GB RAM) con l'ultima versione di Java 8 ha risultati notevolmente migliori senza modifiche al codice:

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

Se si potesse sostituire mayContinue()in for loop conditioncon solo una semplice condizione, si potrebbe ottenere un risultato più elevato. E mi piace il tuo modo di precalcolare la somma pari, quindi incrementare di due.
The Coder,

@ user1354678, Grazie per la raccomandazione. Stranamente, non ha funzionato. Ho provato varianti di questo codice su un altro computer e ho scoperto che la versione pubblicata è la più veloce. Rimuovere le chiamate di clock dal codice e usare un semplice numero di tre cifre mi è costato poco più di un secondo. Ho anche provato a passare startTimea un endTimeper eliminare le sottrazioni ~ 2e7, ma questo mi è costato 3e7 dal mio punteggio!
Sadakatsu,

L'hai provato con System.nanoTime() - startTime < TIME_LIMIT, perché mi fissa un po 'il codice. Non è incredibilmente veloce, considerando il fatto, questa condizione viene controllata milioni di volte, sarà un po 'veloce. Una cosa che ho imparato dal tuo codice è, non mettere fordentro un for.. Dopo foressermi spostato in un altro metodo nel mio codice, la mia velocità del codice viene aumentata del 40%, grazie. sono molto più efficienti di ArrayList se si considera il fatto che è stato recuperato milioni di volte ..
The Coder

È possibile ottenere x2risultati se si implementa MultiThreading. Ma dovrebbe precalcolare l'intero array prima di eseguire il calcolo Prime.
The Coder,

@utente1354678, spostare il controllo dal mayContinue()metodo nel ciclo for mi costa 8e6 dal mio punteggio. Questo potrebbe essere un problema di ottimizzazioni locali. Ho sperimentato diversi tipi di dati per archiviare i numeri primi durante lo sviluppo di questa soluzione. Sono stato in grado di raggiungere solo 8.8e7 con ArrayList, ma ho colpito 1.8e8 (ora 2.4e8) usando un array. Potrebbero esserci alcuni aumenti delle prestazioni coinvolti nella ricerca, ma ci sono aumenti definiti per l'allocazione della memoria. Ho pensato di eseguire il multithreading dell'algoritmo, ma ho riscontrato problemi.
Sadakatsu,

1

R, 2,5e7

Setaccio semplice di Eratostene, vettorializzato il più possibile. R non è davvero progettato per questo tipo di problema e sono abbastanza sicuro che possa essere reso più veloce.

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

Punto giusto su T. 2: MAX è un vettore di numeri interi, quindi per valori grandi di MAX, sum(vec)si verifica un overflow di numeri interi e restituisce NA. sum(as.numeric(vec))sta sommando un vettore di doppi che non trabocca (anche se potrebbe non dare la risposta giusta)
mawir

1

Python, ~ 7e8

Utilizzando un setaccio incrementale di eratostene. È necessario prestare attenzione al fatto che un valore contrassegnato sia contrassegnato con il suo divisore più basso, ma l'implementazione è piuttosto semplice.

Il tempismo è stato preso con PyPy 2.6.0, l'input è accettato come argomento della riga di comando.

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

Esempio di utilizzo

$ pypy sum-lpf.py 10000
5786451

$ pypy sum-lpf.py 100000000
279218813374515

0

Julia, 5e7

Sicuramente Julia può fare di meglio, ma questo è quello che ho per ora. Questo fa 5e7 in circa 60 secondi su JuliaBox ma non riesco ancora a testare localmente. Spero che a quel punto avrò pensato a un approccio più intelligente.

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

Qui stiamo creando una funzione lpfche scorre attraverso numeri primi sequenziali e controlla l'input per divisibilità per ciascuno. La funzione restituisce il primo divisore incontrato, ottenendo così il fattore primo minimo.

La funzione principale calcola lpfsugli interi da 2 all'ingresso in parallelo e riduce il risultato sommando.


0

Lisp comune, 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)))))

Ho scelto di generare prima un elenco di numeri primi da 2 a (sqrt input), quindi testare ogni valore con i numeri primi, mentre in precedenza avrei testato ogni numero fino a (sqrt input), il che sarebbe inutile (ad esempio, se un numero è divisibile per 4, è anche divisibile per 2, quindi è già rappresentato.)

Grazie a Dio per gli effetti collaterali mentre ci sono. La rimozione-se entrambi riduce la dimensione dell'elenco e conta quanti elementi sono stati rimossi, quindi devo solo moltiplicarlo per qualunque valore il ciclo sia attivo e aggiungerlo nel totale parziale.

(Fatto curioso: deleteè l'equivalente distruttivo di remove, ma per qualsiasi motivo, deleteè di gran lunga più lento che removein questo caso.)


Non ho mai usato Lisp prima, ricevo un errore del compilatore quando provo a eseguire il codice: (defvar total 0) (defvar counter 0) (defvar input 10000) (defvar input (loop for i from 2 to input collect i)) ( loop per i da 2 a (floor (input sqrt)) (setf counter 0) summing (prog2 (nsubstitute-if 0 # '(lambda (x) (if (eq (mod xi) 0) (progn (contatore incf) t ))) numeri) (* contatore i) (imposta numeri (rimuovi 0 numeri))) nel totale (ritorno (+ totale (riduci # '+ numeri)))))
Nicolás Siplis,

Sto usando SBCL 1.0.38, ma quando torno a casa mi aggiorno all'ultima versione e vedo come va. Se lo salvi in ​​un file, puoi eseguirlo con "sbcl --script <nomefile>".
Candele,

Ho provato, ma ancora senza fortuna, nel caso in cui ho provato a compilare online con Ideone, ma non ha funzionato neanche.
Nicolás Siplis,

Oh, scusa, ho dimenticato la parola chiave "do" nella riga 6. Dovrebbe essere eseguito ora, però, dagli un'altra possibilità.
Candele,

Fantastico, calcola 6e6 in 60 secondi sulla mia macchina! A proposito, se decido di inserire il mio codice, sai se dovrei inviarlo come risposta? Non sono sicuro che ciò consentirebbe nuovi invii.
Nicolás Siplis,

0

Ruggine 1.5e9

Un setaccio Eratostene molto ingenuo, ma ho sentito che Rust non ha ricevuto alcun amore qui!

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

Setaccio puro di Eratostene con vantaggio di BitSet

Ho calcolato la somma del fattore Primo più piccolo fino a Integer.MAX_VALUE - 1poco fa 33.89 s. Ma non posso procedere più grande perché qualsiasi ulteriore porterà a Overflow intero sulla dimensione del Bitset. Quindi sto lavorando per creare un altro Bitset per il prossimo set di Ranges. Fino ad allora, questo è il più veloce che sono in grado di generare.


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

}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.