Javascript calculation bug - javascript

is there a better way to multiply and divide figures than using the * and / ?
There is a strange behavior in Chrome Firefox and Internet Explorer using those operaters:
x1 = 9999.8
x1 * 100 = 999979.9999999999
x1 * 100 / 100 = 9999.8
x1 / 100 = 99.99799999999999
http://jsbin.com/ekoye3/
I am trying to round down the user input with parseInt ( x1 * 100 ) / 100 and the result for 9999.8 is 9999.79
Should I use another way to achieve this?

That's no bug. You may want to check out:
Is JavaScript’s math broken?
Integer arithmetic in floating-point is exact, so decimal representation errors can be avoided by scaling. For example:
x1 = 9999.8; // Your example
console.log(x1 * 100); // 999979.9999999999
console.log(x1 * 100 / 100); // 9999.8
console.log(x1 / 100); // 99.99799999999999
x1 = 9999800; // Your example scaled by 1000
console.log((x1 * 100) / 10000); // 999980
console.log((x1 * 100 / 100) / 10000); // 9999.8
console.log((x1 / 100) / 10000); // 99.998

You could use the toFixed() method:
var a = parseInt ( x1 * 100 ) / 100;
var result = a.toFixed( 1 );

You may want to check this. If you want to do computation on numbers which represent money, you should count cents and use integers.

Related

Custom Rounding up to nearest 0.05

I want to do custom round up to near 0.05 , based on following condition.It is hard to explain , but following example will be easy to understand .
12.910 - 12.90
12.920 - 12.90
12.930 - 12.90
12.940 - 12.90
12.941 - 12.95
12.950 - 12.95
12.960 - 12.95
12.970 - 12.95
12.980 - 12.95
12.990 - 12.95
12.991 - 13.00
13.000 - 13.00
I tried several function , but it is rounding up 12.98 to 13.00.
function customRound( num) {
return Math.round(num * 20) / 20;
}
Coming at this visually, your rounding algorithm seems to look like this:
The dot is where you want to round to for that interval. ( marks the open end of an interval, ] the closed end. (12.99 belongs to the red interval.) We'll implement this algorithm by manipulating the line to match Math.floor's.
First, let's work with integers.
num * 100
Your rounding interval is left-open and right-closed, but Math.floor is left-closed and right-open. We can flip the line to match by multiplying by −1:
num * 100 * -1
⇒ num * -100
Your rounding intervals' lengths are 5, so we need to put the ends of the intervals on multiples of 5...
num * -100 - 1
...before dividing by 5 to match Math.floor.
(num * -100 - 1 ) / 5
⇒ num * -20 - 0.2
Now we can take the floor.
return Math.floor(num * -20 - 0.2);
Scale back up to the original by multiplying by 5:
return Math.floor(num * -20 - 0.2) * 5;
Shift the returned value over to the dot by adding 4:
return Math.floor(num * -20 - 0.2) * 5 + 4;
Undo the alignment we did earlier:
return Math.floor(num * -20 - 0.2) * 5 + 4 + 1;
⇒ return Math.floor(num * -20 - 0.2) * 5 + 5;
Undo the flip:
return (Math.floor(num * -20 - 0.2) * 5 + 5) * -1;
⇒ return Math.floor(num * -20 - 0.2) * -5 - 5;
And divide the whole thing by 100 to get your original scale back:
return (Math.floor(num * -20 - 0.2) * -5 - 5) / 100;
⇒ return Math.floor(num * -20 - 0.2) * -0.05 - 0.05;
Using Robin Zigmond's testing framework,
function customRound(num) {
return Math.floor(num * -20 - 0.2) * -0.05 - 0.05;
}
// test desired results
var tests = [12.91, 12.92, 12.93, 12.94, 12.941, 12.95, 12.96, 12.97, 12.98, 12.99, 12.991, 13];
for (var i=0; i<tests.length; i++) {
console.log(`${tests[i].toFixed(3)} - ${customRound(tests[i]).toFixed(2)}`);
}
If you really intended to round everything within < .01 of the nearest .05 then try the below, to get the precision of the number it uses answer from Is there a reliable way in JavaScript to obtain the number of decimal places of an arbitrary number?
function decimalPlaces(n) {
var s = "" + (+n);
var match = /(?:\.(\d+))?(?:[eE]([+\-]?\d+))?$/.exec(s);
if (!match) { return 0; }
return Math.max(
0, // lower limit.
(match[1] == '0' ? 0 : (match[1] || '').length)
- (match[2] || 0));
}
var test = 12.941;
var factor = Math.pow(10,decimalPlaces(test));
var remainder = ((test * factor) % (.05 * factor))/factor;
var result;
if (remainder>.04) {
result = Math.round(test*20)/20;
} else {
result = (test*factor - remainder*factor)/factor;
}
console.log('result is:',result);
As far as I can tell from your example, the desired behaviour appears to be "round up to the nearest 0.01, then round that result down to the nearest 0.05".
This can be implemented as follows. As you can see, it agrees exactly with your examples (I even took care to format it the same way) - but please let me know if I've got the wrong end of the stick.
function customRound(num) {
var intermediateResult = Math.ceil(num*100)/100;
return Math.floor(intermediateResult*20)/20;
}
// test desired results
var tests = [12.91, 12.92, 12.93, 12.94, 12.941, 12.95, 12.96, 12.97, 12.98, 12.99, 12.991, 13];
for (var i=0; i<tests.length; i++) {
console.log(`${tests[i].toFixed(3)} - ${customRound(tests[i]).toFixed(2)}`);
}

