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();
不工作显示无限为什么?
答案 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.com:http://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)
您可以使用WebWorkers和BigInt来计算斐波那契数列的巨大值:
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>