Javascript斐波那契

时间:2011-11-30 19:09:45

标签: javascript fibonacci

function fibo() {
var first,second,add;
for(var i=0;i<4000;i++){
    if(i === 0){
        first = 1;
        second = 2;
    }
    add = first + second;
    first = second;
    second = add;

}

alert(add);

}

fibo();

不工作显示无限为什么?

7 个答案:

答案 0 :(得分:17)

简单:因为它太大了。

第300个术语是222232244629420445529739893461909967206666939096499764990979600,所以你可以想象第4000个有多大。您无法在JavaScript变量中保留此值。

如果你真的想要计算它,可以使用任意精度库,如果你想快速计算它,可能还有JavaScript以外的东西。

检查GNU Multiple Precision Arithmetic Library - GMP。很高兴与C一起使用,它甚至有special Fibonacci functions


这是一个小C程序来完成这项工作:

#include <gmp.h>

int main()
{
    mpz_t num;
    mpz_init(num);

    mpz_fib_ui(num, 4000);
    gmp_printf("%Zd\n", num);

    return 0;
}

编译:

cc fib.c -lgmp

并运行: - )

time ./a.out
39909473435004422792081248094960912600792570982820257852628876326523051818641373433549136769424132442293969306537520118273879628025443235370362250955435654171592897966790864814458223141914272590897468472180370639695334449662650312874735560926298246249404168309064214351044459077749425236777660809226095151852052781352975449482565838369809183771787439660825140502824343131911711296392457138867486593923544177893735428602238212249156564631452507658603400012003685322984838488962351492632577755354452904049241294565662519417235020049873873878602731379207893212335423484873469083054556329894167262818692599815209582517277965059068235543139459375028276851221435815957374273143824422909416395375178739268544368126894240979135322176080374780998010657710775625856041594078495411724236560242597759185543824798332467919613598667003025993715274875

real    0m0.005s
user    0m0.001s
sys     0m0.002s

答案 1 :(得分:3)

虽然已被接受,但我认为我可以提供更简单的解决方案。只需将数字存储在数组中,每个元素一个数字,并像在小学一样执行添加 - “在列中”。它是这样的:

function add(a, b) {
    while (a.length < b.length) a.unshift(0);
    while (a.length > b.length) b.unshift(0);
    var carry = 0, sum = []
    for (var i = a.length - 1; i >= 0; i--) {
        var s = a[i] + b[i] + carry;
        if (s >= 10) {
            s = s - 10;
            carry = 1;
        } else {
            carry = 0;
        }
        sum.unshift(s);
    }
    if (carry)
        sum.unshift(carry);
    return sum;
}

斐波纳契函数是这样的:

function fib(n) {
    var f1 = [0];
    var f2 = [1];

    while (n--) {
        var f3 = add(f1, f2)
        f1 = f2;
        f2 = f3;
    }
    return f1.join("");
}

似乎完全无效,但只需要几分之一秒才能在2.3GHz macbook上获得fib(4000)

答案 2 :(得分:2)

因为Number.MAX_VALUE + Number.MAX_VALUE === Infinity

问题是sum超过了JavaScripts存储数值的功能。

答案 3 :(得分:2)

斐波那契(4000)[836位]

39909473435004422792081248094960912600792570982820257852628876326523051818641373433549136769424132442293969306537520118273879628025443235370362250955435654171592897966790864814458223141914272590897468472180370639695334449662650312874735560926298246249404168309064214351044459077749425236777660809226095151852052781352975449482565838369809183771787439660825140502824343131911711296392457138867486593923544177893735428602238212249156564631452507658603400012003685322984838488962351492632577755354452904049241294565662519417235020049873873878602731379207893212335423484873469083054556329894167262818692599815209582517277965059068235543139459375028276851221435815957374273143824422909416395375178739268544368126894240979135322176080374780998010657710775625856041594078495411724236560242597759185543824798332467919613598667003025993715274875

<!doctype html>
<html lang= "en">
<head>
<meta charset= "utf-8">
<title> Javascript Big Integers</title>

