最小素因数の合計


19

SF(n)は、指定された数値nに対して最小の素因数を計算する関数です。

T(N)を2 <= n <= NのすべてのSF(n)の合計と呼びます。

T(1)= 0(合計は0の被加数以上)

T(2)= 2(2は最初の素数)

T(3)= 5 = 2 + 3

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

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

...

T(10000)= 5786451

勝者は、自分のラップトップ(Toshiba Satellite L845、Intel Core i5、8GB RAM)で60秒で最大のT(N)を計算することに成功した人です。


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秒以内に正しい答えを出力する限り、許容できます。
ニコラスシプリス

1
4つのスレッドがあります。
ニコラスシプリス

1
サードパーティのライブラリは許可されていますか?プログラムがスレッドを作成していても大丈夫ですか?
コーダー

回答:


12

ニム、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)

NimのGMPラッパーをコードに実装しようとしましたが、動作させることができませんでした(以前はGMPを使用したことがないため、確かに役に立たなかった)。
ニコラスシプリス

returnin fの定義も必要ありません。単一式のプロシージャは自動的に戻ります。
kirbyfan64sos

3
これは、Nimが目立ったマージンで獲得した最初の最速コードではありません。調査する価値があるかもしれません。
プリモ

GMPを使用したときの動作を確認したいのですが、努力しても正しく実装できませんでした。
ニコラスシプリス

Nimは間違いなく私の学習リストに載っています!
Sp3000

5

C、プライムシーブ:5e9

結果:

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

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

プログラム:

それはかなり率直なプログラムですが、メモリ管理を正しくする方法を見つけるのに時間がかかりました-私は範囲内の数字ごとに1バイトのRAMしか持っていないので、注意しなければなりませんでした。エラストーンの標準的なふるいです。

#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
メモリが問題になる場合は、数字ごとに1ビットで十分です。ビットマスクを使用してフラグを保存できます。
レトコラディ

@RetoKoradi残念ながら、それはおそらく1分を超えるほどプログラムを遅くするでしょう。
isaacg

assert.hには何が必要ですか?
マックスリード

@MaxRiedそれは初期のバージョンから残っていました。
isaacg

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

Linuxマシンでは25秒で約9e7に到達できます。Cコードを掘り下げると、2/3/5をチェックした後、数値を完全に因数分解することになるため、高速になる可能性があります。

ふるいを使用してこれを行うはるかに賢い方法があります。単純なブルートフォースの方法が出発点になると思いました。ちなみに、これは基本的にProject Euler問題521です。


知っておくと便利な場合は、ふるいのあるPythonではT(47000)しか管理できません。あなたがやっていることと似たようなことを試して、それが速いかどうかを確認します。
カデ

ふるいを使用しないほうが速いように見えます。私はあなたと同様の方法でT(493900)を計算することができました。
カデ

これまでPerlを使用したことはありませんが、私はなんとかあなたの答えを確認できました。リストに追加します!
ニコラスシプリス

公平を期すために、これはCのファクタリングを行うモジュールを使用します(すべてに純粋なPerlを使用するように強制できますが、もちろん高速ではありません)。
DanaJ

回答は言語の任意の組み合わせを使用して計算できるため、問題ありません。
ニコラスシプリス

3

Go、21e9

ふるいを実行して、各数値<= Nの最小係数を見つけます。ゴルーチンを生成して、数値空間のセクションをカウントします。

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

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)when を計算する作業を完了している場合N % 2 == 1、それを知っていT(N + 1) == T(N) + 2ます。これにより、3からカウントを開始し、2ずつ反復して増分できます。
  • Collection型ではなく配列に素数を格納します。これはN私が到達できる倍以上になりました。
  • エラトステネスのふるいを実行するのではなく、素数を使用して数値を因数分解します。これは、メモリストレージがプライムアレイにほぼ完全に制限されることを意味します。
  • 最小の因子を見つけようとしている数の平方根を保存します。毎回素因数を二乗する@ user1354678のアプローチを試しましたが、これは私のスコアから1e7ほどかかりました。

