দ্রুততম ফিবোনাচি লিখুন


10

এটি ফিবোনাকির সংখ্যাগুলি সম্পর্কে আরও একটি চ্যালেঞ্জ।

লক্ষ্যটি 20'000'000 তম ফিবোনাচি নাম্বারটি যত দ্রুত সম্ভব গণনা করা ute দশমিক আউটপুট প্রায় 4 মাইবি বড়; এটি দিয়ে শুরু:

28543982899108793710435526490684533031144309848579

আউটপুটটির MD5 যোগফল

fa831ff5dd57a830792d8ded4c24c2cb

আপনাকে এমন একটি প্রোগ্রাম জমা দিতে হবে যা চলাকালীন সংখ্যাটি গণনা করে এবং ফলাফলটি রাখে stdout। আমার নিজের মেশিনে পরিমাপ করা দ্রুততম প্রোগ্রামটি জিতেছে।

এখানে কিছু অতিরিক্ত নিয়ম রয়েছে:

  • আপনাকে x64 লিনাক্সে সোর্স কোড এবং বাইনারি চালিতযোগ্য জমা দিতে হবে
  • উত্স কোডটি 1 এমআইবি এর চেয়ে কম হতে হবে, সমাবেশের ক্ষেত্রে এটি কেবল গ্রহণযোগ্য যদি কেবল বাইনারিটি ছোট হয়।
  • আপনার বাইনারিতে গণনা করার জন্য আপনাকে অবশ্যই কোনও ছদ্মবেশী ফ্যাশনে অন্তর্ভুক্ত করা উচিত নয়। সংখ্যাটি রানটাইমে গণনা করতে হবে।
  • আমার কম্পিউটারে দুটি কোর রয়েছে; আপনাকে সমান্তরালতা ব্যবহারের অনুমতি দেওয়া হয়

আমি ইন্টারনেট থেকে একটি ছোট বাস্তবায়ন গ্রহণ করেছি যা প্রায় ৪.৫ সেকেন্ডে চলে। আপনার কাছে একটি ভাল অ্যালগরিদম আছে ধরে নেওয়া এইটিকে পরাভূত করা খুব কঠিন হওয়া উচিত নয়।


1
বাবু, সেজে এর মতো যে কোনও কিছুতে অনির্দিষ্ট ফ্লোটের যথার্থতা রয়েছে সেই জিনিসটি দ্বিতীয় সেকেন্ডের 1/10 তম কম সময়ে চালাবে। এটি কেবল একটি সহজ অভিব্যক্তিphi = (1+sqrt(5))/2
জেবার্নার্ডো

4
আমরা কি হেক্সে আউটপুট দিতে পারি?
কিথ র্যান্ডাল

2
@ কিথ নোপ এটি অনুমানের অংশ।
FUZxxl

3
যেহেতু এটি আপনার সিপিইউতে পরিমাপ করা হবে , তাই আমরা এটি সম্পর্কে আরও কিছু তথ্য থাকতে পারি, তাই না? ইন্টেল নাকি এএমডি? এল 1 এবং নির্দেশের ক্যাশেগুলির আকার? নির্দেশ সেট এক্সটেনশন?
জেবি

2
আমি যেমন এটি গণনা করছি, আপনার প্রারম্ভিক স্ট্রিং এবং এমডি 5 কেবলমাত্র 2'000'000 তম নয়, 20'000'000 তম সংখ্যার জন্য।
জেবি

উত্তর:


4

সিএম জিএমপি, 3.6 এস

Sশ্বর, তবে জিএমপি কোডকে কুৎসিত করে। কারাৎসুবা-স্টাইলের কৌশল দ্বারা, দ্বিগুণ পদক্ষেপের জন্য আমি 2 গুণকে কমিয়ে ফেলতে সক্ষম হয়েছি। এখন যেহেতু আমি FUZxxl এর সমাধানটি পড়ছি, আমি এই ধারণাটি প্রথম নই। আমি আমার হাতকে আরও দু'টি কৌশল পেয়েছি ... সম্ভবত আমি পরে তাদের চেষ্টা করব।

#include <gmp.h>
#include <stdio.h>

#define DBL mpz_mul_2exp(u,a,1);mpz_mul_2exp(v,b,1);mpz_add(u,u,b);mpz_sub(v,a,v);mpz_mul(b,u,b);mpz_mul(a,v,a);mpz_add(a,b,a);
#define ADD mpz_add(a,a,b);mpz_swap(a,b);

