सबसे छोटे प्रमुख कारकों का योग


19

एसएफ (एन) एक फ़ंक्शन है जो किसी दिए गए नंबर n के लिए सबसे छोटे प्रमुख कारक की गणना करता है।

हम 2 <= n <= N के साथ हर SF (n) के योग को T (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

विजेता वह होगा जो अपने स्वयं के लैपटॉप (तोशिबा सैटेलाइट L845, इंटेल कोर i5, 8 जीबी रैम) पर 60 सेकंड में सबसे बड़ा टी (एन) की गणना करने का प्रबंधन करता है।


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

Pf (2) = 2, Pf (3) = 3, So, T (3) = 2 + 3 = 5. क्या मैं सही हूं? मैंने मुख्य कारकों को खोजने के लिए प्रोग्राम किया, लेकिन क्या आप मौजूदा आवश्यकता के बारे में विस्तार से बता सकते हैं। धन्यवाद
सांकेतिक शब्दों में बदलनेवाला

1
@ToddLehman मैं अपने स्वयं के लैपटॉप (Sony Vaio SVF14A16CLB) में प्रत्येक कोड चला रहा हूं, इसलिए यदि यह 60 सेकंड से कम समय लेता है तो मैं संख्या बढ़ाता हूं और अधिक समय लगने पर इसे घटाता हूं।
निकोलस सिप्लिस

1
हां, जब तक यह मेरी अपनी मशीन पर चलता है और 60 सेकंड या उससे कम समय में सही उत्तर देता है, यह स्वीकार्य है।
निकोलस सिप्लिस

1
इसके 4 सूत्र हैं।
निकोलस सिप्लिस

1
क्या थर्ड पार्टी लाइब्रेरी की अनुमति है? यदि प्रोग्राम थ्रेड्स बना रहा है तो यह ठीक है?
कोडर

जवाबों:


12

निम, 3.6 ई १३

स्मृति आवश्यकताओं को बहुत अधिक हो जाने के बाद उच्चतम एन की गणना करने की कोशिश करते समय बस sieving सबसे अच्छा जवाब नहीं है। यहां एक अलग दृष्टिकोण है (कुछ दिनों पहले निम के साथ शुरू किया गया था और गति और वाक्यविन्यास के साथ प्यार हो गया था, इसे तेज या अधिक पठनीय बनाने के किसी भी सुझाव का स्वागत है!)।

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 रैपर को अपने कोड में लागू करने की कोशिश की, लेकिन यह काम नहीं कर सका (पहले कभी जीएमपी का इस्तेमाल नहीं किया ताकि निश्चित रूप से मदद नहीं मिली)।
निकोलस सिप्लिस

तुम भी परिभाषा returnमें fकी जरूरत नहीं है । सिंगल-एक्सप्रेशन प्रोक्स स्वचालित रूप से वापस आ जाते हैं।
kirbyfan64sos

3
यह पहला सबसे तेज़-कोड नहीं है जिसे निम ने ध्यान देने योग्य अंतर से जीता है। जांच के लायक हो सकता है।
प्रिमो जूल

मैं यह देखने के लिए उत्सुक हूं कि जीएमपी का उपयोग करते समय यह कैसा प्रदर्शन करता है, लेकिन मेरे प्रयासों के बावजूद इसे सही ढंग से लागू नहीं कर सका।
निकोलस सिप्लिस

निम निश्चित रूप से मेरी सीखने की सूची पर जा रही है!
Sp3000

5

सी, प्रधान छलनी: 5e9

परिणाम:

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

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

कार्यक्रम:

हालांकि यह एक बहुत ही कठिन कार्यक्रम है, लेकिन मुझे यह समझने में थोड़ा समय लगा कि मैमोरी मैनेजमेंट को सही कैसे किया जाए - मेरे पास रेंज में प्रति नंबर 1 बाइट के लिए पर्याप्त रैम है, इसलिए मुझे सावधान रहना होगा। यह एरास्टोन्स की एक मानक चलनी है।

#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 मिनट के निशान पर रख देगा।
इसाॅग

क्या आप के लिए assert.h की जरूरत है?
मैक्स राइड

@MaxRied यह एक कर्ण संस्करण से बचा हुआ था।
ईसैक

3

पर्ल, ब्रूट फोर्स फैक्टरिंग

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

मैं अपने लिनक्स मशीन पर 25 सेकंड में लगभग 9e7 प्राप्त कर सकता हूं। यह सी कोड में खुदाई करके तेज हो सकता है, क्योंकि यह 2/3/5 के लिए एक चेक के बाद कह रहा है, पूरी तरह से संख्या को कारक।

ऐसा करने के लिए बहुत अधिक चतुर तरीके हैं जो कि sieving का उपयोग करते हैं। मैंने सोचा कि एक सरल जानवर बल तरीका एक शुरुआत होगी। यह मूल रूप से प्रोजेक्ट यूलर समस्या 521 है, वैसे।


अगर यह जानने के लिए सभी उपयोगी है, तो एक छलनी के साथ पायथन में मैं केवल टी (47000) का प्रबंधन कर सकता हूं। मैं कुछ ऐसा ही करने की कोशिश कर रहा हूं जो आप देख रहे हैं कि क्या यह तेज है।
केड

ऐसा लगता है कि एक छलनी का उपयोग नहीं करना तेज है .. मैं आपके लिए एक समान विधि के साथ टी (493900) की गणना करने में सक्षम था।
केड

पहले कभी पर्ल का उपयोग नहीं किया गया था, लेकिन मैं आपके उत्तर को सत्यापित करने में कामयाब रहा, मैं आपको सूची में जोड़ दूंगा!
निकोलस सिप्लिस

निष्पक्ष होने के लिए, यह मेरे मॉड्यूल का उपयोग करता है जो सी में फैक्टरिंग करता है (आप इसे हर चीज के लिए शुद्ध पर्ल का उपयोग करने के लिए मजबूर कर सकते हैं, लेकिन निश्चित रूप से यह उतना तेज़ नहीं है)।
दाना जज

उत्तर भाषा के किसी भी संयोजन का उपयोग करके गणना की जा सकती है, इसलिए यह ठीक है।
निकोलस सिप्लिस

3

गो, २१ ई ९

प्रत्येक संख्या के न्यूनतम कारक को खोजने के लिए एक छलनी करता है <= 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

सी ++, 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

जावा 8: 1.8e8 2.4e8

इस प्रविष्टि की तुलना पहले से ही किए गए कई अन्य लोगों से नहीं है, लेकिन मैं अपना जवाब पोस्ट करना चाहता था क्योंकि मुझे इस पर काम करने में मज़ा आया।

मेरे दृष्टिकोण के मुख्य अनुकूलन निम्नानुसार हैं:

  • हर सम संख्या में 2 का सबसे छोटा कारक होता है, इसलिए हर विषम संख्या के संसाधित होने के बाद इन्हें मुफ्त में जोड़ा जा सकता है। मूल रूप से, यदि आपने काम किया है कि गणना T(N)कब N % 2 == 1, आप जानते हैं T(N + 1) == T(N) + 2। यह मुझे तीन पर अपनी गिनती शुरू करने और दो बार पुनरावृत्ति द्वारा वृद्धि करने की अनुमति देता है।
  • मैं एक प्रकार के विपरीत एक सरणी में अपनी प्रमुख संख्याओं को संग्रहीत करता हूं Collection। इससे दोगुना से अधिक Nमैं पहुंच सकता हूं।
  • मैं एराटोस्थनीज की छलनी का विरोध करने के लिए एक संख्या को कारक के लिए अभाज्य संख्याओं का उपयोग करता हूं। इसका मतलब यह है कि मेरी मेमोरी स्टोरेज लगभग पूरी तरह से मेरे प्राइम सरणी में प्रतिबंधित है।
  • मैं उस संख्या के वर्गमूल को संग्रहीत करता हूं जिसके लिए मैं सबसे छोटा कारक खोजने की कोशिश कर रहा हूं। मैंने हर बार प्राइम फैक्टर को स्क्वेर करने के लिए @ user1354678 के दृष्टिकोण की कोशिश की, लेकिन इसने मुझे मेरे स्कोर से लगभग 1e7 की लागत दी।

इसके बारे में बस इतना ही है। मेरा कोड 3 से twos द्वारा पुनरावृत्ति करता है जब तक कि यह पता नहीं लगाता है कि यह हिट हो गई है या समय सीमा पार कर गई है, जिस बिंदु पर यह उत्तर को बाहर निकालता है।

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

जावा 8 के नवीनतम संस्करण के साथ एक अलग प्रणाली (विंडोज 8.1, इंटेल कोर i7 @ 2.5 गीगाहर्ट्ज, 8 जीबी रैम) पर चलने से बिना किसी कोड परिवर्तन के बेहतर परिणाम सामने आए हैं।

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

आप बदल सकते हैं mayContinue()में for loop conditionसिर्फ एक सरल शर्त के साथ, आप उच्च परिणाम प्राप्त कर सकते हैं। और मुझे आपके द्वारा राशि समाप्‍त करने का तरीका भी पसंद है, फिर दो से वृद्धि।
कोडर

@ user1354678, सिफारिश के लिए धन्यवाद। अजीब बात है, यह काम नहीं किया। मैंने एक अलग कंप्यूटर पर इस कोड के बदलावों की कोशिश की और पाया कि पोस्ट किया गया संस्करण सबसे तेज़ है। कोड से घड़ी की कॉल को हटाने और एक साधारण थ्रेशहोल्ड नंबर का उपयोग करने से मुझे एक सेकंड से थोड़ा अधिक खर्च होता है। मैंने भी ~ 2e7 सबट्रेक्शन को खत्म करने के startTimeलिए मुझे स्विच करने की कोशिश की endTime, लेकिन मेरे स्कोर से मुझे 3e7 का खर्च आया!
सादकात्सु

क्या आपने इसके साथ कोशिश की System.nanoTime() - startTime < TIME_LIMIT, coz यह आपके लिए मेरे कोड को थोड़ा तेज करता है। यह बहुत तेज़ी से नहीं है, इस तथ्य को देखते हुए, इस स्थिति को लाखों बार जांचा जाता है, यह थोड़ा तेज़ होगा। एक बात जो मैंने आपके कोड से सीखी है, वह forअंदर मत डालो for.. forमेरे कोड में किसी अन्य विधि पर जाने के बाद , मेरी कोड गति 40% बढ़ जाती है, धन्यवाद .. एक बात जो मुझे अभी भी पता चल रही है, वह है इस तथ्य पर विचार करते समय ArrayList से बहुत अधिक कुशल हैं कि यह लाखों बार लाया गया है ..
कोडर

x2यदि आप लागू करते हैं तो आप परिणाम प्राप्त कर सकते हैं MultiThreading। लेकिन प्रधान गणना को चलाने से पहले इसे पूरी सारणी में शामिल करना होगा।
कोडर

@ user1354678, चेक को mayContinue()विधि से लूप में ले जाने के लिए मुझे मेरे स्कोर से 8e6 खर्च करना होगा। यह स्थानीय अनुकूलन का मुद्दा हो सकता है। जब मैंने इस समाधान को विकसित कर रहा था, तो मुझे स्टोर करने के लिए कई डेटा प्रकारों के साथ प्रयोग किया। मैं केवल 8.8e7 तक पहुंचने में सक्षम था ArrayList, लेकिन मैंने एक सरणी का उपयोग करके 1.8e8 (अब 2.4e8) को मारा। लुकअप के साथ कुछ प्रदर्शन बूस्ट शामिल हो सकते हैं, लेकिन मेमोरी आवंटन के लिए कुछ निश्चित बूस्ट हैं। मैंने एल्गोरिथ्म को मल्टी-थ्रेडिंग के बारे में सोचा है, लेकिन मैं समस्याओं में भाग गया।
सादकात्सु

1

आर, 2.5 ई 7

Eratosthenes की सरल दिमाग की छलनी, जितना संभव हो उतना सदिश। आर वास्तव में इस तरह की समस्या के लिए नहीं बनाया गया है और मुझे पूरा यकीन है कि इसे और तेज बनाया जा सकता है।

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))युगल का एक सदिश योग है जो अतिप्रवाह नहीं करता है (हालाँकि यह सही उत्तर नहीं दे सकता है)
mawir

