आप जल्दी से कितना गुणा कर सकते हैं?


12

हाल ही में पायथन को कोसने के साथ , यहाँ पायथन की ताकत दिखाने की कोशिश की गई है। आपकी चुनौती एक ऐसे कार्यक्रम को लिखना nहै जो 10 सेकंड के भीतर यथासंभव अधिक संख्या में फैक्टरियल की गणना करता है।

आपका स्कोर होगा (highest n for your program on your machine)/(highest n for my program on your machine)

नियम

  • आपको एक सटीक पूर्णांक समाधान की गणना करनी चाहिए। चूँकि फैक्टरियल 64 बिट अहस्ताक्षरित पूर्णांक में फिट होने की तुलना में बहुत अधिक होगा, यदि आप अपनी भाषा में बड़े पूर्णांक का समर्थन नहीं करते हैं तो आप तार का उपयोग कर सकते हैं।
  • मानक खामियों को मना किया जाता है। विशेष रूप से, आप किसी भी बाह्य संसाधनों का उपयोग नहीं कर सकते।
  • केवल गणना भाग (इसमें स्ट्रिंग्स का उपयोग करके किसी भी वर्कआर्ड के लिए समय शामिल है) कुल समय में जोड़ता है जो औसतन 10 सेकंड से कम होना चाहिए।
  • सिंगल थ्रेडेड प्रोग्राम्स।
  • आपको आउटपुट को आसानी से प्रिंट करने योग्य रूप में संग्रहीत करना चाहिए (जैसे कि मुद्रण में समय लगता है) (नीचे मेरा कार्यक्रम देखें), स्ट्रिंग, चर, वर्ण सरणी, आदि।

संपादित करें:

  • आपके कार्यक्रम को सभी के लिए सही आउटपुट देना होगा n:1 <= n <= (your highest n)

EDIT2:

  • मुझे यह स्पष्ट रूप से कहने से नफरत है, लेकिन आपकी भाषा के अंतर्निहित तथ्यात्मक कार्यों का उपयोग मानक कमियां के अंतर्गत आता है http://meta.codegolf.stackexchange.com/a/1078/8766 क्षमा करें गणितज्ञ और ऋषि

मेरा कार्यक्रम

from __future__ import print_function
import time


def factorial( n ):
    return reduce( ( lambda x , y : x * y ) , xrange( 1 , n + 1 ) , 1 )

start = time.clock()
answer = factorial( 90000 )
end = time.clock()

print ( answer )
print ( "Time:" , end - start , "sec" )

उच्चतम स्कोर जीतता है। रिकॉर्ड के लिए, मेरा कोड एक पेंटियम 4 3.0 गीगाहर्ट्ज पर n = 90000लगभग 9.89सेकंड में प्रबंधन कर सकता है


संपादित करें: हर कोई केवल उच्चतम n के बजाय स्कोर जोड़ सकता है । बस उच्चतम का अपने आप से कोई मतलब नहीं है क्योंकि यह आपके हार्डवेयर पर निर्भर करता है। अन्यथा एक उद्देश्य जीतने वाली कसौटी होना असंभव है। अलियाशा का एवर सही ढंग से करता है।n


हमें विजेता मिल गया। मैंने जावा उत्तर को /codegolf//a/26974/8766 स्वीकार नहीं किया, क्योंकि यह http://meta.codegolf.stackexchange.com/a/1080/8766 के करीब स्कर्ट की तरह है


1
operator.mul
लैंबडा

1
बिट ने इस काम को अंजाम दिया, लेकिन यह मानते हुए कि मैंने नियमों को सही ढंग से पढ़ा है यह MATLAB समाधान अच्छा होगा:, एक सेकंड के एक अंश में factorial(Inf)रिटर्न Inf
डेनिस जहरुद्दीन

1
@ डोरकोनोब जो मानक खामियों में फिट बैठता है।
जस्टिन

1
@ डेनिसजेरुद्दीन, "Inf" को "सटीक पूर्णांक समाधान" के रूप में संदर्भित करने के लिए थोड़ा खिंचाव है।
tobyink

1
@Quincunx नहीं, किसी भी भाषा की अनुमति है।
user80551

जवाबों:


7

GMP के साथ C ++, स्कोर = 55.55 (10,000,000 / 180,000)

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <vector>
#include <iostream>
#include <queue>
#include <gmpxx.h>

int main(int argc, char *argv[]) {
  uint64_t n = atoi(argv[1]);

  // Iterate through 1..n.  Strip off powers of 2.  Multiply
  // remainders together into <= 64 bit chunks.
  uint64_t twos = 0;
  std::vector<uint64_t> terms;
  uint64_t m = 1;
  for(uint64_t i = 1; i <= n; i++) {
    uint64_t j = __builtin_ctzll(i);
    twos += j;
    uint64_t k = i >> j;
    if(__builtin_clzll(m) + __builtin_clzll(k) >= 64) {
      m *= k;
    } else {
      terms.push_back(m);
      m = k;
    }
  }
  if(m != 1) terms.push_back(m);

  // convert to gmp
  // why isn't there a 64-bit constructor?
  std::queue<mpz_class> gmpterms;
  for(int i = 0; i < terms.size(); i++) {
    mpz_class x = (uint32_t)(terms[i] >> 32);
    x <<= 32;
    x += (uint32_t)terms[i];
    gmpterms.push(x);
  }

  // pop two from the bottom, multiply them, push on the end.
  while(gmpterms.size() > 1) {
    mpz_class a = gmpterms.front();
    gmpterms.pop();
    mpz_class b = gmpterms.front();
    gmpterms.pop();
    gmpterms.push(a * b);
  }

  mpz_class r = gmpterms.front();
  r <<= twos;
  //std::cout << r << std::endl;
}

