Сумма наименьших простых факторов


19

SF (n) - это функция, которая вычисляет наименьший простой множитель для данного числа n.

Мы будем называть T (N) суммой каждого SF (n) с 2 <= n <= N.

T (1) = 0 (сумма превышает 0 слагаемых)

T (2) = 2 (2 - первое простое число)

Т (3) = 5 = 2 + 3

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

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

...

Т (10000) = 5786451

Победителем станет тот, кому удастся вычислить наибольшее значение T (N) за 60 секунд на моем собственном ноутбуке (Toshiba Satellite L845, Intel Core i5, 8 ГБ ОЗУ).


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

Pf (2) = 2, Pf (3) = 3, поэтому T (3) = 2 + 3 = 5. Я прав? Я запрограммирован, чтобы найти основные факторы, но не могли бы вы уточнить о текущем требовании. Спасибо
— Кодер

1
@ToddLehman Я запускаю каждый код на своем ноутбуке (Sony Vaio SVF14A16CLB), поэтому, если это займет менее 60 секунд, я увеличу число и уменьшу его, когда это займет больше времени.
— Николас Сиплис

1
Да, до тех пор , как он работает на своей машине и выдает правильный ответ в течение 60 секунд или меньше, это приемлемо.
— Николас Siplis

1
Имеет 4 темы.
— Николас Siplis

1
Разрешены ли сторонние библиотеки? Это нормально , если программа создания потоков?
— Кодер

Ответы:


12

Nim, 3.6e13

Простое просеивание - не лучший ответ при попытке вычислить максимально возможное значение N, поскольку требования к памяти становятся слишком высокими. Вот другой подход (начатый с Nim пару дней назад и влюбленный в скорость и синтаксис, любые предложения, чтобы сделать его более быстрым или более читабельным, приветствуются!).

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

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

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

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

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

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

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

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

            if u[i]:
                continue

            d = i * p

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

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

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

    sumB[1] + ret

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

Я пытался внедрить обертку GMP для Nim в свой код, но просто не мог заставить ее работать (никогда раньше не использовал GMP, так что это, конечно, не помогло).
— Николас Сиплис

Кроме того, не нужно returnв fопределении «S. Процедуры с одним выражением автоматически возвращаются.
— kirbyfan64sos

3
Это не первый быстрый код , который Nim выиграл заметным отрывом. Может быть стоит исследовать.
— прима

Мне любопытно посмотреть, как он работает при использовании GMP, но не смог правильно его реализовать, несмотря на мои усилия.
— Николас Siplis

Nim определенно идет на моем освоении списка!
— Sp3000

5

C, Prime Сито: 5e9

Результаты:

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

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

Программа:

Хотя это довольно простая программа, мне потребовалось некоторое время, чтобы понять, как правильно управлять памятью - у меня достаточно оперативной памяти только на 1 байт на число в диапазоне, поэтому я должен был быть осторожным. Это стандартное сито Erasthones.

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

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

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

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

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

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

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

1
Если память является проблемой, один бит на число должно быть достаточно. Вы можете использовать битовую маску для хранения флагов.
— Рето Коради

@RetoKoradi К сожалению, это, вероятно , замедлить работу программы достаточно , чтобы поставить его на 1 - й минуте.
— isaacg

Для чего вам нужен assert.h?
— Макс Ried

@MaxRied Он остался от версии earlie.
— Исаак

3

Perl, перебор факторинг

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

Я могу получить до 9e7 в течение 25 секунд на моей машине Linux. Это может быть быстрее, если копаться в коде C, как говорится после проверки на 2/3/5, полностью учитывать число.

Есть гораздо более умные способы сделать это с помощью просеивания. Я думал, что простой перебор путь будет началом. Это в основном Проект Эйлера проблемы 521, кстати.


Если это вообще полезно знать, в Python с ситом можно управлять только Т (47000). Я собираюсь попробовать что - то подобное тому , что вы делаете , чтобы увидеть , если это быстрее.
— Кейд

Похоже, не использовать сито быстрее .. Я смог рассчитать T (493900) с помощью метода, аналогичного вашему.
— Каде

Никогда не использовал Perl раньше , но мне удалось подтвердить свой ответ, я добавлю вас в список!
— Николас Siplis

Чтобы быть справедливым, это использует мой модуль , который делает факторинг в C (вы можете заставить его использовать чистый Perl для всех, но, конечно , это не так быстро).
— DanaJ