int main(){
    mpz_t a,b,u,v;
    mpz_init(a);mpz_set_ui(a,0);
    mpz_init(b);mpz_set_ui(b,1);
    mpz_init(u);
    mpz_init(v);

    DBL
    DBL
    DBL ADD
    DBL ADD
    DBL
    DBL
    DBL
    DBL ADD
    DBL
    DBL
    DBL ADD
    DBL
    DBL ADD
    DBL ADD
    DBL
    DBL ADD
    DBL
    DBL
    DBL
    DBL
    DBL
    DBL
    DBL
    DBL /*Comment this line out for F(10M)*/

    mpz_out_str(stdout,10,b);
    printf("\n");
}

দিয়ে নির্মিত gcc -O3 m.c -o m -lgmp


হাঃ হাঃ হাঃ. শনাক্তকারী নামকরণ বাদে, এটি হ'ল আমার সমাধান :)
জেবি

@ জেবি: প্রথম! : ডি
বুথবি

এটি রাখুন;) পরবর্তী কৌতুকটি আমার হাতা হ্যাসেল থেকে সি থেকে বেশি উপকৃত হবে
জেবি

প্রথমে আমার হাতা কে জিএইচসি বাগে ফাটিয়ে ফেলা হয়েছে। বিরক্তি প্রকাশ করতে ব্যবহৃত। আমাকে দ্বিতীয়টিতে ফিরে যেতে হবে, যা বাস্তবায়ন করতে দূরবর্তীভাবে মজাদার নয়, তাই সময় এবং অনুপ্রেরণা লাগবে।
জেবি

আমার মেশিনে 3.6 সেকেন্ড
FUZxxl

11

ঋষি

হুম, আপনি ধরে নিচ্ছেন যে দ্রুততম একটি সংকলিত প্রোগ্রাম হতে চলেছে। আপনার জন্য কোন বাইনারি!

print fibonacci(2000000)

আমার মেশিনে এটি 0.10 সিপিইউ সেকেন্ড, 0.15 ওয়াল সেকেন্ড সময় নেয়।

সম্পাদনা: কনসোলে সময় নোটবুকের পরিবর্তে


1
আমার ধারণাটি আপনার সিএএস কত দ্রুত এটি করতে পারে তা জানার ছিল না, বরং আপনি নিজেই কত দ্রুত এটি কোড করতে পারেন তা জানার ছিল না।
FUZxxl

11
রেকর্ডের জন্য, আমি এটি কেবল স্মার্টাস হিসাবে রেখেছি; আপনি বিল্টিন ব্যবহার করবেন না বলেছিলেন না।
বুথবি

5

Haskell,

এটি আমার নিজের চেষ্টা, যদিও আমি নিজেই অ্যালগরিদমটি লিখিনি। আমি বরং এটি haskell.org থেকে অনুলিপি করেছি এবং Data.Vectorএটির বিখ্যাত স্ট্রিম ফিউশন সহ এটি ব্যবহার করার জন্য অভিযোজিত করেছি :

import Data.Vector as V
import Data.Bits

main :: IO ()
main = print $ fib 20000000

fib :: Int -> Integer
fib n = snd . V.foldl' fib' (1,0) . V.dropWhile not $ V.map (testBit n) $ V.enumFromStepN (s-1) (-1) s
    where
        s = bitSize n
        fib' (f,g) p
            | p         = (f*(f+2*g),ss)
            | otherwise = (ss,g*(2*f-g))
            where ss = f*f+g*g

জিএইচসি 7.0.3 এবং নীচের পতাকাগুলির সাথে সংকলিত হওয়ার সময় এটি প্রায় 4.5 সেকেন্ড নেয়

ghc -O3 -fllvm fib.hs

অদ্ভুত ... প্রত্যাশিত নম্বরটি মুদ্রণের জন্য এটির 20000000 থেকে 40000000 এ পরিবর্তন করা দরকার।
জেবি

Gotcha। হওয়া উচিত enumFromStepN (s-1)পরিবর্তেenumFromStepN s
জেবি

@ জেবি এই সমস্ত বিভ্রান্তির জন্য দুঃখিত। যুক্তিসঙ্গতভাবে বড় সংখ্যা পেতে আমি প্রাথমিকভাবে প্রোগ্রামটি বিভিন্ন মান সহ পরীক্ষা করেছিলাম এবং আউটপুটটিকে বিভিন্ন ফাইলে সংরক্ষণ করি। তবে কিছু আমি কীভাবে তাদের বিভ্রান্ত করেছি। পছন্দসই ফলাফলটি মেলে আমি আপডেট করেছি have
FUZxxl