8

पायथन 2.7

42.575 = (6,812,000 / 160,000) लगभग


कोड:

import gmpy2

def fac1(n):
    m=lambda(L):([]if len(L)%2==0 else[L.pop()])+map(lambda(l):l[0]*l[1],zip(L[1::2],L[-2::-2]))
    L=map(gmpy2.mpz,xrange(1,n+1))
    Number = (len(L)-1).bit_length()
    while Number:Number-=1;L=m(L)
    return L[0]

def fac2(n):
    global E; E=0
    def f(i):
        global E; E+=i//2
        return[]if i==1 else f(i//2)+range(3,i,2)+[[1,i][i%2]]
    m=lambda(L):([]if len(L)%2==0 else[L.pop()])+map(lambda(l):l[0]*l[1],zip(L[1::2],L[-2::-2]))
    L=map(gmpy2.mpz,f(n))
    N=(len(L)-1).bit_length()
    while N: N-=1;L=m(L)
    return L[0]<<E

परीक्षा:

import time

start = time.time()
baseline(160000)
print time.time()-start

start = time.time()
fac1(6811000)
print time.time()-start

start = time.time()
fac2(6812000)
print time.time()-start

start = time.time()
gmpy2.fac(26000000)
print time.time()-start

आउटपुट:

10.0069999695
10.0729999542
10.0360000134
9.98699998856

यह काम किस प्रकार करता है:

बड़े गुणा में अधिक समय लगता है, इस प्रकार हम संभव के रूप में कई छोटे गुणा करना चाहते हैं। यह पायथन में विशेष रूप से सच है जहां संख्याओं के लिए कम है कि 2^64हम हार्डवेयर अंकगणित का उपयोग करते हैं, और इसके बाद हम सॉफ्टवेयर का उपयोग करते हैं। तो, में m(L), हम एक सूची के साथ शुरू करते हैं L; यदि यह विषम लंबाई है तो हम इसे फिर से बनाने के लिए एक संख्या को विचार से हटा देते हैं। फिर हम तत्व के 1साथ तत्व को गुणा करते हैं -2, तत्व के 3साथ -4, आदि, ताकि

m([1,2,3,4,5,6,7,8]) = [2*7, 4*5, 6*3, 8*1] = [14, 20, 18, 8]
m([10,12,6]) = [360,112]
m([120,6]) = [40320]

यह दृष्टिकोण सुनिश्चित करता है कि हम यथासंभव लंबे समय तक हार्डवेयर अंकगणित का उपयोग कर रहे हैं, जिसके बाद हम कुशल gmc अंकगणितीय लाइब्रेरी पर स्विच करते हैं।

में fac2, हम एक और अधिक क्लासिक डिवाइड लेते हैं और साथ ही दृष्टिकोण को जीतते हैं, जहां हम प्रत्येक 2 के प्रत्येक मल्टीपल को विभाजित करते हैं और एक तुच्छ प्रदर्शन को बढ़ावा देने के लिए उन्हें अंत में बिटशिफ्ट करते हैं। मैंने इसे यहाँ शामिल किया है क्योंकि यह आमतौर पर लगभग 0.5% से अधिक तेज है fac1

fac1(क्योंकि मैं कर सकता हूं) का गोल्फ संस्करण , 220 बी

import gmpy2
def f(n):
    m=lambda(L):([]if len(L)%2==0 else[L.pop()])+map(lambda(l):l[0]*l[1],zip(L[1::2],L[-2::-2]))
    L=map(gmpy2.mpz,xrange(1,n+1));N=(len(L)-1).bit_length()
    while N:N-=1;L=m(L)
return L[0]

1
यदि GMP बैकएंड में एक बिटशिफ्ट फ़ंक्शन शामिल है तो आप सूची में प्रत्येक संख्या को 2 से विभाजित करके संख्याओं को और भी छोटा रख सकते हैं, जब तक कि यह समान न हो और फिर अंत में एक ही शिफ्ट कर रहा हो।
पीटर टेलर

कहाँ से मिला gmpy2? $ python अजगर 2.7.3 (डिफ़ॉल्ट, 27 फरवरी 2014, 19:58:35) [GCC 4.6.3] linux2 पर "अधिक", "कॉपीराइट", "क्रेडिट" या "लाइसेंस" अधिक जानकारी के लिए टाइप करें। >>> gmpy2 आयात से mpz ट्रेसीबैक (सबसे हालिया कॉल अंतिम): फ़ाइल "<stdin>", पंक्ति 1, में <मॉड्यूल> ImportError: gmpy2 नाम का कोई मॉड्यूल नहीं >>>>
user80551

@ user80551: code.google.com/p/gmpy (शीर्ष Google खोज परिणाम) में कई अलग-अलग प्लेटफार्मों के लिए इंस्टॉलर हैं।
एलेक्जेंडर-ब्रेट

गोल्फ संस्करण के लिए, क्या आप इसके while len(L): ...बजाय नहीं कर सकते while len(L)>1: ...?
user80551

नहीं: उस लूप के अंदर का कार्य कभी भी सूची 1 की लंबाई से नीचे नहीं ले जाएगा और किसी भी तरह हमें पहले तत्व की आवश्यकता होगी!
अलेक्जेंडर-ब्रेट

2

जावा - 125.15 (21,400,000 / 171,000)

साथ ही बेशर्मी से पीटर लुसेंची के गितुब रेपो (धन्यवाद @ अर्ध- बहिष्कृत) से नकल की गई और एमआईटी लाइसेंस के तहत लाइसेंस प्राप्त किया गया, यह अल्बर्ट शॉएगेग एट अल द्वारा प्रस्तावित "प्राइम फेक्टराइजेशन नेस्टेड स्क्वेरिंग" एल्गोरिदम का उपयोग करता है। (Luschny के factorial एल्गोरिदम विवरण पृष्ठ के अनुसार )।

मैंने Java के BigInteger का उपयोग करने के लिए एल्गोरिदम को थोड़ा अनुकूलित किया और n <20 के लिए लुकअप टेबल का उपयोग नहीं किया।

Gcj के साथ संकलित, जो अपने BigInteger कार्यान्वयन के लिए GMP का उपयोग करता है, और लिनक्स 3.12.4 (Gentoo) पर चलता है, कोर i7 4700MQ पर 2.40GHz पर

import java.math.BigInteger;

public class PrimeSieveFactorialSchoenhage {

    private static int[] primeList, multiList;

    public static BigInteger factorial(int n) {
        int log2n = 31 - Integer.numberOfLeadingZeros(n);
        int piN = log2n < 2 ? 1 : 2 + (15 * n) / (8 * (log2n - 1));

        primeList = new int[piN];
        multiList = new int[piN];

        int len = primeFactors(n);
        return nestedSquare(len).shiftLeft(n - Integer.bitCount(n));
    }

    private static BigInteger nestedSquare(int len) {
        if (len == 0) {
            return BigInteger.ONE;
        }

        int i = 0, mult = multiList[0];

        while (mult > 1) {
            if ((mult & 1) == 1) { // is mult odd ?
                primeList[len++] = primeList[i];
            }

            multiList[i++] = mult / 2;
            mult = multiList[i];
        }
        BigInteger ns = nestedSquare(i);
        if (len <= i) {
            return ns.multiply(ns);
        }

        return product(primeList, i, len - i).multiply(ns.multiply(ns));
    }

    private static BigInteger product(int[] a, int start, int length) {
        if (length == 0) {
            return BigInteger.ONE;
        }

        int len = (length + 1) / 2;
        long[] b = new long[len];

        int i, j, k;

        for (k = 0, i = start, j = start + length - 1; i < j; i++, k++, j--) {
            b[k] = a[i] * (long) a[j];
        }

        if (i == j) {
            b[k++] = a[j];
        }

        return recProduct(b, 0, k - 1);
    }

    private static BigInteger recProduct(long[] s, int n, int m) {
        if (n > m) {
            return BigInteger.ONE;
        }
        if (n == m) {
            return BigInteger.valueOf(s[n]);
        }
        int k = (n + m) >> 1;
        return recProduct(s, n, k).multiply(recProduct(s, k + 1, m));
    }

    private static int primeFactors(int n) {
        int[] primes = new int[n < 17 ? 6 : (int) Math.floor(n / (Math.log(n) - 1.5))];
        int numPrimes = makePrimeList(n, primes);

        int maxBound = n / 2, count = 0;

        int start = indexOf(primes, 2, 0, numPrimes - 1);
        int end = indexOf(primes, n, start, numPrimes);

        for (int i = start; i < end; i++) {
            int prime = primes[i];
            int m = prime > maxBound ? 1 : 0;

            if (prime <= maxBound) {
                int q = n;
                while (q >= prime) {
                    m += q /= prime;
                }
            }

            primeList[count] = prime;
            multiList[count++] = m;
        }
        return count;
    }

    private static int indexOf(final int[] data, int value, int low, int high) {
        while (low < high) {
            int mid = (low + high) >>> 1;

            if (data[mid] < value) {
                low = mid + 1;
            } else {
                high = mid;
            }
        }

        if (low >= data.length) {
            return low;
        }

        if (data[low] == value) {
            low++;
        }

        return low;
    }

    private static int makePrimeList(int n, int[] prime) {
        boolean[] composite = new boolean[n / 3];

        sieveOfEratosthenes(composite);

        boolean toggle = false;
        int p = 5, i = 0, j = 2;

        prime[0] = 2;
        prime[1] = 3;

        while (p <= n) {
            if (!composite[i++]) {
                prime[j++] = p;
            }
            // -- never mind, it's ok.
            p += (toggle = !toggle) ? 2 : 4;
        }

        return j; // number of primes
    }

    private static void sieveOfEratosthenes(final boolean[] composite) {
        int d1 = 8;
        int d2 = 8;
        int p1 = 3;
        int p2 = 7;
        int s1 = 7;
        int s2 = 3;
        int n = 0;
        int len = composite.length;
        boolean toggle = false;

        while (s1 < len) { // -- scan sieve
            if (!composite[n++]) { // -- if a prime is found, cancel its multiples
                int inc = p1 + p2;

                for (int k = s1; k < len; k += inc) {
                    composite[k] = true;
                }

                for (int k = s1 + s2; k < len; k += inc) {
                    composite[k] = true;
                }
            }

            if (toggle = !toggle) { // Never mind, it's ok.
                s1 += d2;
                d1 += 16;
                p1 += 2;
                p2 += 2;
                s2 = p2;
            } else {
                s1 += d1;
                d2 += 8;
                p1 += 2;
                p2 += 6;
                s2 = p1;
            }
        }
    }

    public static void main(String[] args) {
        int n = Integer.parseInt(args[0]);
        long nanos = System.nanoTime();
        BigInteger fact = factorial(n);
        nanos = System.nanoTime() - nanos;
        // Commented out because it takes ages to print
        //System.out.println(fact);
        System.out.println(nanos / 1e9);
    }
}

संकलितgcj -O3 --main=PrimeSieveFactorialSchoenhage PrimeSieveFactorialSchoenhage.java -o pf_nest_square_fact
14mRh4X0r

1

पायथन 3, एन = 100000

एक साधारण एल्गोरिथ्म परिवर्तन था जो 10000 तक नमूना कोड को टक्कर देने के लिए आवश्यक था।

import time

def factorial(n):
    result = 1
    while n > 0:
        result *= n
        n = n - 1
    return result

start = time.clock()
answer = factorial(100000)
end = time.clock()

print(answer)
print("Time:", end - start, "sec")

स्पष्ट रूप से सबसे रचनात्मक उत्तर नहीं है, लेकिन वास्तव में केवल एक ही तरीका है एक फैक्ट्री ...।


कृपया स्कोर दें, मेरा संपादन देखें। टक्कर शायद होगा क्योंकि अपने मशीन मेरा से बेहतर है।
user80551

1

पर्ल + सी, एन = लगभग 3 मिलियन

यहाँ मैं गणित :: BigInt :: CPMP पर उपलब्ध GMP लाइब्रेरी का उपयोग कर रहा हूँ , जो पर्ल के मुख्य गणित :: BigInt वस्तुओं के लिए बड़े पैमाने पर गति प्रदान करता है।

use v5.14;
use Time::HiRes 'time';
use Math::BigInt only => 'GMP';

sub factorial { Math::BigInt::->new(@_)->bfac }

my $start  = time;
my $answer = factorial( 3_000_000 );
my $end    = time;

say $answer;
say "Time: ", $end - $start, " sec";

यह ध्यान रखें कि मेरा कंप्यूटर शायद आपकी तुलना में थोड़ा धीमा है। आपके मूल पायथन लिपि का उपयोग करते हुए, मैं केवल factorial(40000)10 सेकंड में गणना कर सकता हूं ; factorial(90000)बहुत लंबा समय लगता है। (मैं एक मिनट के बाद Ctrl + C को हिट करता हूं।) आपके हार्डवेयर पर, Math :: BigInt :: GMP का उपयोग करके, आप 10 सेकंड से कम समय में 5 मिलियन या उससे अधिक के भाज्य की गणना करने में सक्षम हो सकते हैं ।

एक बात जो आप नोटिस कर सकते हैं, वह यह है कि हालांकि फैक्टरियल की गणना अविश्वसनीय रूप से जल्दी से की जाती है, परिणाम को प्रिंट करना बहुत धीमा है, मूल गणना की तुलना में लगभग तीन गुना अधिक समय ले रहा है। ऐसा इसलिए है क्योंकि GMP आंतरिक रूप से दशमलव प्रतिनिधित्व के बजाय एक द्विआधारी का उपयोग करता है, और इसे प्रिंट करने के लिए दशमलव रूपांतरण के लिए द्विआधारी की आवश्यकता होती है।


1
मुझे लगता है कि जीएमपी एक बाहरी संसाधन के रूप में गिना जाता है। (हालांकि यह निश्चित रूप से चीजों को प्रधान गुणन को लागू करने और स्क्रैच से
स्ट्रॉन्ज

3
मुझे लगता है कि "बाहरी संसाधन" संभालने था पूर्व परिकलित आदि एक डेटाबेस में जवाब के सेट, या एक वेब सेवा, से समाधान को देख करने के लिए भेजा
tobyink

स्क्वीमिश: पुस्तकालय आमतौर पर बाहरी संसाधनों के रूप में नहीं गिनते हैं जब तक कि उनके पास एक फ़ंक्शन न हो जो उबाऊ खामियों के नियम के तहत आता है।
एलेक्जेंडर-ब्रेट

1
टोबिंक: क्या आप बता सकते हैं कि आपका कार्यक्रम क्या करता है? ऐसा लगता है कि आप केवल एक अंतर्निहित फ़ंक्शन (bfac?) का उपयोग कर रहे हैं
अलेक्जेंडर-ब्रेट

हाँ। क्योंकि यह का उपयोग करता है यह जवाब है, अमान्य है के भाज्य विधिMath::BigInt
14mRh4X0r

1

पायथन 2.7
5.94 = 1'200'000 / 202'000

def fast_fac(n):
    def prod(start, fin):
            if fin - start <= 50:
                    return reduce(lambda x,y: x*y, xrange(start, fin+1), 1)
            else:
                    mid = (start+fin) / 2
                    return prod(start, mid) * prod(mid+1, fin)
    return prod(1, n)

छोटी संख्या के कई समूहों के गुणा के सापेक्ष आसानी का उपयोग करता है और फिर बड़ी संख्या में शामिल बड़ी संख्या की तुलना में उन्हें गुणा करता है।


1

C #: 0,48 (77,000 / 160,000)

मैं इससे खुश नहीं हूं।

क्या C # धीमा है?

लेकिन यहां मेरी एंट्री वैसे भी है।

static void Main(string[] args)
    {
        Console.WriteLine("Enter N for fatorial:");
        int n = Convert.ToInt32(Console.ReadLine());

        Stopwatch s = Stopwatch.StartNew();


        BigInteger result = 1;
        while (0 <-- n) result *= n;

        s.Stop();

        Console.WriteLine("Output: {0} ", result);

        Console.WriteLine("Completed in {0}", s.Elapsed);

    }

जब n = 77000 लगता है 00:00:09:8708952 गणना करने के लिए है।

मैं कोर स्टूडियो i3-2330M @ 2.2GHz का उपयोग करके विजुअल स्टूडियो के बाहर रिलीज़ मोड में चल रहा हूं।

संपादित करें: चूंकि मैं कुछ भी बुद्धिमान नहीं कर रहा हूं, इसलिए मैं उस परिणाम को स्वीकार करता हूं। शायद .NET फ्रेमवर्क 4.5 कुछ ओवरहेड (या BigInteger है कि तेज नहीं है) जोड़ रहा है।


कृपया स्कोर दें और न कि सिर्फn
user80551

1
आप zero approached byइसे प्रीटियर बनाने के लिए ऑपरेटर का उपयोग कर सकते हैं (जैसे कि n = ... + 1तब शुरू करें while (0 <-- n) result *= n;)
Cthulhu

1
.NET के लिए BigInteger ने शायद बड़ी संख्या में गुणा करने के लिए एल्गोरिदम लागू नहीं किया था, जैसे कि Karatsuba या Toom-3। यदि हां, तो यह एक अच्छा उदाहरण है कि पायथन कैसे तेज है।
kernigh

1

बीसी, स्कोर = 0.19

क्या बिल्ली, यहाँ मेरे दावेदार के लिए "आप धीरे-धीरे कितनी गुणा कर सकते हैं?"

बीसी है "एक मनमाना परिशुद्धता कैलकुलेटर भाषा", लेकिन दुर्भाग्य से नहीं बल्कि धीमी:

n=read()
for(f=i=1;i<=n;i++)f*=i
f
quit

मेरे मध्य 2012 मैकबुक प्रो (2.3 गीगाहर्ट्ज इंटेल कोर i7) के बारे में 10 सेकंड में संदर्भ अजगर उत्तर 122000 की गणना कर सकता है!, लेकिन यह बीसी स्क्रिप्ट केवल 23600 गणना कर सकता है!

इसके विपरीत 10000! अजगर संदर्भ स्क्रिप्ट के साथ 1.5s लेता है, लेकिन ईसा पूर्व स्क्रिप्ट 50s लेता है।

हरे बाबा।


1
ओपनबीएसडी बीसी (1) तेज है। आपका कार्यक्रम स्कोर 0.29 = 28000/98000 है। नहीं है read(), इसलिए मैं भागा time sed 's/read()/28000/' factorial.bc | bc
kernigh

1

बैश: स्कोर = 0.001206 (181/150000)

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

#!/bin/bash


add() { # arbitrary-precision addition
  if (( ${#1} < ${#2} )); then
    local a="$2" b="$1" sum= carry=0
  else
    local a="$1" b="$2" sum= carry=0
  fi

  while (( ${#a} )); do
    local -i d1="${a##${a%?}}" d2="10#0${b##${b%?}}" s=carry+d1+d2
    sum="${s##${s%?}}$sum"
    carry="10#0${s%?}"
    a="${a%?}" b="${b%?}"
  done
  echo "$sum"
}

multiply() { # arbitrary-precision multiplication
  if (( ${#1} < ${#2} )); then
    local a="$2" b="$1" product=0
  else
    local a="$1" b="$2" product=0
  fi

  local zeroes=
  while (( ${#b} )); do
    local m1="$a"
    local m2="${b##${b%?}}"
    local partial=$zeroes 
    local -i carry=0
    while (( ${#m1} )); do 
      local -i d="${m1##${m1%?}}"
      m1="${m1%?}"
      local -i p=d*m2+carry
      partial="${p##${p%?}}$partial"
      carry="10#0${p%?}"
    done
    partial="${carry#0}$partial"
    product="$(add "$product" "$partial")"
    zeroes=0$zeroes
    b="${b%?}"
  done
  echo "$product"
}

# 'timerun' function
trap 'echo $((i -1)) $f; exit'  USR1  
(sleep 9.9; kill -USR1 $$)&

declare -i i 
f=1
for ((i=1; i< 10000 ; i++ ))   # 10000 is verry optimistic
do
    f=$(multiply $f $i)
done 

1
कृपया स्कोर जोड़ें और न केवल उच्चतम n
user80551

@ user80551 यह हो चुका है
इमैनुएल

1

पाइथन 3, पीटर लुशनी द्वारा उन्नत एल्गो: 8.25x (1 280 000/155 000)

पीटर Luschny,
http://www.luschny.de/math/factorial/FastFactorialFunctions.htm , से बेशर्मी से कॉपी किया गया
जो "क्रिएटिव कॉमन्स एट्रिब्यूशन-शेयरएलाइल 3.0" लाइसेंस के तहत यह कोड प्रदान करता है।

यह वास्तव में एक काफी उन्नत एल्गोरिथ्म है, जिसे "स्विंगिंग फैक्टरियल" कहा जाता है और प्रिम्स की सूची का उपयोग करते हुए। मुझे संदेह है कि यह और भी तेज हो सकता है अगर यह अन्य उत्तरों में से कई को पसंद करता है और 32 बिट पूर्णांक के साथ अधिकांश गुणा करता है।

#! /usr/bin/python3
import time
import bisect 

def Primes(n) : 
  primes = [2, 3] 
  lim, tog = n // 3, False 
  composite = [False for i in range(lim)] 

  d1 = 8; d2 = 8; p1 = 3; p2 = 7; s = 7; s2 = 3; m = -1 

  while s < lim :             # --  scan the sieve 
      m += 1                  # --  if a prime is found 
      if not composite[m] :   # --  cancel its multiples 
          inc = p1 + p2 
          for k in range(s,      lim, inc) : composite[k] = True 
          for k in range(s + s2, lim, inc) : composite[k] = True 

          tog = not tog 
          if tog: s += d2; d1 += 16; p1 += 2; p2 += 2; s2 = p2 
          else:   s += d1; d2 +=  8; p1 += 2; p2 += 6; s2 = p1 

  k, p, tog = 0, 5, False 
  while p <= n : 
      if not composite[k] : primes.append(p) 
      k += 1; 
      tog = not tog 
      p += 2 if tog else 4 

  return primes 

def isqrt(x): 
  ''' 
  Writing your own square root function
  ''' 
  if x < 0: raise ValueError('square root not defined for negative numbers') 
  n = int(x) 
  if n == 0: return 0 
  a, b = divmod(n.bit_length(), 2) 
  x = 2**(a + b) 
  while True: 
      y = (x + n // x) // 2 
      if y >= x: return x 
      x = y 

def product(s, n, m): 
  if n > m: return 1 
  if n == m: return s[n] 
  k = (n + m) // 2 
  return product(s, n, k) * product(s, k + 1, m) 

def factorialPS(n): 

  small_swing = [1,1,1,3,3,15,5,35,35,315,63,693,231,3003,429,6435,6435, 
          109395,12155,230945,46189,969969,88179,2028117,676039,16900975, 
          1300075,35102025,5014575,145422675,9694845,300540195,300540195] 

  def swing(m, primes): 
      if m < 33: return small_swing[m] 

      s = bisect.bisect_left(primes, 1 + isqrt(m)) 
      d = bisect.bisect_left(primes, 1 + m // 3) 
      e = bisect.bisect_left(primes, 1 + m // 2) 
      g = bisect.bisect_left(primes, 1 + m) 

      factors = primes[e:g] 
      factors += filter(lambda x: (m // x) & 1 == 1, primes[s:d]) 
      for prime in primes[1:s]:   
          p, q = 1, m 
          while True: 
              q //= prime 
              if q == 0: break 
              if q & 1 == 1: 
                  p *= prime 
          if p > 1: factors.append(p) 

      return product(factors, 0, len(factors) - 1) 

  def odd_factorial(n, primes): 
      if n < 2: return 1 
      return (odd_factorial(n // 2, primes)**2) * swing(n, primes) 

  def eval(n): 
      if n < 0: 
          raise ValueError('factorial not defined for negative numbers') 

      if n == 0: return 1 
      if n < 20: return product(range(2, n + 1), 0, n-2) 

      N, bits = n, n 
      while N != 0: 
          bits -= N & 1 
          N >>= 1 

      primes = Primes(n) 
      return odd_factorial(n, primes) * 2**bits 

  return eval(n)

start = time.time()
answer = factorialPS(1280000) 
print(time.time()-start)

1

जावा - 10.9

n = 885000

Mergesort-y।

import java.math.BigInteger;

public class Factorials {

    public static BigInteger fac;

    public static BigInteger two = BigInteger.valueOf(2);

    static BigInteger mul(BigInteger start, BigInteger end) {
        if(start.equals(end)) {
            return start;
        } else {
            BigInteger mid = start.add(end.subtract(start).divide(Factorials.two));
            return Factorials.mul(start, mid).multiply(Factorials.mul(mid.add(BigInteger.ONE), end));
        }
    }

    public static void main(String[] args) {
        Factorials.fac = BigInteger.valueOf(Integer.parseInt(args[0]));
        long t = System.nanoTime();
        BigInteger result = mul(BigInteger.ONE, fac);
        t = System.nanoTime() - t;
        System.out.print(String.valueOf(((float) t) / 1000000000)); //result.toString()+" @ "+
    }
}

BigIntegers धीमे हैं।

मनमाना-सटीक उच्च गति जावा पूर्णांक पुस्तकालयों के लिए सिफारिशें? : पी


क्या मैं इसे मल्टीथ्रेडेड बनाने के लिए आपका कोड चुरा सकता हूं?
साइमन कुआंग

@SimonKuang आगे बढ़ो। : पी बहु-थ्रेडेड प्रविष्टियों की अनुमति नहीं है यहाँ, यद्यपि। इसके अलावा, आप एक अधिक कुशल BigInteger कार्यान्वयन का उपयोग करना चाह सकते हैं।
cjfaure

मर्जेसॉर्ट-वाई इसे डिवाइड-एंड- कॉनकेर कहा जाता है।
जॉनचेन 902

1

C ++ (x86_64-specific) - 3.0 (390000/130000)

(x86-32 के लिए आसानी से पोर्टेबल, अन्य आर्किटेक्चर के लिए पोर्टिंग से एक महत्वपूर्ण गति हानि होती है)

यहाँ लंबे अंकगणित का अपना सूक्ष्म कार्यान्वयन है।
गणना में स्वयं 10 सेकंड लगते हैं, और जबकि आउटपुट आसानी से प्रिंट करने योग्य रूप में होता है ( operator<<ओवरलोड देखें ), इसे प्रिंट करने में कुछ और समय लगता है।

#include <vector>
#include <iostream>
#include <stdint.h>
#include <ctime>

typedef uint64_t digit;
typedef std::vector<digit> number;

std::ostream &operator<<(std::ostream &s, const number &x)
{
    std::vector<char> o;
    size_t size = x.size() * 21;
    o.resize(size);
    size_t lud = 0;
    for(number::const_reverse_iterator i = x.rbegin(), end = x.rend(); i != end; i++)
    {
        digit carry = 0;
        int j;
        for(j = 0; j <= lud || carry; j++)
        {
            digit r = o[j] * (1LL << 32) + carry;
            o[j] = r % 10;
            carry = r / 10;
        }
        lud = j;
        carry = 0;
        for(j = 0; j <= lud || carry; j++)
        {
            digit r = o[j] * (1LL << 32) + carry;
            o[j] = r % 10;
            carry = r / 10;
        }
        lud = j;
        carry = *i;
        for(j = 0; carry; j++)
        {
            digit r = o[j] + (carry % 10);
            carry /= 10;
            carry += r / 10;
            o[j] = r % 10;
        }
        if(j > lud)
            lud = j;
    }
    for(int j = lud; j--;)
        s.put(o[j] + '0');
    return s;
}

inline uint64_t dmul(uint64_t x, uint64_t y, uint64_t &carry)
{
    asm("mulq %2" : "+a"(x), "=d"(carry) : "r"(y));
    return x;
}
inline digit dadd(digit x, digit y, digit &carry)
{
    asm("movq $0, %1; addq %2, %0; adcq %1, %1" : "+r"(x), "=r"(carry), "+r"(y));
    return x;
}

void multiply(number &x, digit y)
{
    x.resize(x.size() + 2);
    digit carry = 0;
    for(number::iterator i = x.begin(), end = x.end(); i != end; i++)
    {
        digit nc, res = dmul(*i, y, nc);
        *i = dadd(res, carry, carry);
        carry += nc;
    }
    size_t sz = x.size();
    for(number::const_reverse_iterator i = x.rbegin(), end = x.rend(); i != end; i++)
    {
        if(*i)
            break;
        sz--;
    }
    x.resize(sz);
}

int main()
{
    const int r = 390000;
    clock_t start = clock();
    number n;
    digit mult = 1;
    n.push_back(1);
    for(digit a = 2; a <= r; a++)
    {
        digit carry, m = dmul(mult, a, carry);
        if(carry)
        {
            multiply(n, mult);
            mult = a;
        }
        else
            mult = m;
    }
    multiply(n, mult);
    std::cout << "Took: " << (clock() - start)/((double)CLOCKS_PER_SEC) << std::endl;
    std::cout << n << std::endl;
}

अपना स्कोर जांचें। आपको अपने कंप्यूटर पर प्रश्न पायथन 2.7 प्रोग्राम को चलाने की आवश्यकता है। अपने कंप्यूटर के लिए, मैं के साथ अपने कार्यक्रम संकलित g++ -O2 factorial.cc -o factorialऔर यह स्कोर 3.90 = 382,000 / 98000.
kernigh

अजीब, मुझे 3.9 मिली और इस कार्यक्रम के लिए आपको 3.0 मिले। मुझे लगता है कि आपका तेज कंप्यूटर एक दंड है। शायद आपका कार्यक्रम rवृद्धि के रूप में पायथन पर अपना लाभ खो देता है । यदि ऐसा है, और आप r10 सेकंड में उच्चतर कर सकते हैं , तो आपका स्कोर नीचे चला जाता है।
कर्नेल

0

पायथन 3: 280000/168000

अपना कार्यक्रम चलाने का समय: बीच में 9.87585953253 और 10.3046453994। मेरे कार्यक्रम को चलाने का समय: के बारे में 10.35296977897559

import time

def factorial(n):
    f = 1
    while n > 1:
        hn = n >> 1
        f = f * 2**hn * double_factorial(n) #dfl[hn + (n & 1) - 1]
        n = hn
    return f
def double_factorial(n):
    #dfl = [1]
    p = 1
    l = 3
    mh = n
    while l <= n:
        p *= l
        l += 2
        #dfl.append(p)
    return p

start = time.clock()
factorial(280000)
end = time.clock()

print(end - start)

मैंने पढ़ा यह उत्तर cs.SE पर पढ़ा और इसे पायथन में लागू करने का प्रयास करने का निर्णय लिया। हालांकि, मैं गलती से पता चला कि n! = (⌊n / 2⌋)! * 2**(⌊n / 2⌋) * n!!(ध्यान दें: !!है दोहरा भाज्य )। इसलिए मैंने उसे गैर-पुनरावर्ती रूप में परिवर्तित कर दिया।

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

अजीब बात है, मैंने पायथन 3 में भोले सीधे गुणन को लागू किया, और यह आपके कार्यक्रम से बेहतर है: n = 16900010 सेकंड में:

def factorial(n):
    p=1
    for i in range(n):
        p*=i+1
    return p

0

रूबी 2.1

स्कोर = 1.80 = 176_000 / 98_000

EDIT: 1.35 = 132_000 / 98_000 से सुधरा है

मैंने GMP factorial algorithm से आइडिया लिया । यह प्रोग्राम प्राइम नंबर जेनरेट करने के लिए स्टैण्डर्ड लाइब्रेरी का उपयोग करता है। रूबी एक बुरा विकल्प है क्योंकि पाइथन की तुलना में रूबी में गुणन धीमा लगता है।

  1. रूबी 2.1 में मेरा कार्यक्रम: स्कोर = 1.80 = 176_000 / 98_000
  2. पायथन 2.7 में तुच्छ एल्गोरिथ्म: स्कोर = 1 = 98_000 / 98_000
  3. रूबी 2.1 में तुच्छ एल्गोरिथ्म: स्कोर = 0.878 = 86_000 / 98_000

हां, ruby 2.1.0p0 (2013-12-25 revision 44422) [x86_64-openbsd]जीएमपी के खिलाफ लिंक के मेरे बाइनरी । रूबी 2.1 ने बड़े गुणन के लिए GMP का उपयोग करने के लिए एक सुविधा को जोड़ा, लेकिन यह अभी भी पायथन 2.7 की तुलना में धीमा लगता है।

require 'benchmark'
require 'optparse'
require 'prime'

def factorial(n)
  # calculate primes up to n, drop the 2
  @odd_primes = Prime.each(n).drop(1)

  # count prime factors of factorial(n)
  @factors = Hash.new(0)
  factorial_recurse(n)

  shift = @factors.delete(2) || 0
  @factors.inject(1) {|product, (base, exp)|
    product * base**exp
  } << shift
end

def factorial_recurse(n)
  return if n < 2

  # collect prime factors of 2 * 4 * 6 * .. * n
  #  = (2 * 2 * 2 * .. * 2) * (1 * 2 * 3 * .. * exp)
  #  = 2**exp * factorial(exp) where exp = floor(n/2)
  exp = n >> 1
  factorial_recurse(exp)
  @factors[2] += exp

  # collect prime factors 3 * 5 * 7 * ... * n
  for prime in @odd_primes
    break if prime > n
    exp = 0
    # count occurences of prime, prime**2, prime**3, .. n
    prime_power = prime
    until prime_power > n
      # floor(n / prime_power) occurences in 1 * 2 * .. * n,
      # but only ceil(count / 2) occurences in 3 * 5 * .. * n
      @factors[prime] += (n / prime_power + 1) >> 1
      prime_power *= prime
    end
  end
end

# usage: factorial.rb [-ct] [number]
cflag = tflag = false
OptionParser.new {|opts|
  opts.on('-c', 'Check for bugs') { cflag = true }
  opts.on('-t', 'Use trivial algorithm') { tflag = true }
  opts.parse!
}
$*[1] and fail 'too many arguments'
n = Integer($*[0] || 176_000)

if cflag
  factorial(n) == (1..n).reduce(1, :*) or
    fail "bad program: factorial(#{n}) is wrong"
  puts "ok"
  exit
end

# measure processor time to calculate factorial
f = nil
if tflag
  time = Benchmark.measure { f = (1..n).reduce(1, :*) }
else
  time = Benchmark.measure { f = factorial(n) }
end
puts f
puts "Time #{time.total} sec"

0

जूलिया - स्कोर = 15.194

संदर्भ कार्यक्रम के रूप में ठीक उसी दृष्टिकोण का उपयोग ...

f(n)=reduce(*,1:big(n))

तो यह कम का उपयोग करता है, मूल द्विआधारी गुणन ऑपरेशन, और एक सीमा (इस मामले में, बड़े (n) का उपयोग करके गणना को Int64 के बजाय BigInt में करने के लिए बाध्य करने के लिए)। इसी से मुझे मिलता है

julia> @time K=f(2340000);
elapsed time: 9.991324093 seconds (814552840 bytes allocated)

मेरे कंप्यूटर पर, 154000 के इनपुट के साथ चल रहे रेफरेंस प्रोग्राम के साथ, मुझे Time: 10.041181 secआउटपुट मिलता है ( python ./test.pyरनिंग का उपयोग करते हुए , जहाँ test.py उस फाइल का नाम है जिसमें रेफरेंस कोड होता है)


0

tcl, 13757

मेरा जवाब है कि tcl की सीमा की जाँच करें।

पहली पंक्ति केवल एक इनपुट पैरामीटर सेट करने के लिए है:

set n 13757

अन्य स्वयं एल्गोरिथ्म हैं:

set r 2
for {set i 3} {$i <= $n} {incr i} {set r [expr {$r*$i}]}   
puts $r

मैंने अपना कोड http://rextester.com/live/WEL36956 पर परीक्षण किया ; यदि मैं n बड़ा बनाता हूं, मुझे एक SIGKILL मिलता है; n एक स्थानीय tcl दुभाषिया पर बड़ा हो सकता है, जो मेरे पास नहीं है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.