Is there a slicker way of doing this? - javascript

I seem to handle special cases like this somewhat frequently. There's got to be a more concise syntax or construct:
var x = solveForX(); /* some slow calculation here */
if (x < 0)
{
x = 0;
}
This is equivalent, but doesn't feel any more elegant:
var x;
x = (x = solveForX()) < 0 ? 0 : x;
Maybe there's a bit shift trick?
Update: I ran some benchmarks to compare my two favorite answers - the one I accepted, and Peter Ajtai's. Turns out Peter's is quite a bit faster! Running 1,000,000 iterations of each (I also ran a version that caches Math.max to see how much time the lookup contributed) shows that Peter's runs in under half the time of the Math.max version, even with max caching.
That said, even the "slowest" method is still quite fast.

How about
var x = Math.max(solveForX(), 0);

Something like:
x = Math.max(0, solveForX());

(x < 0) && (x = 0);
Edit: Removed the if statement. Thanks Andreas.
This is one line, and it's clear what it does (in my personal opinion) - if you're familiar with boolean short circuit evaluation.
The above makes use of boolean short circuit evaluation. This can be very useful in certain situations (especially pointer arithmetic in C++, but boolean short circuit evaluation also works in Javascript).
x = 0 only evaluates if x < 0.
Here are two examples:
This alerts 1:
<script type="text/javascript">
var x = 1;
(x < 0) && (x = 0);
alert(x);
</script>
This alerts 0:
<script type="text/javascript">
var x = -1;
(x < 0) && (x = 0);
alert(x);
</script>

I'd decorate the original solveForX function.
function returnNonNegative(fn) {
function _f() {
var x = fn();
if (x < 0) {
x = 0;
}
return x;
}
return _f;
}
solveForX = returnNonNegative(solveForX);
In this particular case, using Math.max seems to be fine, but this pattern provides a generic solution for this type of problems.

The accepted answer is perfect. If you want to accomplish the same without a function call, I believe that this is most concise:
var x;
(x = solveForX()) > 0 || (x = 0);
(In Safari, this implementation is a whole 7% faster than Math.max(), which is probably not worth caring about)

I think that this way is pretty nice!
var x = Math.max(solveForX(), 0);
Good luck!

Related

Javascript comparison operators, is === more efficient than ==?

I recently was told the triple equal operator is more efficient because it will not try and convert any of the variables before comparing. Never thought about performance implications.
Does anyone have information on the performance of various comparison operators or other common JS operators that may slow a framework down?
Are there complex object types where this is a factor?
I realize this may be relevant to edge cases only, but without concrete data, it's hard to tell.
Should be, since it performs less operations. == performs type conversions before comparing if both arguments have different types. Pseudocode below.
function doubleEquals(a, b) {
[a, b] = coerceTypes(a, b)
return compareSameType(a, b)
}
function tripleEquals(a, b) {
if (!areSameType(a, b)) {
return false
}
return compareSameType(a, b)
}
If you compare == and === with two inputs of the same type though, the difference should be very small to none since no conversion would be required.
This is not really an answer to my question, but only one edge example:
For 100K or more comparisons between a string and a float (ex: 0.035 == "0.035") it seems there is certainly a noticeable performance difference of around 1000%, or 10x. As tested on Chrome v77.
If there is a framework doing a lot of comparisons behind the scenes, I could see how this could effect how "crisp" it feels. But it could also be completely irrelevant. I don't have any data for framework use.
See the code below for a an example.
print('string vs float comparison operator performance')
let start = Date.now();
let loopCount = 10000000;
let appxLoopCostRatio = 2857;
for (let i=0; i < loopCount; i++) {
let x = Math.random();
let y = Math.random().toString();
if (x == y) count++;
}
let mid = Date.now();
for (let i=0; i < loopCount; i++) {
let x = Math.random();
let y = Math.random().toString();
if (x === y) count++;
}
let mid2 = Date.now();
//no comparison
for (let i=0; i < loopCount; i++) {
let x = Math.random();
let y = Math.random().toString();
}
let finish = Date.now();
let a, b, cost;
a = mid-start;
b = mid2-mid;
cost = finish-mid2;
print('runtime == comparison:', mid-start);
print('runtime === comparison:', mid2-mid);
print('appx cost of variable generation:', finish-mid2);
let expectedCost = (loopCount / appxLoopCostRatio);
let TcCost = (b-cost < (expectedCost * 0.05)) ? (expectedCost * 0.05) : b-cost;
print(` === is more efficient by ${Math.floor((a-cost)/TcCost) * 100 }%`)

How to write js code with minimal number of jumps required to reach target with less time complexity

I wrote like below. But how to make it more efficient. Need suggestions!!
For example, given:
X = 10
Y = 85
D = 30
Y is the target, D is the jumpcount , X is the current position .
function solution(X, Y, D) {
for(var i =1; X<=Y; i++){
X = X+D;
if( X >= Y ){
return i;
}
}
}
The above code works fine, but how to write efficiently?
Thanks in advance!
You don't need to simulate jumping, You can just use maths:
(X >= Y) ? 1 : Math.ceil((Y-X)/D)
EDIT: Updated for x >= y according to Patrick Robert's suggestion.
Based on the question (minimal number of jumps required), as I understand, when x==y should be 0 steps, then:
Math.ceil(Math.abs((Y-X)/D))
works when Y<0 and/or X<0

