Somme des plus petits facteurs premiers


19

SF (n) est une fonction qui calcule le plus petit facteur premier pour un nombre n donné.

Nous appellerons T (N) la somme de chaque SF (n) avec 2 <= n <= N.

T (1) = 0 (la somme est supérieure à 0 somme)

T (2) = 2 (2 est le premier nombre premier)

T (3) = 5 = 2 + 3

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

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

...

T (10000) = 5786451

Le gagnant sera celui qui parvient à calculer le plus grand T (N) en 60 secondes sur mon propre ordinateur portable (Toshiba Satellite L845, Intel Core i5, 8 Go de RAM).


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

Pf (2) = 2, Pf (3) = 3, donc, T (3) = 2 + 3 = 5. Ai-je raison? J'ai programmé pour trouver des facteurs premiers, mais pourriez-vous élaborer sur l'exigence actuelle. Merci
Le codeur

1
@ToddLehman J'exécute chaque code dans mon propre ordinateur portable (Sony Vaio SVF14A16CLB), donc si cela prend moins de 60 secondes, j'augmente le nombre et le diminue lorsqu'il prend plus de temps.
Nicolás Siplis

1
Oui, tant qu'il fonctionne sur ma propre machine et génère la bonne réponse en 60 secondes ou moins, c'est acceptable.
Nicolás Siplis

1
Il a 4 fils.
Nicolás Siplis

1
Les bibliothèques tierces sont-elles autorisées? C'est ok si le programme crée des threads?
The Coder

Réponses:


12

Nim, 3.6e13

Le simple tamisage n'est pas la meilleure réponse lorsque vous essayez de calculer le N le plus élevé possible car les besoins en mémoire deviennent trop élevés. Voici une approche différente (commencé avec Nim il y a quelques jours et tombé amoureux de la vitesse et de la syntaxe, toutes les suggestions pour le rendre plus rapide ou plus lisible sont les bienvenues!).

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)

J'ai essayé d'implémenter le wrapper GMP pour Nim dans mon code, mais je n'ai tout simplement pas pu le faire fonctionner (jamais utilisé GMP auparavant, ce qui n'a certainement pas aidé).
Nicolás Siplis

Vous n'avez pas non plus besoin de la définition de returnin f. Les procs d'expression simple reviennent automatiquement.
kirbyfan64sos

3
Ce n'est pas le premier code le plus rapide que Nim a remporté par une marge notable. Cela pourrait valoir la peine d'être étudié.
primo

Je suis curieux de voir ses performances lors de l'utilisation de GMP, mais je n'ai pas pu l'implémenter correctement malgré mes efforts.
Nicolás Siplis

Nim est définitivement sur ma liste à apprendre!
Sp3000

5

C, tamis principal: 5e9

Résultats:

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

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

Programme:

Bien que ce soit un programme plutôt simple, il m'a fallu un certain temps pour comprendre comment gérer la mémoire correctement - je n'ai que suffisamment de RAM pour 1 octet par numéro dans la plage, j'ai donc dû faire attention. C'est un tamis standard d'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
Si la mémoire est un problème, un bit par nombre devrait suffire. Vous pouvez utiliser un masque de bits pour stocker les indicateurs.
Reto Koradi

@RetoKoradi Malheureusement, cela ralentirait probablement le programme suffisamment pour le faire passer la barre des 1 minute.
isaacg

Pourquoi avez-vous besoin de assert.h?
Max Ried

@MaxRied Il a été laissé à partir d'une version earlie.
isaacg

3

Perl, affacturage par force brute

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

Je peux atteindre environ 9e7 en 25 secondes sur ma machine Linux. Cela pourrait être plus rapide en fouillant dans le code C, comme il est dit après une vérification des 2/3/5, factorisez complètement le nombre.

Il existe des moyens beaucoup plus intelligents de le faire en utilisant le tamisage. Je pensais qu'un simple moyen de force brute serait un début. Il s'agit en fait du problème 521 de Project Euler.


S'il est utile de le savoir, en Python avec un tamis je ne peux gérer que T (47000). Je vais essayer quelque chose de similaire à ce que vous faites pour voir si c'est plus rapide.
Kade

On dirait que ne pas utiliser de tamis est plus rapide .. J'ai pu calculer T (493900) avec une méthode similaire à la vôtre.
Kade

Jamais utilisé Perl mais j'ai réussi à vérifier votre réponse, je vais vous ajouter à la liste!
Nicolás Siplis