@ বুথবি না, আমি পছন্দসই ফাইবোনাচি নম্বরটি পরিবর্তন করি নি, বরং রেফারেন্স আউটপুটটি ভুল ছিল।
FUZxxl

পার্শ্ব নোট: এটি আমার মেশিনে প্রায় 1.5s, কিন্তু LLVM উভয়ই ডেটা না V
জেবি

4

গাভী

 MoO moO MoO mOo MOO OOM MMM moO moO
 MMM mOo mOo moO MMM mOo MMM moO moO
 MOO MOo mOo MoO moO moo mOo mOo moo

মো! (কিছুক্ষণ সময় নেয় some কিছু দুধ পান করুন ...)


1
দ্রষ্টব্য: যদিও এটি সত্যিই কাজ করে, এটি সম্ভবত 20,000,000 এ পৌঁছাতে পারে না ...
টিমটেক

2

গণিত, ব্যাখ্যা করা:

First@Timing[Fibonacci[2 10^6]]

সময়যুক্ত:

0.032 secs on my poor man's laptop.

এবং অবশ্যই, কোনও বাইনারি নেই।


প্রিন্ট করে না stdout
বুথবি

@ বুথবি ভুল আপনি যদি কমান্ড লাইন ইন্টারফেস ব্যবহার করেন তবে এটি স্ট্যান্ডার্ড আউটপুটকে লিখবে। উদাহরণস্বরূপ দেখুন stackoverflow.com/questions/6542537/...
ডঃ belisarius

নাহ, আমি কমান্ডলাইন ইন্টারফেস, সংস্করণ 6.0 ব্যবহার করছি। এমনকি ব্যবহার করেও -batchoutput, এটি কেবল সময়ের তথ্য মুদ্রণ করে না ফিবোনাকির নম্বর ci
বুথবি

দুঃখিত, আমার কাছে গণিত নেই বলে পুনরুত্পাদন করা যাবে না।
FUZxxl

5
curl 'http://www.wolframalpha.com/input/?i=Fibonacci%5B2+10^6%5D' | grep 'Decimal approximation:' | sed ... এটি আপনার ইন্টারনেট সংযোগের গতির প্রতি শ্রদ্ধাজনক সময়ে চলে। ;-)
সুলতানিক

2

আমার ল্যাপটপে ওকামল, 0.856 এস

জারিথ গ্রন্থাগার প্রয়োজন। আমি বিগ_ইন্ট ব্যবহার করেছি তবে জরিথের তুলনায় এটি কুকুর ধীর। একই কোড সহ এটি 10 ​​মিনিট সময় নিয়েছে! বেশিরভাগ সময় ব্যয় সংখ্যাটি প্রিন্ট করতে ব্যয় হয়েছিল (9½ মিনিট বা তার বেশি)!

module M = Map.Make
  (struct
    type t = int
    let compare = compare
   end)

let double b = Z.shift_left b 1
let ( +. ) b1 b2 = Z.add b1 b2
let ( *. ) b1 b2 = Z.mul b1 b2

let cache = ref M.empty 
let rec fib_log n =
  if n = 0
  then Z.zero
  else if n = 1
  then Z.one
  else if n mod 2 = 0
  then
    let f_n_half = fib_log_cached (n/2)
    and f_n_half_minus_one = fib_log_cached (n/2-1)
    in f_n_half *. (f_n_half +. double f_n_half_minus_one)
  else
    let f_n_half = fib_log_cached (n/2)
    and f_n_half_plus_one = fib_log_cached (n/2+1)
    in (f_n_half *. f_n_half) +.
    (f_n_half_plus_one *. f_n_half_plus_one)
and fib_log_cached n =
    try M.find n !cache
    with Not_found ->
      let res = fib_log n
      in cache := M.add n res !cache;
      res

let () =
  let res = fib_log 20_000_000 in
  Z.print res; print_newline ()

আমি বিশ্বাস করতে পারি না লাইব্রেরি কতটা তফাৎ করেছে!


1
তুলনার জন্য @ বুথবাইয়ের সমাধানটি আমার ল্যাপটপে চালাতে 0.875s সময় নেয়। পার্থক্যটি অবহেলা বলে মনে হচ্ছে। এছাড়াও, স্পষ্টতই আমার ল্যাপটপটি দ্রুত : o
রেইচার্সস