1

पायथन, ~ 7 ई 8

एराथोस्टेनेस की वृद्धिशील चलनी का उपयोग करना। कुछ देखभाल करने की आवश्यकता है कि एक चिह्नित मूल्य इसके सबसे कम भाजक के साथ चिह्नित है, लेकिन कार्यान्वयन अन्यथा काफी सीधे आगे है।

टाइमिंग को 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

जूलिया, ५ इ 7

निश्चित रूप से जूलिया बेहतर कर सकती है, लेकिन यह मेरे लिए अभी है। यह जूलियाबॉक्स पर लगभग 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

आम लिस्प, 1 ई 7

(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), फिर हर मूल्य का परीक्षण primes के साथ किया है, जबकि पहले मैं हर संख्या के विरुद्ध परीक्षण करूँगा (sqrt input), जो कि व्यर्थ होगा (जैसे, यदि संख्या 4 से विभाज्य है, यह भी 2 से विभाज्य है, इसलिए इसका पहले से ही हिसाब है।)

जब मैं इस पर हूं तो साइड-इफेक्ट्स के लिए भगवान का शुक्र है। निष्कासन-यदि सूची के आकार को कम करता है और गिना जाता है कि कितने तत्व निकाले गए हैं, तो मुझे बस यह गुणा करना होगा कि जो भी मूल्य लूप पर है और उसे कुल में जोड़ दें।