Pour être honnête, cela utilise mon module qui fait la factorisation en C (vous pouvez le forcer à utiliser du Perl pur pour tout, mais bien sûr ce n'est pas aussi rapide).
DanaJ

La réponse peut être calculée en utilisant n'importe quelle combinaison de langues, donc c'est OK.
Nicolás Siplis

3

Go, 21e9

Fait un tamis pour trouver le facteur minimum de chaque nombre <= N. Fait apparaître des goroutines pour compter les sections de l'espace numérique.

Exécutez avec "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
}

Notez que la réponse pour N = 21e9 se situe entre 2 ^ 63 et 2 ^ 64, j'ai donc dû utiliser des entiers 64 bits non signés pour compter correctement ...


J'ai dû le modifier pour qu'il fonctionne sur ma machine (N réduit à 1e9) mais le temps d'exécution lui-même est assez rapide, bon travail!
Nicolás Siplis

@ NicolásSiplis: l'utilisation de la mémoire a été corrigée.
Keith Randall

Le temps d'exécution était de 80 secondes mais 1,6e10 a été calculé en presque exactement 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

Cette entrée ne se compare pas à plusieurs autres déjà en place, mais je voulais poster ma réponse car je me suis amusé à travailler dessus.

Les principales optimisations de mon approche sont les suivantes:

  • Chaque nombre pair a un plus petit facteur de 2, donc ceux-ci peuvent être ajoutés gratuitement après le traitement de chaque nombre impair. En gros, si vous avez fait le travail pour calculer T(N)quand N % 2 == 1, vous le savez T(N + 1) == T(N) + 2. Cela me permet de commencer mon comptage à trois et d'incrémenter par itération par deux.
  • Je stocke mes nombres premiers dans un tableau par opposition à un Collectiontype. Cela a plus que doublé le nombre que Nje peux atteindre.
  • J'utilise les nombres premiers pour factoriser un nombre par opposition à effectuer le tamis d'Ératosthène. Cela signifie que mon stockage en mémoire est limité presque complètement à mon tableau de nombres premiers.
  • Je stocke la racine carrée du nombre pour lequel j'essaie de trouver le plus petit facteur. J'ai essayé l'approche de @ user1354678 de la quadrature d'un facteur premier à chaque fois, mais cela m'a coûté environ 1e7 d'après mon score.

C'est à peu près tout. Mon code réitère à partir de 3 par deux jusqu'à ce qu'il détecte qu'il a atteint ou dépassé le délai, auquel cas il crache la réponse.

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

Fonctionnant sur un système différent (Windows 8.1, Intel Core i7 @ 2,5 GHz, 8 Go de RAM) avec la dernière version de Java 8 a des résultats nettement meilleurs sans changement de code:

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

Si vous pouviez remplacer mayContinue()dans for loop conditionavec juste une condition simple, vous pouvez obtenir le résultat plus élevé. Et j'aime votre façon de précalculer la somme paire, puis de l'incrémenter de deux.
The Coder

@ user1354678, Merci pour la recommandation. Étrangement, cela n'a pas fonctionné. J'ai essayé des variantes de ce code sur un autre ordinateur et j'ai constaté que la version publiée était la plus rapide. Supprimer les appels d'horloge du code et utiliser un simple numéro de seuil m'a coûté un peu plus d'une seconde. J'ai même essayé de passer startTimeà un endTimepour éliminer les soustractions ~ 2e7, mais cela m'a coûté 3e7 de mon score!
sadakatsu

L'avez-vous essayé avec System.nanoTime() - startTime < TIME_LIMIT, car il fixe un peu votre code pour moi. Ce n'est pas incroyablement rapide, compte tenu du fait, cette condition est vérifiée des millions de fois, ce sera un peu rapide. Une chose que j'ai apprise de votre code est, ne mettez pas à l' forintérieur d'un for.. Après être passé forà une autre méthode dans mon code, la vitesse de mon code augmente de 40%, merci .. Une chose que je comprends toujours, c'est que les tableaux sont beaucoup plus efficaces que ArrayList si l'on considère le fait qu'il est récupéré des millions de fois ..
The Coder

Vous pourriez obtenir des x2résultats si vous implémentez MultiThreading. Mais il faudrait précalculer l'ensemble du tableau avant d'exécuter le calcul Prime.
The Coder

@ user1354678, déplacer le chèque de la mayContinue()méthode dans la boucle for me coûte 8e6 de mon score. Cela peut être un problème d'optimisations locales. J'ai expérimenté plusieurs types de données pour stocker les nombres premiers lorsque je développais cette solution. Je n'ai pu atteindre que 8.8e7 avec ArrayList, mais j'ai atteint 1.8e8 (maintenant 2.4e8) en utilisant un tableau. Il peut y avoir des augmentations de performances impliquées avec la recherche, mais il existe des augmentations définies pour l'allocation de mémoire. J'ai pensé au multi-threading de l'algorithme, mais j'ai rencontré des problèmes.
sadakatsu