<style>
body{margin: 0 1em;width: auto;font-size: 125%}
p{max-width: 800px;margin: 1ex 1em;}
div{margin: 1em;}
input, textarea, label{
    font-size: 1em;line-height: 1.2;font-family: arial, sans-serif;
    font-weight: 600;padding: 0 2px;
}
textarea{
    background-color: white;    color: black;   width: 90%; 
    border: 2px ridge silver;position: absolute;z-index: 5;overflow-y: scroll;height: 500px;
}
#fibInp{text-align: right;}
#calcfibBtn, #stopFibBtn{color:navy;cursor:pointer}
#calcfibBtn:focus, #stopFibBtn:focus, #calcfibBtn:hover, #stopFibBtn:hover{color:red}

</style>

<script>
//utilities
//ie version (if any) determines initial loop size
/*@cc_on
    @if(@_jscript_version> 5.5){
    navigator.IEmod= document.documentMode? document.documentMode: 
    window.XMLHttpRequest? 7: 6;
    }
    @end
@*/

function mr(hoo){
    if(hoo){
        if(typeof hoo== 'string') return document.getElementById(hoo);
        if(hoo.nodeType=== 1) return hoo;
    }
    return null;
}
if(!Array.prototype.map){
    Array.prototype.map= function(fun, scope){
        var L= this.length, A= Array(this.length), i= 0, val;
        if(typeof fun== 'function'){
            while(i< L){
                if(i in this){
                    A[i]= fun.call(scope, this[i], i, this);
                }
                ++i;
            }
            return A;
        }
    }
}
//Big Integer Object
function BigInt(n, sign){
    if(this.constructor!= BigInt){
        if(n.constructor== BigInt) return n;
        n= n.toString();
        if(/^\d+$/.test(n)){
            var digits= n.split('').map(Number);
            return new BigInt(digits.reverse(), sign);
        }
        else{
            throw Error('base 10 integer input only');
        }
    }
    while(n.length && !n[n.length - 1]){
        --n.length;
    }
    this.digits= n;
    this.length= n.length;
    if(sign== -1) this.sign= sign;
}
BigInt.prototype.toString= function(){
    var s= this.digits.slice().reverse().join('');
    if(this.sign== -1) s= '-'+s;
    return s;
}
BigInt.prototype.plus= function(n){
    n= BigInt(n);
    var n1= this.digits, n2= n.digits,
    len1= n1.length, len2= n2.length,
    hoo= Array(Math.max(len1, len2)+ 1),
    size= Math.min(len1, len2), temp= 0, dig;
    for(var i= 0; i < size; i++){
        dig= n1[i]+ n2[i]+ temp;
        hoo[i]= dig%10;
        temp= (dig/10)|0;
    }
    if(len2> len1){
        n1= n2;
        len1= len2;
    }
    for(var i= size; temp && i < len1; i++){
        dig= n1[i]+ temp;
        hoo[i]= dig%10;
        temp= (dig/10)|0;
    }
    if(temp) hoo[i]= temp;
    while(i < len1){
        hoo[i]= n1[i];
        ++i;
    }
    return new BigInt(hoo);
}
// Math.fibonacci methods
Math.fibonacci= function(n){
    var n1= 0, n2= 1, t= 1, fib= [], i= 0;
    var limit= 9007199254740992;
    while(n1< limit){
        fib[i++]= n1;
        if(i== n) return fib;
        n2= t;
        t= n1+n2;
        n1= n2;
    }
    if(n){
        t= fib.pop(), n1= fib.pop(), i= fib.length;
        while(i<n){
            fib[i++]= n1;
            n2= BigInt(t);
            t= n2.plus(n1);
            n1= n2.toString();
        }
    }
    return fib;
}
Math.nthFibonacci= function(n, ret){
    var fibs= [0, 1], i= 78;
    while(n && --i){
        fibs[2]= fibs[0]+ fibs[1];
        fibs.shift();
        n--;
    }
    if(n){
        fibs= [BigInt(fibs[0]), BigInt(fibs[1])];
        while(n--){
            fibs[2]= fibs[0].plus(fibs[1]);
            fibs.shift();
        }
    }
    return ret? fibs: fibs[0];
}
// demonstration code
Fib={
    clear: function(){
        mr('yw_fib_tex').value= '';
        Fib.wait= false;
        mr('fibInp').value= '';
    },
    counter: 1,
    demo: function(){
        mr('calcfibBtn').onclick= Fib.getFib;
        mr('stopFibBtn').onclick= Fib.quitFib;
        mr('fibInp').onkeypress= Fib.keycheck;
        mr('fibInp').focus();
    },
    discomma: !!window.opera,
    getFib: function(){
        mr('yw_fib_tex').value= '';
        var d, c, n= mr('fibInp').value;
        n= parseInt(mr('fibInp').value);
        if(!n || n<2){
            mr('fibInp').value= '';
            mr('fibInp').focus();
            return true;
        }
        if(n<= 1100){
            d= Math.nthFibonacci(n).toString();
            var fibs= ['', n, d.length, d];
            Fib.report(fibs);
            return true;
        }
        if(n> 10000){
            d= Fib;
            c= d.counter;
            if(c> 2000){
                Fib.reach(d.low, d.high, n, c, Fib.report);
                return true;
            }
        }
        d= Math.nthFibonacci(1000, 1);
        Fib.reach(d[0], d[1], n, 1000, Fib.report);
        return true;
    },
    high: 1,
    keycheck: function(e){
        e= e || window.event;
        var k= e.charCode || e.keyCode;
        if(k== 13) Fib.getFib();
        return true;
    },
    low: 0,
    quitFib: function(){
        Fib.wait= true;
        mr('yw_fib_tex').focus();
    },
    reach: function(n1, n2, n, i, cb){
        var d, q, who, mf= Fib, F= Fib.reach;
        if(F.time=== undefined){
            F.top= n;
            F.count= i+1;
            F.time= new Date().getTime();
            F.cb= cb;
            F.tik= false;
        }
        q= n2.toString().length;
        who= mr('yw_fib_tex');
        if(who){
            if(q<2100) who.value= n2;
            else who.value= q+ ' digits...thinking...';
        }
        if(q> 20000) q= q> 100000? 10: 20;
        else if(q> 5000) q= q> 10000? 50: 100;
        else q= q> 1000? 200: 1000;
        if(navigator.IEmod) q/= 4;
        q= Math.min(q, F.top-F.count);
        while(q> 0){
            d= BigInt(n1).plus(n2);
            F.count++;
            n1= n2;
            n2= d;
            --q;
        }
        if(F.count>= F.top || Fib.wait){
            var t= (new Date()-F.time)/1000;
            d= d.toString();
            var fibs= [t, F.count, d.length, d, n1];
            F.time= undefined;
            if(typeof F.cb== 'function') return F.cb(fibs);
        }
        else{
            setTimeout(function(){
                F(n1, d)
            },
            0);
        }
    },
    report: function(fb){
        var mf= Fib, s, fibz, f1= fb[1], t= fb[0] || '', fN= fb[3];
        if(t){
            t+= mf.time;
            if(mf.wait) Fib.time+= t;
            else Fib.time= 0;
            t= t.toFixed(3)+' seconds to calculate ';
        }
        fibz= t+'fibonacci('+f1+') ['+fb[2]+' digits]';
        if(fb[4] && fN> mf.counter){
            mf.counter= f1;
            mf.low= fb[4];
            mf.high= fN;
        }
        fN= fN.toString();
        if(window.opera){
            fN= fN.replace(/(\d{10})/g, '$1 ');
        }
        fibz= fibz+'\n\n'+fN;
        mr('yw_fib_tex').value= fibz;
        Fib.wait= false;
        mr('yw_fib_tex').focus();
        return true;
    },
    time: 0,
    wait: false
}
window.onload= function(){
    Fib.demo();
}
</script>
</head>