Ответ может быть вычислен с использованием любой комбинации языков, так что все нормально.
— Николас Siplis

3

Go, 21e9

Делает ли сито для нахождения минимального множителя для каждого числа <= N. порождает подпрограммы для подсчета разделов числового пространства.

Запуск с "идти работать prime.go -P 4 -N 21000000000".

package main

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

const S = 1 << 16

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

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

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

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

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

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

Обратите внимание, что ответ для N = 21e9 находится между 2 ^ 63 и 2 ^ 64, поэтому мне пришлось использовать 64-разрядные целые числа без знака для правильного подсчета ...


Я должен был изменить его , чтобы работать на моей машине (снижение N до 1e9) , но сама среда довольно быстро, хорошая работа!
— Николас Сиплис

@ NicolásSiplis: использование памяти было исправлено.
— Кит Рэндалл

Время работы составило 80 секунд, но 1.6e10 было рассчитано почти точно за 60!
— Николас Сиплис

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

Эта запись не сравнится с несколькими другими, которые уже есть, но я хотел опубликовать свой ответ, так как мне было весело работать над этим.

Основные оптимизации моего подхода заключаются в следующем:

  • Каждое четное число имеет наименьший коэффициент 2, поэтому их можно добавить бесплатно после обработки каждого нечетного числа. По сути, если вы выполнили работу, чтобы рассчитать, T(N)когда N % 2 == 1, вы это знаете T(N + 1) == T(N) + 2. Это позволяет мне начать отсчет с трех и увеличивать по итерации по два.
  • Я храню мои простые числа в массиве, а не в Collectionтипе. Это более чем вдвое больше, чем Nя могу достичь.
  • Я использую простые числа для вычисления числа в отличие от исполнения Решета Эратосфена. Это означает, что объем моей памяти практически полностью ограничен массивом простых чисел.
  • Я храню квадратный корень числа, для которого я пытаюсь найти наименьший фактор. Я попытался @ подход user1354678 о квадратуре главным фактором каждый раз, но это стоило мне о чем 1e7 от моего счета.

Вот и все, что нужно сделать. Мой код перебирает с 3 по двойками до тех пор, пока не обнаружит, что он ударил или превысил лимит времени, и в этот момент он выплевывает ответ.

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

Работа в другой системе (Windows 8.1, Intel Core i7 @ 2,5 ГГц, 8 ГБ ОЗУ) с последней версией Java 8 заметно улучшила результаты без изменений кода:

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

Если бы вы могли заменить mayContinue()в for loop conditionтолько с условием простого, можно добиться более высокого результата. И мне нравится твой способ предварительного вычисления четной суммы, а затем увеличения на два.
— Кодер

@ user1354678, спасибо за рекомендации. Странно, это не сработало. Я попробовал варианты этого кода на другом компьютере и обнаружил, что опубликованная версия является самой быстрой. Удаление вызовов часов из кода и использование простого порогового числа обошлось мне чуть более секунды. Я даже пытался переключиться startTimeна an, endTimeчтобы исключить вычитания ~ 2e7, но это стоило мне 3e7 из моего счета!
— sadakatsu

Вы пробовали это сделать System.nanoTime() - startTime < TIME_LIMIT, потому что это немного закрепляет ваш код для меня. Это не слишком быстро, учитывая тот факт, что это условие проверяется миллионы раз, оно будет немного быстрым. Одна вещь, которую я узнал из вашего кода, заключается в том, что не помещайте forвнутрь a for.. После перехода forк другому методу в моем коде моя скорость кода увеличивается на 40%, спасибо .. Одна вещь, которую я до сих пор выясняю, состоит в том, делали ли массивы намного эффективнее, чем ArrayList, если учитывать тот факт, что он выбирается миллионы раз ..
— The Coder

Вы могли бы добиться x2результата, если бы вы реализовали MultiThreading. Но необходимо выполнить предварительный расчет всего массива перед запуском вычисления Prime.
— Кодер

@ user1354678, перемещение чека из mayContinue()метода в цикл for будет стоить мне 8e6 из моего счета. Это может быть проблемой локальной оптимизации. Я экспериментировал с несколькими типами данных для хранения простых чисел при разработке этого решения. Я смог достичь только 8.8e7 с ArrayList, но я ударил 1.8e8 (теперь 2.4e8), используя массив. С поиском могут быть некоторые повышения производительности, но есть определенные повышения для выделения памяти. Я думал о многопоточности алгоритма, но столкнулся с проблемами.
— садакацу

