I need to calculate the index of a Fibonacci number with JavaScript, within the Fibonacci sequence. I need to do this without using recursion, or a loop. I found the following formula in the Math forum:
n=⌊logφ(F⋅5√+12)⌋
and coded it in JavaScript:
function fibIndex(fib)
{
fib = BigNumber(fib);
return logBasePhi(fib.times(Math.sqrt(5)).plus((1/2)));
}
function phi()
{
return (1 + Math.sqrt(5))/ 2;
}
function getBaseLog(x, y) {
return Math.log(y) / Math.log(x);
}
function logBasePhi(x)
{
return getBaseLog(phi(), x);
}
Notice the .times() and .plus() functions that are part of this BigNumber Library that has been extremely useful up to this point. This works fine, until the Fibonacci number I want to find the index for is really big.
The problem:
I need a different way to calculate the logarithm with such a big number. If I have a really big number, such as Fibonacci of 2000, I get Infinity for obvious reasons. The library itself does not have any methods to calculate the log, and I can't write this function either.
I would have never imagined that the logarithm of any number with such a small base (phi) can be bigger than the max for JavaScript integers. Can you guys point me in the right direction? Should I just leave it at obtaining the index for numbers less than Fib(1500) and call it good?
You can use BigInteger. You can see an example of how to use it here: http://reallifejs.com/the-meat/calculators/big-number-calculator/
For anyone else looking for this function, here it is using this BigInteger library:
function fibIndex(fib)
{
fib = BigInteger(fib);
var x = fib.multiply(Math.sqrt(5)).add((1/2));
return Math.round(x.log() / Math.log(phi()));
}
function phi()
{
return (1 + Math.sqrt(5))/ 2;
}
I still use the same equation explained in my question above, and it returns the index of Fibonacci's of any size.
fibIndex("35522938794321715091272953991088875073660950670711879743399900326436254083421380378927750257524675311447286915610820861302904371152466182968261111009824391725637150862745505342130220586979511719255023895335108709522075314248260664483166479670588221585277069887873168196490963561219694518077864879100421788205515385380434545975662001723555342440392621808579760295648531141638822913590607533540054087452041707826153271185259107394199852367649618298517093117009455894918353503525076230125819543123779319167440820789626564459764725339684808290073756385496248142195843240135064507885354877296572024804408624272941753639812538039913142028651903030529871116793317789757893606550341466951324756526825899737667945813833853722262630433262780974915425005732866591818868174705546087022106127052877310847951571707582794820376128579789767721485109492542287764348615868723395725124814856415577763540656765591673162724146048330852788081439178288706881889502843933839383437965572895385440792960391702268984769357859686271266574632871727046024303184663919395401465801528726015901456333025573481247959101652204602988035141532490361245742139050819433077833707742246312835208439293469725777437940254819086871672146128972238328251414589544434435170261367824782155103657578194196270111748570034449297964612564456266891635499257186520205662004190179581465184858273590634696557067719668344569716772604494379268256417559005989196664062339943367426392267549671696091620704483335705235401024668972377058959013548701899237423163317609813480075906438821567501678027453981255872940165896765562906948275888682233026018398591561683968279253311810352982216449990605138841279476258998291555393112171672512247299540528273985304628059093340049555047981741901553118436996372565143437092164040501385121979087826864836002852441013290435451405818936965791830088594057993174801701555239838033825491101182302604693483923297155552732646664230339899386949247469662146601783799159535265663192798622519600080199294778264021930327804674406845390858689361183645138036024622999759181149374409868339056190354930762438018253181839721998646473911299168577029520666199783681191268719288387969624745653240780708319950931159323616116725759084631179863296728766212415593748082930558151101350076376704295363472805637813559350925898715117938481138744212886965977892516525139040863376874438253015614485120277306681922196720541898193702570355885540352668267759850827312025869672621201575016416207760471674541668295376322809412095582968275396449970226064500618788480102243996614437085271546164050332641040829307354667753670012241015315160013952802535500838629086649248253271677865717482331893600871123634025348607623548331397239596180750809096946397974233223417735790158178612741331748855629088340732705900553246041710742016160018303725512211509204034880759596775427996675371964469431717567054234107252511625358715489171574578479304777517899774723598872665991091538945488811618222438651723224465992160327444696552759313881273021480919406887970238509074105071808066821703115066838126027585207922256205186141921352880657758551963602504587265334948468963725795943612659061581738118921217900480358979991209140061985794462152498458564473369295078153567296201818251720281822962062936831573631653751528074225190111823253702351177610664803940345503699699208037095784870495785646943997234474258262569998608041243140247674073513323374199936066218946098722092264140092669753657824017634461763981521997119226219136508584203375683292957948563073632975937642581947768042371117470198355444599517718979158713784804470849343173517943800269775988799065209263727016757620989100649249277790139290067789688270481157537247255077854388424596882337360026236416764073030845206282134294301701605369452555608749844089881840152464688185413471165531348083450071936767808847178828505212544681448346850412422392584457798023562617507156540143036586660455094150665003248778589943633804236061867787254092465761897721097498706848304838082130151573830146281598905862080528755999259386441406295844212093958532689277331339576745477613093048842162872506248493879631984787279577095875465635013803960469019743694441996546910736934590725390122252181310568062868015617422771375425422209106466232597689466636780861666245204430735375550444974466951762888881642801337840709202391876433786768647147807880162471534334272202034098411011768290957484345424507121327462388443014612800575348423810123382495642833743034606424879522789397956839996920113680951463518836156462019057063161795046895734075593501902084338246542048532779483281408634769806186279989881229648075555962086774926497206070780542404761166097604241890965888018873735027199940548827053350115337885438800728312460914286268127990478092896975620706029422142841447344514680046143167682001640750053397540223424322177217456434741847020047763710403144096996427837529811812126999093061373016438435440619803496909856986800826405322182728111872725881192065183612822832173197471616932926246556344247662468294551754101114527143077792003917544284111176961413199426663155326179333146951914261328112918116870606040456416800180399145364936151721824514256765308265696290759951243242140057433018143404698921069198350343599629915865217541917472815612277351716569260985624821969133328022587501");
will return 25,001, which is the index of the above fib.
Instead use this formula:
(Fn) = (Fn-1) + (Fn-2)
n is a subindex, for understanding I say...
So let's code :D
function fibonacci(n) {
var f = new Array();
f[0] = 1;
f[1] = 1;
if(n == 1 && n == 2) {
return 1;
}
for(var i = 2; i < n; i++) {
f[i] = f[i - 1] + f[i - 2];
}
return f[n - 1];
}
Related
I ran into the challenge where I need a function that returns a random number within a given range from 0 - X. Not only that, but I require the number returned to be unique; not duplicating numbers that have already been returned on previous calls to the function.
Optionally, when this is done (e.g. the range has been 'exhausted'), just return a random number within the range.
How would one go about doing this?
This should do it:
function makeRandomRange(x) {
var used = new Array(x),
exhausted = false;
return function getRandom() {
var random = Math.floor(Math.random() * x);
if (exhausted) {
return random;
} else {
for (var i=0; i<x; i++) {
random = (random + 1) % x;
if (random in used)
continue;
used[random] = true;
return random;
}
// no free place found
exhausted = true;
used = null; // free memory
return random;
}
};
}
Usage:
var generate = makeRandomRange(20);
var x1 = generate(),
x2 = generate(),
...
Although it works, it has no good performance when the x-th random is generated - it searches the whole list for a free place. This algorithm, a step-by-step Fisher–Yates shuffle, from the question Unique (non-repeating) random numbers in O(1)?, will perform better:
function makeRandomRange(x) {
var range = new Array(x),
pointer = x;
return function getRandom() {
pointer = (pointer-1+x) % x;
var random = Math.floor(Math.random() * pointer);
var num = (random in range) ? range[random] : random;
range[random] = (pointer in range) ? range[pointer] : pointer;
return range[pointer] = num;
};
}
(Demo at jsfiddle.net)
Extended version which does only generate one "group" of unique numbers:
function makeRandomRange(x) {
var range = new Array(x),
pointer = x;
return function getRandom() {
if (range) {
pointer--;
var random = Math.floor(Math.random() * pointer);
var num = (random in range) ? range[random] : random;
range[random] = (pointer in range) ? range[pointer] : pointer;
range[pointer] = num;
if (pointer <= 0) { // first x numbers had been unique
range = null; // free memory;
}
return num;
} else {
return Math.floor(Math.random() * x);
}
};
}
(Demo)
You got some great programming answer. Here's one with a more theoretical flavor to complete your panorama :-)
Your problem is called "sampling" or "subset sampling" and there are several ways you could do this. Let N be the range you are sampling frame (i.e., N=X+1) and M be the size of your sample (the number of elements you want to pick).
if N is much larger than M, you'll want to use an algorithm such as the one suggested by Bentley and Floyd in his column "Programming Pearls: a sample of brilliance" (temporarily available without ACM's lock screen here), I really recommend this as they explicitly give code and discuss in terms of hash tables, etc.; there a few neat tricks in there
if N is within the same range as M, then you might want to use the Fisher-Yates shuffle but stop after only M steps (instead of N)
if you don't really know then the algorithm on page 647 of Devroye's book on random generation is pretty fast.
I wrote this function. It keeps its own array with a history of generated numbers, preventing initial duplicates, continuing to output a random number if all numbers in the range have been outputted once:
// Generates a unique number from a range
// keeps track of generated numbers in a history array
// if all numbers in the range have been returned once, keep outputting random numbers within the range
var UniqueRandom = { NumHistory: new Array(), generate: function(maxNum) {
var current = Math.round(Math.random()*(maxNum-1));
if (maxNum > 1 && this.NumHistory.length > 0) {
if (this.NumHistory.length != maxNum) {
while($.inArray(current, this.NumHistory) != -1) { current = Math.round(Math.random()*(maxNum-1)); }
this.NumHistory.push(current);
return current;
} else {
//unique numbers done, continue outputting random numbers, or we could reset the history array (NumHistory = [];)
return current;
}
} else {
//first time only
this.NumHistory.push(current);
return current;
}
}
};
Here's a working Fiddle
I hope this is of use to someone!
Edit: as pointed out by Pointy below, it might get slow with a large range (here is a
fiddle, going over a range from 0-1000, which seems to run fine). However; I didn't require a very large range, so perhaps this function is indeed not suited if you look to generate and keep track of an enormous range.
You may try generating the number using the current date and time value which would make it unique. To make it within the range, you may have to use some mathematical function.
goal: take a number like 54321, add the numbers together (5+4+3+2+1 = 15), then take that number (15) add the digits (1+5 = 6), so return 6;
here is my code:
function digital_root(n) {
if (n >=10) {
var digits = n.toString().split('').map(function(item, index) {return parseInt(item)}).reduce(function(a,b){ return a+b});
console.log(digits);
}
}
digital_root(1632)
Can't figure out: How to get that function to repeat over and over until digits is just one number (i.e. less than 10). I have tried a variety of nested functions, but can't seem to get it right.
If possible please point me in the direction to the solution ("try a nesting in a while... or read up on..."), but don't give me the complete code solution ("Use this code chunk:...."). I've developed a bad habit of just reading and copying...
Thank you!
Try this: reference HERE
function digital_root(n) {
var singlesum = 0;
while (n >= 10 ) {
singlesum=0;
while (n > 0) {
var rem;
rem = n % 10;
singlesum = singlesum + rem;
n = parseInt(n / 10);
}
n = singlesum;
}
console.log(singlesum);
}
digital_root(1632)
You can use recursion to solve this.
Write a function makeSingleDigit, which argument will be your number.
You need a base condition with the base step, which in your case stops the recursion when received number is one-digit and returns the number.
If condition is not true, you just need to get another digit from the number by n%10 and sum it with the makeSingleDigit(Math.floor(n/10)). By this, you repeatedly sum digits of new numbers, until function receives one-digit number.
Mathematical solution just for your information: the number, which you want to find is n % 9 === 0 ? 9 : n % 9, thus it is the remainder of the division by 9 if it is not 0, otherwise it is 9.
Here is a very optimal solution to the problem:
function digital_root(n) {
return (n - 1) % 9 + 1;
}
const result = digital_root(1632);
console.log(result);
Well, not a very good solution but you can give a hit.
function digital_root(n) {
if (n >=10) {
var digits = n.toString().split('').map(function(item, index) {return parseInt(item)}).reduce(function(a,b){ return a+b});
console.log(digits);
return(digits);
}
}
var num = 1632;
do{
num = digital_root(num);
}while(num>10);
Experienced codefighters, i have just started using Codefight website to learn Javascript. I have solved their task but system does not accept it. The task is to sum all integers (inidividual digit) in a number. For example sumDigit(111) = 3. What is wrong with my code? Please help me.
Code
function digitSum(n) {
var emptyArray = [];
var total = 0;
var number = n.toString();
var res = number.split("");
for (var i=0; i<res.length; i++) {
var numberInd = Number(res[i]);
emptyArray.push(numberInd);
}
var finalSum = emptyArray.reduce(add,total);
function add(a,b) {
return a + b;
}
console.log(finalSum);
//console.log(emptyArray);
//console.log(res);
}
Here's a faster trick for summing the individual digits of a number using only arithmetic:
var digitSum = function(n) {
var sum = 0;
while (n > 0) {
sum += n % 10;
n = Math.floor(n / 10);
}
return sum;
};
n % 10 is the remainder when you divide n by 10. Effectively, this retrieves the ones-digit of a number. Math.floor(n / 10) is the integer division of n by 10. You can think of it as chopping off the ones-digit of a number. That means that this code adds the ones digit to sum, chops off the ones digit (moving the tens digit down to where the ones-digit was) and repeats this process until the number is equal to zero (i.e. there are no digits left).
The reason why this is more efficient than your method is that it doesn't require converting the integer to a string, which is a potentially costly operation. Since CodeFights is mainly a test of algorithmic ability, they are most likely looking for the more algorithmic answer, which is the one I explained above.
I'm trying to solve a Coderbyte challenge, and I'm still trying to fully understand recursion.
Here's the problem: Using the JavaScript language, have the function AdditivePersistence(num) take the num parameter being passed which will always be a positive integer and return its additive persistence which is the number of times you must add the digits in num until you reach a single digit. For example: if num is 2718 then your program should return 2 because 2 + 7 + 1 + 8 = 18 and 1 + 8 = 9 and you stop at 9.
Here's the solution I put into jsfiddle.net to try out:
function AdditivePersistence(num) {
var count=0;
var sum=0;
var x = num.toString().split('');
for(var i=0; i<x.length; i++) {
sum += parseInt(x[i]);
}
if(sum.length == 1) {
return sum;
}
else {
return AdditivePersistence(sum);
}
}
alert(AdditivePersistence(19));
It tells me that there's too much recursion. Is there another "else" I could put that would basically just re-run the function until the sum was one digit?
One of the problems is that your if statement will never evaluate as 'true'. The reason being is that the sum variable is holding a number, and numbers don't have a length function. Also, as 'Barmar' pointed out, you haven't incremented the count variable, and neither are you returning the count variable.
Here's a solution that works using recursion.
function AdditivePersistence(num) {
var result = recursive(String(num).split('').reduce(function(x,y){return parseInt(x) + parseInt(y)}), 1);
function recursive(n, count){
c = count;
if(n < 10)return c;
else{
count += 1
return recursive(String(n).split('').reduce(function(x,y){return parseInt(x) + parseInt(y)}), count)
}
}
return num < 10 ? 0 : result
}
To fix the 'too much recursion problem',
if(sum.toString().length == 1)
However, as the others have said, your implementation does not return the Additive Persistence. Use James Farrell's answer to solve the Coderbyte challenge.
I'm doing the 3rd project euler question right now. So far I've figured out how to solve the problem which is finding the largest prime factor of 600851475143.
I've wrote a small bit of code that can place all the prime factors of a number into an array. The problem I'm having is the number may be too large to compute. I've used other large numbers (not as large as this one) and they've worked fine but this one just freezes up the page like it's in an endless loop. Here's the code:
var primes = [];
function factor (largestNumber) {
var a = largestNumber;
var b = 2;
while (b < largestNumber) {
if (a % b == 0) {
a /= b;
primes.push(b);
b = 2;
} else {
b++;
}
}
}
factor(600851475143);
console.log(primes);
Your algorithm is not optimal.
function factor(largestNumber) {
var primes = []; // using local value
var a = largestNumber;
var b = 2;
while (b <= Math.floor(Math.sqrt(a))) { // we do not need to check whole number
// over and over again.
// We could check to a only
// or even to sqrt(a) only
if (a % b == 0) {
a /= b;
primes.push(b);
// there is no reason to reset value
} else {
b++;
}
}
primes.push(a); // rest number would be always prime
return primes;
}
console.log(factor(600851475143));
This may be a useful way, split the largest primary factor into 3 part.
Cut the largest Num into 2 close num eg 40 => 5 * 8
Get the bigger num(8) and find out all the prime num small than it. Storage into Array.
Use a loop to get the largest prime factor.
That's all, I will try it tonight. If I make it I will add the jsfiddle addr. : )