1

Haskell,

আমার সিস্টেমে এটি FUZxxl এর উত্তরের (~ 17 সেকেন্ডের পরিবর্তে 18 ডলার ) প্রায় দ্রুত গতিতে চলেছে

main = print $ fst $ fib2 20000000

-- | fib2: Compute (fib n, fib (n+1)).
--
-- Having two adjacent Fibonacci numbers lets us
-- traverse up or down the series efficiently.
fib2 :: Int -> (Integer, Integer)

-- Guard against negative n.
fib2 n | n < 0 = error "fib2: negative index"

-- Start with a few base cases.
fib2 0 = (0, 1)
fib2 1 = (1, 1)
fib2 2 = (1, 2)
fib2 3 = (2, 3)

-- For larger numbers, derive fib2 n from fib2 (n `div` 2)
-- This takes advantage of the following identity:
--
--    fib(n) = fib(k)*fib(n-k-1) + fib(k+1)*fib(n-k)
--             where n > k
--               and k ≥ 0.
--
fib2 n =
    let (a, b) = fib2 (n `div` 2)
     in if even n
        then ((b-a)*a + a*b, a*a + b*b)
        else (a*a + b*b, a*b + b*(a+b))

খুশী হলাম। আমি হাস্কেলকে ভালবাসি
অ্যারেন

আমি এটিকে দৌড় দিয়েছি। আমি বেশ মুগ্ধ ছিলাম। এই ধরণের গাণিতিক কোড সমস্যার জন্য হাস্কেল দুর্দান্ত।
আন্ডারেন

1

সি, নিষ্পাপ অ্যালগরিদম

কৌতূহলী ছিল, এবং আমি এর আগে জিএমপি ব্যবহার করিনি ... সুতরাং:

#include <stdio.h>
#include <stdlib.h>
#include <gmp.h>

int main(int argc, char *argv[]){
    int n = (argc>1)?atoi(argv[1]):0;

    mpz_t temp,prev,result;
    mpz_init(temp);
    mpz_init_set_ui(prev, 0);
    mpz_init_set_ui(result, 1);

    for(int i = 2; i <= n; i++) {
        mpz_add(temp, result, prev);
        mpz_swap(temp, result);
        mpz_swap(temp, prev);
    }

    printf("fib(%d) = %s\n", n, mpz_get_str (NULL, 10, result));

    return 0;
}

ফাইব (1 মিলিয়ন) প্রায় 7 সেকেন্ড লাগে ... সুতরাং এই অ্যালগরিদম রেসটি জিতবে না।


1