1

R 2,5e7

Простое сито из Эратосфена, максимально векторизованное. R на самом деле не предназначен для такого рода проблем, и я уверен, что это можно сделать быстрее.

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

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

Справедливо по поводу T. 2: MAX является вектором целых чисел, поэтому для больших значений MAX sum(vec)приводит к переполнению целого числа и возвращает NA. sum(as.numeric(vec))
— суммирует вектор двойных чисел,

1

Питон, ~ 7e8

Использование добавочного сита из эратостенов. Необходимо позаботиться о том, чтобы помеченное значение было отмечено его самым низким делителем, но в остальном реализация довольно проста.

Время было взято с PyPy 2.6.0, ввод принимается как аргумент командной строки.

from sys import argv
from math import sqrt

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

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

print t

Образец использования

$ pypy sum-lpf.py 10000
5786451

$ pypy sum-lpf.py 100000000
279218813374515

0

Юлия, 5е7

Конечно, Юля может сделать лучше, но это то, что у меня есть сейчас. Это делает 5e7 примерно за 60 секунд на JuliaBox, но я пока не могу проверить локально. Надеюсь, к тому времени я подумаю о более умном подходе.

const PRIMES = primes(2^16)

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

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

Здесь мы создаем функцию, lpfкоторая перебирает последовательные простые числа и проверяет входные данные на делимость для каждого. Функция возвращает первый встреченный делитель, тем самым получая наименьший простой множитель.

Основная функция вычисляет lpfцелые числа от 2 до входных данных параллельно и уменьшает результат путем суммирования.


0

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

Я решил сначала создать список простых чисел от 2 до (sqrt input), а затем проверить каждое значение с помощью простых чисел, тогда как ранее я проверял каждое число до(sqrt input) , что было бы бессмысленно (например, если число делится на 4, оно также делится на 2, поэтому оно уже учтено.)

Слава Богу за побочные эффекты, пока я в этом. Команда remove-if уменьшает размер списка и подсчитывает, сколько элементов было удалено, поэтому мне просто нужно умножить это значение на любое значение цикла и добавить его в промежуточный итог.

(Интересный факт: deleteдеструктивный эквивалент remove, но по какой-то причине он deleteнамного медленнее, чем removeв этом случае.)


Никогда ранее не использовал Lisp, я получаю ошибку компилятора при попытке запустить ваш код: (defvar total 0) (defvar counter 0) (defvar input 10000) (числа defvar (цикл для i от 2 до ввода, собирать i)) ( цикл для i от 2 до (floor (sqrt input)) (setf counter 0) суммирование (prog2 (nsubstitute-if 0 # '' (лямбда (x) (if (eq (mod xi) 0)) (progn (incf counter) t ))) числа) (* i counter) (setf numbers (убрать 0 цифр))) в итоге окончательно (возврат (+ total (уменьшить # '+ числа))))
— Николас Сиплис

Я использую SBCL 1.0.38, но когда я вернусь домой, я обновлюсь до последней версии и посмотрю, как это происходит. Если вы сохраните его в файл, вы можете запустить его с помощью «sbcl --script <filename>».
— свечи

Я пытался, но все равно не повезло, на всякий случай я попытался собрать онлайн с Ideone, но это тоже не сработало.
— Николас Сиплис

Ой, извините, я забыл ключевое слово "do" в строке 6. Теперь оно должно запуститься, дать ему еще один шанс.
— свечи

Отлично, он вычисляет 6e6 за 60 секунд на моей машине! Кстати, если я решу ввести свой собственный код, знаете ли вы, если я должен представить его в качестве ответа? Я не уверен, что это позволит новые представления.
— Николас Сиплис

0

Ржавчина 1.5е9

Очень наивное сито Эратосфена, но я чувствовал, что Руст не получил здесь никакой любви!

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

Я вычислил сумму наименьшего Integer.MAX_VALUE - 1простого множителя до 33.89 s. Но я не могу продолжать дальше, потому что это приведет к переполнению целочисленного размера. Поэтому я работаю над созданием другого набора битов для следующего набора диапазонов. До тех пор, это самый быстрый, который я могу генерировать.


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

import java.util.BitSet;

public class SmallPrimeFactorSum {

    static int    limit     = Integer.MAX_VALUE - 1;

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

    static long   start     = System.nanoTime();

    static long   sum       = 0;

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

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

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

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

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

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

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

}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.