これですべてです。私のコードは、3から2ずつ繰り返され、ヒットまたは制限時間を超えたことを検出し、その時点で答えを吐き出します。

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を搭載した別のシステム(Windows 8.1、Intelコアi7 @ 2.5 GHz、8 GB RAM)で実行すると、コードを変更することなく著しく優れた結果が得られます。

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

mayContinue()in for loop conditionを単純な条件に置き換えることができれば、より高い結果を達成できます。そして、偶数の合計を事前に計算してから2ずつ増やす方法が気に入っています。
コーダー

@ user1354678、推奨してくれてありがとう。奇妙なことに、うまくいきませんでした。別のコンピューターでこのコードのバリエーションを試したところ、投稿されたバージョンが最速のものであることがわかりました。コードからクロックコールを削除し、単純なしきい値を使用すると、1秒強かかりました。〜2e7の減算をなくすためにに切り替えようとstartTimeしましたendTimeが、それは私のスコアから3e7のコストがかかりました!
貞勝

あなたがそれを試しましたSystem.nanoTime() - startTime < TIME_LIMIT、それは少し私のためにあなたのコードを固定だって、。この状況は何百万回もチェックされているという事実を考慮すると、非常に高速ではありません。少し高速です。コードから学んだことの1つは、..のfor中に入れないことforです。forコード内の別のメソッドに移動した後、コードの速度が40%向上します。ありがとう。 ...それは時代のフェッチ百万人だという事実を考慮する際のArrayListよりもはるかに効率的である
コーダ

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))(それが正しい答えを与えていないかもしれませんが)オーバーフローしないdoubleのベクトルを加算している
mawir

1

Python、〜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

ジュリア、5e7

確かにジュリアはもっと良くできますが、これは私が今持っているものです。これは、JuliaBoxで約60秒で5e7を実行しますが、ローカルでまだテストできません。うまくいけば、もっと賢いアプローチを考えたことでしょう。

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)、これは無意味ですまた、2で割り切れるので、すでに説明されています。)

私がそれにいる間、副作用に神に感謝します。remove-ifはリストのサイズを小さくし、削除された要素の数をカウントします。そのため、ループの値に乗算し、それを現在の合計に追加するだけです。

(面白い事実:deleteはの破壊的な同等物ですremoveが、何らかの理由で、この場合deleteよりもあらゆる種類の速度が遅くなりますremove。)


以前Lispを使用したことがないので、コードを実行しようとするとコンパイラエラーが発生します:(defvar total 0)(defvar counter 0)(defvar input 10000)(defvar numbers(loop for i to input collect i))( iのループを2から(floor(sqrt input))(setf counter 0)summing(prog2(nsubstitute-if 0# '(lambda(x)(if(eq(mod xi)0)(progn(incf counter)t )))数字)(* iカウンター)(setf数字(0数字を削除))))最終的に合計(return(+ total(reduce# '+ numbers)))))
NicolásSiplis

私はSBCL 1.0.38を使用していますが、家に帰ったら最新バージョンに更新し、どのように動作するかを確認します。ファイルに保存する場合、「sbcl --script <filename>」を使用して実行できます。
キャンドル

Ideoneを使ってオンラインでコンパイルしようとしても、うまくいきませんでしたが、うまくいきませんでした。
ニコラスシプリス

ああ、申し訳ありませんが、6行目の「do」キーワードを忘れてしまいました。しかし、今度は実行されるはずです。
キャンドル

私のマシンでは60秒で6e6を計算します!ところで、自分のコードを入力することにした場合、回答として送信する必要があるかどうかを知っていますか?それが新しい投稿を許可するかどうかはわかりません。
ニコラスシプリス

0

錆1.5e9

非常に素朴なエラトステインのふるいですが、Rustはここで愛を受けていないと感じました!

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

}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.