আমি এসবিসিএলে ম্যাট্রিক্স গুণিতকরণ পদ্ধতিটি (এসআইএসপি, http://sicp.org.ua/sicp/Exercise1-19 ) প্রয়োগ করেছি তবে এটি শেষ হতে 30 সেকেন্ড সময় নেয়। আমি GMP ব্যবহার করে এটি সিতে পোর্ট করেছিলাম এবং এটি আমার মেশিনে প্রায় 1.36 সেকেন্ডের মধ্যে সঠিক ফলাফল দেয়। এটি বুথবাইয়ের উত্তরের মতোই দ্রুত।

#include <gmp.h>
#include <stdio.h>

int main()
{
  int n = 20000000;

  mpz_t a, b, p, q, psq, qsq, twopq, bq, aq, ap, bp;
  int count = n;

  mpz_init_set_si(a, 1);
  mpz_init_set_si(b, 0);
  mpz_init_set_si(p, 0);
  mpz_init_set_si(q, 1);
  mpz_init(psq);
  mpz_init(qsq);
  mpz_init(twopq);
  mpz_init(bq);
  mpz_init(aq);
  mpz_init(ap);
  mpz_init(bp);

  while(count > 0)
    {
      if ((count % 2) == 0)
        {
          mpz_mul(psq, p, p);
          mpz_mul(qsq, q, q);
          mpz_mul(twopq, p, q);
          mpz_mul_si(twopq, twopq, 2);

          mpz_add(p, psq, qsq);    // p -> (p * p) + (q * q)
          mpz_add(q, twopq, qsq);  // q -> (2 * p * q) + (q * q) 
          count/=2;
        }

      else
       {
          mpz_mul(bq, b, q);
          mpz_mul(aq, a, q);
          mpz_mul(ap, a, p);
          mpz_mul(bp, b, p);

          mpz_add(a, bq, aq);      // a -> (b * q) + (a * q)
          mpz_add(a, a, ap);       //              + (a * p)

          mpz_add(b, bp, aq);      // b -> (b * p) + (a * q)

          count--;
       }

    }

  gmp_printf("%Zd\n", b);
  return 0;
}

1

জাভা: গণনা করতে 8 সেকেন্ড, লেখার জন্য 18 সেকেন্ড

public static BigInteger fibonacci1(int n) {
    if (n < 0) explode("non-negative please");
    short charPos = 32;
    boolean[] buf = new boolean[32];
    do {
        buf[--charPos] = (n & 1) == 1;
        n >>>= 1;
    } while (n != 0);
    BigInteger a = BigInteger.ZERO;
    BigInteger b = BigInteger.ONE;
    BigInteger temp;
    do {
        if (buf[charPos++]) {
            temp = b.multiply(b).add(a.multiply(a));
            b = b.multiply(a.shiftLeft(1).add(b));
            a = temp;
        } else {
            temp = b.multiply(b).add(a.multiply(a));
            a = a.multiply(b.shiftLeft(1).subtract(a));
            b = temp;
        }
    } while (charPos < 32);
    return a;
}

public static void main(String[] args) {
    BigInteger f;
    f = fibonacci1(20000000);
    // about 8 seconds
    System.out.println(f.toString());
    // about 18 seconds
}

0

যাওয়া

এটা বিব্রতকরভাবে ধীর। আমার কম্পিউটারে এটি 3 মিনিটেরও কম সময় নেয়। এটি কেবলমাত্র 120 পুনরাবৃত্ত কলগুলি, যদিও (ক্যাশে যুক্ত করার পরে)। নোট করুন যে এটি প্রচুর স্মৃতি ব্যবহার করতে পারে (১.৪ জিআইবি এর মতো)!

package main

import (
    "math/big"
    "fmt"
)

var cache = make(map[int64] *big.Int)

func fib_log_cache(n int64) *big.Int {
    if res, ok := cache[n]; ok {
        return res
    }
    res := fib_log(n)
    cache[n] = res
    return res
}

func fib_log(n int64) *big.Int {
    if n <= 1 {
        return big.NewInt(n)
    }

    if n % 2 == 0 {
        f_n_half := fib_log_cache(n/2)
        f_n_half_minus_one := fib_log_cache(n/2-1)
        res := new(big.Int).Lsh(f_n_half_minus_one, 1)
        res.Add(f_n_half, res)
        res.Mul(f_n_half, res)
        return res
    }
    f_n_half := fib_log_cache(n/2)
    f_n_half_plus_one := fib_log_cache(n/2+1)
    res := new(big.Int).Mul(f_n_half_plus_one, f_n_half_plus_one)
    tmp := new(big.Int).Mul(f_n_half, f_n_half)
    res.Add(res, tmp)
    return res
}

func main() {
    fmt.Println(fib_log(20000000))
}

আমি গো রুটিনগুলি ব্যবহার করে (ক্যাশে যুক্ত করার আগে) সমান্তরাল করার চেষ্টা করেছি এবং এটি 19 গিগাবাইট মেমরির ব্যবহার শুরু করেছে: /
রেচার্লস

-4

সিউডো কোড (আপনি জানেন না আপনি কী ব্যবহার করছেন)

product = 1
multiplier = 3 // 3 is fibonacci sequence, but this can be any number, 
      // generating an infinite amount of sequences
y = 28 // the 2^x-1 term, so 2^28-1=1,284,455,535th term
for (int i = 1; int < y; i++) {
  product= sum*multiplier-1
  multiplier= multiplier^2-2
}
multiplier=multiplier-product // 2^28+1 1,284,455,537th 

আমার কম্পিউটারটি এই দুটি শর্তটি করতে 56 ঘন্টা সময় নিয়েছে। আমার কম্পিউটারটি একধরণের কৃপণ। আমি 22 শে অক্টোবর একটি পাঠ্য ফাইলে নম্বর পাব। 1.2 সংযোগগুলি আমার সংযোগটি ভাগ করে নেওয়া কিছুটা বড়।


1
আমি আপনার উত্তর দ্বারা বিভ্রান্ত সুডোকোড? এবং এখনও আপনার সময় আছে? কোড পোস্ট করুন! ভাষা কোন ব্যাপার না!
বুথবাই

এটি, এবং আউটপুটটি কেবল 4 মিলিয়ন বা
তত
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.