<body>
<h2 id= "yw_fib_head"> Fibonacci numbers in javascript</h2>
<p>
This is a demonstration of Big Integer Math in Javascript, handling numbers of arbitrary precision.
The time it takes to calculate a large Fibonacci number depends on your computer and browser.</p>
<div>
<label> fibonacci#<input size= "5" id= "fibInp" type= "text" value= "1000"> </label>
<input type= "button" id= "calcfibBtn" value= "Calculate">
<input type= "button" id= "stopFibBtn" value= "Stop">
<br>
<textarea readonly= "readonly" id= "yw_fib_tex">
</textarea>
</div>
</body>
</html>

答案 4 :(得分:1)

为了获得更好的效果,您可以使用jsperf.comhttp://jsperf.com/fib-vs-fib-loga/

只需轻微改变函数即可通过javascript计算最大位置。

是的,每个浏览器和使用的arch bean的结果都不同。

function fibo() {
    var first,second,add;
    for(var i=0;i<4000;i++){
        if(i === 0){
            first = 1;
            second = 2;
        }
        if(first+second > Number.MAX_VALUE){
            console.debug(i, first, second);
            return;
        }
        add = first + second;
        first = second;
        second = add;
    }
    alert(add);
}
fibo();

结果是:1473 8.077637632156222e+307 1.3069892237633987e+308 其中1473是可以用javascript计算的最大斐波那契位置。