1

R, 2,5e7

Tamis simple d'ératosthène, vectorisé autant que possible. Les R ne sont pas vraiment conçus pour ce genre de problème et je suis sûr qu'il peut être fait plus rapidement.

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

Juste point sur T. 2: MAX est un vecteur d'entiers donc pour de grandes valeurs de MAX, sum(vec)conduit à un débordement d'entier et retourne NA. sum(as.numeric(vec))résume un vecteur de doubles qui ne déborde pas (bien qu'il ne donne pas la bonne réponse)
mawir

1

Python, ~ 7e8

Utilisation d'un tamis incrémental d'Erathostènes. Il faut prendre soin qu'une valeur marquée soit marquée avec son plus petit diviseur, mais l'implémentation est par ailleurs assez simple.

La synchronisation a été prise avec PyPy 2.6.0, l'entrée est acceptée comme argument de ligne de commande.

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

Exemple d'utilisation

$ pypy sum-lpf.py 10000
5786451

$ pypy sum-lpf.py 100000000
279218813374515

0

Julia, 5e7

Julia peut sûrement faire mieux, mais c'est ce que j'ai pour l'instant. Cela fait 5e7 en environ 60 secondes sur JuliaBox mais je ne peux pas encore tester localement. J'espère que d'ici là, j'aurai pensé à une approche plus 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

Ici, nous créons une fonction lpfqui itère à travers des nombres premiers séquentiels et vérifie la divisibilité de l'entrée par chacun. La fonction renvoie le premier diviseur rencontré, obtenant ainsi le plus petit facteur premier.

La fonction principale calcule lpfsur les entiers de 2 à l'entrée en parallèle et réduit le résultat en sommant.


0

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

J'ai choisi de générer d'abord une liste de nombres premiers de 2 à (sqrt input), puis de tester chaque valeur avec les nombres premiers, alors qu'auparavant je testais contre chaque nombre jusqu'à (sqrt input), ce qui serait inutile (par exemple, si un nombre est divisible par 4, il est également divisible par 2, il est donc déjà pris en compte.)

Dieu merci pour les effets secondaires pendant que j'y suis. Le retrait-si à la fois réduit la taille de la liste et compte le nombre d'éléments supprimés, il me suffit donc de multiplier cela par la valeur de la boucle et de l'ajouter au total cumulé.

(Fait amusant: deleteest l'équivalent destructeur de remove, mais pour une raison quelconque, il deleteest de toutes sortes plus lent que removedans ce cas.)


Jamais utilisé Lisp auparavant, j'obtiens une erreur de compilation lorsque j'essaie d'exécuter votre code: (defvar total 0) (defvar counter 0) (defvar input 10000) (defvar numbers (loop for i from 2 to input collect i)) ( boucle pour i de 2 à (étage (entrée sqrt)) (compteur setf 0) sommation (prog2 (nsubstitute-if 0 # ') (lambda (x) (if (eq (mod xi) 0) (progn (compteur incf) t ))) nombres) (* compteur i) (setf nombres (supprimer 0 nombres))) en total finalement (retour (+ total (réduire # '+ nombres)))))
Nicolás Siplis

J'utilise SBCL 1.0.38, mais quand je rentrerai à la maison, je mettrai à jour la dernière version et voir comment ça se passe. Si vous l'enregistrez dans un fichier, vous pouvez l'exécuter avec "sbcl --script <nom de fichier>".
Bougies

J'ai essayé mais toujours pas de chance, juste au cas où j'aurais essayé de compiler en ligne avec Ideone mais cela n'a pas fonctionné non plus.
Nicolás Siplis

Oh, désolé, j'ai oublié le mot-clé "do" à la ligne 6. Il devrait cependant s'exécuter maintenant, essayez à nouveau.
Bougies

Génial, il calcule 6e6 en 60 secondes sur ma machine! Au fait, si je décide d'entrer mon propre code, savez-vous si je dois le soumettre comme réponse? Je ne sais pas si cela permettrait de nouvelles soumissions.
Nicolás Siplis

0

Rouille 1.5e9

Un tamis Eratosthene très naïf, mais je sentais que Rust n'avait reçu aucun amour ici!

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

Tamis pur d'Ératosthène avec avantage de BitSet

J'ai calculé la plus petite somme du facteur premier jusqu'à Integer.MAX_VALUE - 1juste en dedans 33.89 s. Mais je ne peux pas continuer plus loin car tout autre entraînera un débordement d'entier sur la taille du Bitset. Je travaille donc sur la création d'un autre ensemble de bits pour le prochain ensemble de plages. Jusque-là, c'est le plus rapide que je puisse générer.


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

}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.