Index of a really big Fibonacci Number

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];
}

Need help making an approximation of Euler's constant

It's very close but just one number off. If you can change anything here to make it better it'd be appreciated. I'm comparing my number with Math.E to see if I'm close.
var e = (function() {
var factorial = function(n) {
var a = 1;
for (var i = 1; i <= n; i++) {
a = a * i;
}
return a;
};
for (var k = 0, b = []; k < 18; k++) {
b.push(b.length ? b[k - 1] + 1 / factorial(k) : 1 / factorial(k));
}
return b[b.length - 1];
})();
document.write(e);document.write('<br />'+ Math.E);​
My number: 2.7182818284590455
Math.E: 2.718281828459045
Work from higher numbers to lower numbers to minimize cancellation:
var e = 1;
for(var k = 17; k > 0; --k) {
e = 1 + e/k;
}
return e;
Evaluating the Taylor polynomial by Horner's rule even avoids the factorial and allows you to use more terms (won't make a difference beyond 17, though).
As far as I can see your number is the same as Math.E and even has a better precision.
2.7182818284590455
2.718281828459045
What is the problem after all?
With javascript, you cannot calculate e this way due to the level of precision of javascript computations. See http://www.javascripter.net/faq/accuracy.htm for more info.
To demonstrate this problem please take a look at the following fiddle which calculates e with n starting at 50000000, incrementing n by 1 every 10 milliseconds:
http://jsfiddle.net/q8xRs/1/
I like using integer values to approximate real ones.
Possible approximations of e in order of increasing accuracy are:
11/4
87/32
23225/8544
3442297523731/1266350489376
That last one is fairly accurate, equating to:
2.7182818284590452213260834432
which doesn't diverge from wikipedia's value till the 18th:
2.71828182845904523536028747135266249775724709369995
So there's that, if you're interested.

Positive Number to Negative Number in JavaScript?

Basically, the reverse of abs. If I have:
if ($this.find('.pdxslide-activeSlide').index() < slideNum - 1) {
slideNum = -slideNum
}
console.log(slideNum)
No matter what console always returns a positive number. How do I fix this?
If I do:
if ($this.find('.pdxslide-activeSlide').index() < slideNum - 1) {
_selector.animate({
left: (-slideNum * sizes.images.width) + 'px'
}, 750, 'InOutPDX')
} else {
_selector.animate({
left: (slideNum * sizes.images.width) + 'px'
}, 750, 'InOutPDX')
}
it works tho, but it's not "DRY" and just stupid to have an entire block of code JUST for a -.
Math.abs(num) => Always positive
-Math.abs(num) => Always negative
You do realize however, that for your code
if($this.find('.pdxslide-activeSlide').index() < slideNum-1){ slideNum = -slideNum }
console.log(slideNum)
If the index found is 3 and slideNum is 3,
then 3 < 3-1 => false
so slideNum remains positive??
It looks more like a logic error to me.
The reverse of abs is Math.abs(num) * -1.
The basic formula to reverse positive to negative or negative to positive:
i - (i * 2)
Javascript has a dedicated operator for this: unary negation.
TL;DR: It's the minus sign!
To negate a number, simply prefix it with - in the most intuitive possible way. No need to write a function, use Math.abs() multiply by -1 or use the bitwise operator.
Unary negation works on number literals:
let a = 10; // a is `10`
let b = -10; // b is `-10`
It works with variables too:
let x = 50;
x = -x; // x is now `-50`
let y = -6;
y = -y; // y is now `6`
You can even use it multiple times if you use the grouping operator (a.k.a. parentheses:
l = 10; // l is `10`
m = -10; // m is `-10`
n = -(10); // n is `-10`
o = -(-(10)); // o is `10`
p = -(-10); // p is `10` (double negative makes a positive)
All of the above works with a variable as well.
To get a negative version of a number in JavaScript you can always use the ~ bitwise operator.
For example, if you have a = 1000 and you need to convert it to a negative, you could do the following:
a = ~a + 1;
Which would result in a being -1000.
var x = 100;
var negX = ( -x ); // => -100
num * -1
This would do it for you.
Are you sure that control is going into the body of the if? As in does the condition in the if ever hold true? Because if it doesn't, the body of the if will never get executed and slideNum will remain positive. I'm going to hazard a guess that this is probably what you're seeing.
If I try the following in Firebug, it seems to work:
>>> i = 5; console.log(i); i = -i; console.log(i);
5
-5
slideNum *= -1 should also work. As should Math.abs(slideNum) * -1.
If you don't feel like using Math.Abs * -1 you can you this simple if statement :P
if (x > 0) {
x = -x;
}
Of course you could make this a function like this
function makeNegative(number) {
if (number > 0) {
number = -number;
}
}
makeNegative(-3) => -3
makeNegative(5) => -5
Hope this helps! Math.abs will likely work for you but if it doesn't this little
var i = 10;
i = i / -1;
Result: -10
var i = -10;
i = i / -1;
Result: 10
If you divide by negative 1, it will always flip your number either way.
Use 0 - x
x being the number you want to invert
It will convert negative array to positive or vice versa
function negateOrPositive(arr) {
arr.map(res => -res)
};
In vanilla javascript
if(number > 0)
return -1*number;
Where number above is the positive number you intend to convert
This code will convert just positive numbers to negative numbers simple by multiplying by -1

Categories