答案 5 :(得分:0)

PubNub的Ariya Hidayat昨晚教给我们这个:

function fibo(n) {
    return Array.apply(0, Array(n)). reduce(function(x, y, z){ return x.concat((z < 2) ? z : x[z-1] + x[z-2]); }, []);
     }

答案 6 :(得分:0)

您可以使用WebWorkersBigInt来计算斐波那契数列的巨大值:

var input = document.querySelector('input');
var output = document.querySelector('#output');
var fulloutput = document.querySelector('#fulloutput');
var time = document.querySelector('#time');
var start, end;
var worker;

var createWorker = function () {
  if (worker) worker.terminate();
  var workerContent = "self.onmessage = " + workerFunction.toString();
  var blob = new Blob([workerContent], {type: 'application/javascript'}); 
  worker = new Worker(URL.createObjectURL(blob));
  worker.onmessage = receive;
};

var workerFunction = function(event) {
  var total = BigInt(event.data);
  var fib = function(index) {
    var temp;
    var last = BigInt(0);
    var sum = BigInt(1);
    for (; index >= BigInt(2); index--) {
      if (index % BigInt(1000) === BigInt(0)) 
        self.postMessage({
          total: total,
          calculating: index
        });
      temp = last;
      last = sum;
      sum += temp;
    }
    return sum;
  };
  if (total > BigInt(0)) self.postMessage({done: fib(total)});
  else self.postMessage({error: 'Input error'});
};

window.addEventListener('load', function () {
  if (!window.Worker || 
      !window.Blob   || 
      !window.URL    || 
      !window.BigInt) {
    output.textContent = 'Browser not supported'; 
  } else {
    start = performance.now();
    createWorker();
    output.textContent = 'Worker created, starting calculations';
    worker.postMessage(input.value);
    input.addEventListener('change', function () {
      createWorker();
      start = performance.now();
      output.textContent = 'Calculating';
      worker.postMessage(input.value);
    });
  }
});

var receive = function(event) {
  if (event.data.error) {
    output.textContent =  event.data.error;
  }
  if (event.data.calculating) {
    var total = BigInt(event.data.total);
    var index = BigInt(event.data.calculating);
    var progress = (BigInt(100) * (total - index) / total);
    output.textContent = 'Calculating ' + progress + '%';
  } 
  if (event.data.done) {
    var formatter = new Intl.NumberFormat('en', {
      notation: 'scientific'
    });
    output.textContent = formatter.format(event.data.done);
    fulloutput.textContent = event.data.done;
    end = performance.now();
    time.textContent = 'It took ' + ((end - start) / 1000) + ' seconds';
  }
};
body {
  display: grid;
  place-content: center;
  min-height: 100vh;
}
p, pre  {
  text-align: center;
  width: 80vw;
  white-space:normal;
  word-wrap: break-word;
}
<p>N: <input type="number" value="4000"></p>
<pre id="output"></pre>
<pre id="fulloutput"></pre>
<pre id="time"></pre>