(मजेदार तथ्य: deleteविनाशकारी के बराबर है remove, लेकिन जो भी कारण के लिए, इस मामले में deleteसभी प्रकार की धीमी है remove।)


पहले कभी लिस्प का उपयोग नहीं किया था, मुझे आपके कोड को चलाने की कोशिश करते समय एक कंपाइलर त्रुटि हो रही है: (डिफावर कुल 0) (डिफ्वार काउंटर 0) (डिफावर इनपुट 10000) (डिव्वर नंबर (आई के लिए लूप 2 से इनपुट कलेक्ट i)) ( मैं 2 से (मंजिल (sqrt इनपुट)) (सेटफ काउंटर 0) योग (prog2 (nsubstitute-if 0 # #) (lambda (x) (अगर (eq (mod xi)) 0) (progn (incf काउंटर)) ))) नंबर) (* i काउंटर) (सेटफ नंबर (0 नंबर हटाएं)) कुल मिलाकर (वापसी (+ कुल + # संख्या +
घटाएं

मैं SBCL 1.0.38 का उपयोग कर रहा हूं, लेकिन जब मुझे घर मिलेगा तो मैं नवीनतम संस्करण में अपडेट करूंगा और देखूंगा कि यह कैसे जाता है। यदि आप इसे एक फ़ाइल में सहेजते हैं, तो आप इसे "sbcl --script <फ़ाइल नाम>" के साथ चला सकते हैं।
मोमबत्तियाँ

मैंने कोशिश की, लेकिन अभी भी कोई भाग्य नहीं है, बस अगर मैंने Ideone के साथ ऑनलाइन संकलन करने की कोशिश की, लेकिन यह भी काम नहीं किया।
निकोलस सिप्लिस

ओह, क्षमा करें, मैं लाइन 6 पर "डू" कीवर्ड को भूल गया। इसे अब चलना चाहिए, हालांकि इसे एक और शॉट देना चाहिए।
मोमबत्तियाँ

महान, यह मेरी मशीन पर 60 सेकंड में 6e6 गणना करता है! वैसे, अगर मैं अपना कोड दर्ज करने का फैसला करता हूं, तो क्या आप जानते हैं कि मुझे जवाब के रूप में प्रस्तुत करना चाहिए? मुझे यकीन नहीं है कि अगर यह नई प्रस्तुतियाँ की अनुमति देगा।
निकोलस सिप्लिस

0

जंग 1.5e9

एक बहुत भोली इराटोस्थीन छलनी, लेकिन मुझे लगा कि यहां जंग को कोई प्यार नहीं मिला!

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

जावा 2.14e9

बिटसेट के लाभ के साथ एराटोस्थनीज की शुद्ध छलनी

मैंने 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 Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.