Calculate percentage increase using math formula

I have a function that calculates percentage increase of 2 numbers:
const 1st_num = 50
const 2nd_num = 100
percentage = ((1st_num - 2nd_num) / 1st_num) * 100 // -100
It seems correct but what if the 1st number is 1?
((1 - 50) / 1) * 100 // -4900
I don't see it making sense anymore. What am I missing?
If you are computing a delta variation in percentage between 2 numbers, it should be the other way around:
variation = ((num2 - num1) / num1) * 100
Last but not least, your delta can be over 100%
For example, imagine at
t1=10 and t2=11 -> your delta will be computed like this : (11 - 10)/10, so you have an increase of 10%
but if you have t1=10 and t2=100 -> your delta will become (100 - 10)/10, so you have an increase of 900%
First up all your question is more suitable to somewhere in math forums:
Your formula is right just change it as follows to get increase change in positive numbers:
percentage = ((2nd_num - 1st_num) / 1st_num) * 100 // 100%
However your treatment with 1 is exactly right.
4900 % In other words 49 times increase in value.
You can't use variable name starts with numbers
const fst_num = 50
const snd_num = 100
percentage = ((snd_num -fst_num) / fst_num) * 100
const fst_num = 70192.32
const snd_num = 17548.08
const percentage = ( 100 - ( ( fst_num - snd_num ) / fst_num ) * 100 );

How to Round Up an Integer Javascript

I would like to round up an integer with Javascript.
I have a JSON that retrieve an amount e.g 7435 but I want to round it up to 7500, so I can use in an simple math function. Any ideas? Cause round, and ceil are working only with decimals.
You can use the Math.ceil function
Math.ceil(7435/100)*100;
Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/ceil
You can use this formula:
x = Math.floor((x+99) / 100)*100;
or
x = Math.ceil(x/100) * 100;
or go learn some Math :-)
Math.ceil( number / 100 ) * 100 should work. If you do Math.ceil(7435/100) it will give you 75 and multiplying by 100 will give you 7500. Ceil does not only work with decimals.
var rounded = Math.ceil( 7435 / 100) * 100;
console.log(rounded);

what is the reverse formula of $price_with_tax = price_without_tax + (price_without_tax * (price_tax_rate / 100))

I am trying to get the price_with_tax base on the given price without tax and tax rate on javascript and it works using the formula i mentioned.now I want to get the price_without_tax given the price_with_tax and tax_rate. I did it with
price_wo_tax = price_w_tax - (price_w_tax * (price_tax_rate / 100));
but our formula seems to be wrong? anyone who knows the reverse formula?
If you reverse your formula, you can get following:
price_wo_tax = (100 * price_w_tax) / (100 + price_tax_rate);
Here's explanation:
price_w_tax = price_wo_tax + (price_wo_tax * (price_tax_rate / 100))
transforms to
price_w_tax = price_wo_tax * (1 + price_tax_rate / 100))
transforms to
price_w_tax / (1 + price_tax_rate / 100)) = price_wo_tax
transforms to
price_wo_tax = 100 * price_w_tax / (100 + price_tax_rate)
If your taxrate is say x%, and your total amount is $y.
GST = y - y/(1+x/100)
Of course, if your taxrate is not in percent but is a fraction between 0 and 1, the formula gets
GST = y - y/(1+x)

How to generate random integers which are multiples of 30 in JavaScript

I'm trying to generate random integers that are are multiples of 30 in JavaScript.
That is:
0 60 0 180 120 ...... and so on
in range between 0 to 360 for example
So I am looking for a function something like this:
function (_range,_multi)
{
Math.round(...);
return rndNum;
}
Generate a random number between 0 and 12 (range) and multiply by 30 (multi):
Math.floor(Math.random() * 12) * 30
This gives you [0, 360) (so you never get 360)
Here's a live demo that shows a full working function - the general idea is that you multiply by (max/multiple), floor the value, then multiply it by the multiple:
function generate(min, max, multiple) {
var res = Math.floor(Math.random() * ((max - min) / multiple)) * multiple + min;
return res;
}
alert(generate(0, 360, 30));
Seems like that should work.
function randomMultiple(max, mult) {
return Math.floor(Math.random() * (max / mult)) * mult;
}
Thus a call of randomMultiple(360, 30) would produce an element of G with
G = { y = 30 * x | 0 < x < 12 }

Categories