How can cut number at the second demical point? [duplicate] - javascript

This question already has answers here:
Truncate number to two decimal places without rounding
(43 answers)
Closed 2 years ago.
I got a question.
My backend recieve number string from frontend.
The important point is, I want to cut number at the second demical point.
ex1) '2.346' => 2.34
ex2) '2.3' => 2.3
ex3) '4.246' => 4.24
ex4) '4.1' => 4.1
And when I try this code with '2.346' or '4.246'
let v = '2.346'
v = parseInt(v * 100) / 100
console.log(v)
// v = 2.34
But when I try this code with 2.3 or 4.1, it makes wierd...
let v = '2.3'
v = parseInt(v * 100) / 100
console.log(v)
// v = 2.29
what is the problem in my code...?

Floating-point precision means that multiplying and then dividing by the same number like with your parseInt(v * 100) / 100 may sometimes have long trailing insignificant digits that weren't there to begin with.
If I were you, I'd use a regular expression to match up to 2 digits past a . instead:
const clean = str => str.match(/\d+(?:\.\d{1,2})?/)[0];
console.log(clean('2.346'));
console.log(clean('2.3'));

function tofixed(str){
return parseInt(str * 1000 / 10) /100
}
console.log(tofixed("2.346"))
console.log(tofixed("2.3"))
console.log(tofixed("4.246"))
console.log(tofixed("4.1"))

Related

Javascript calculates large integers incorrectly [duplicate]

This question already has answers here:
Extremely large numbers in javascript
(5 answers)
Closed 2 years ago.
I am making a program about the formula 10^(a-1)-1 mod a = 0. However, when using Javascript, it doesn't work with numbers for a above 23. Example:
var b = 29
var a = Math.pow(10, b-1)
console.log(a);
console.log(a/b);
console.log(a % b)
This is the output:
1e+28
3.448275862068965e+26
14
The output for the modulo function should be 1. Is there any way to make it solve the calculations correctly?
You can use BigInt.
var b = 29n;
var a = 10n ** (b - 1n);
console.log(a.toString());
console.log((a/b).toString());
console.log((a % b).toString());

Splitting a real number into 2 addends

As an extension to my answer to this question, I am trying to split a real number in such a way that each of the two numbers differ by atmost 1 in their last digit (subject to the limitations of floating point arithmetic representation).
For example:
7 => 4, 3
7.2 => 3.6, 3.6
7.3 => 3.7, 3.6 (or 3.5999999999999996) -- I understand this is a corner case and it is alright
7.25 => 3.63, 3.62
7.225 => 3.613, 3.612
To clarify, the resultant addends must contain the same number of digits as the original number.
This is what I've come up with so far.
var x = 7.3;
if(x != Math.round(x)) {
var p1 = Math.ceil((x / 2) * 10) / 10;
} else {
var p1 = Math.ceil(x / 2);
}
var p2 = x - p1;
console.log(p1, p2);
This works for whole numbers and numbers with one decimal after the point as of now. I believe the general solution would involve figuring out how many digits appear after the point.
I am unsure of how to do this, but I believe one solution would involve converting to a string, splitting on '.', finding the digit count, and then multiplying/dividing by the appropriate power of 10... basically extending the code I've written, so it works for any arbitrary number.
Javascript solutions preferred, but a python solution would also work. Any help would be appreciated. Thank you!
Quickly whipped this up, does it fit your needs?
function GenerateAddends(n){
if(n == Math.round(n)){
return [Math.round(n/2),n-Math.round(n/2)];
}else{
var len = n.toString().split(".")[1].length
return [
Math.round(n/2 * Math.pow(10,len)) / Math.pow(10,len),
n - Math.round(n/2 * Math.pow(10,len)) / Math.pow(10,len)
]
}
}
console.log(GenerateAddends(7))
console.log(GenerateAddends(7.2))
console.log(GenerateAddends(7.3))
console.log(GenerateAddends(7.25))
console.log(GenerateAddends(7.225))
Alternatively using ECMAScript 2016:
function GenerateAddends(n){
if(n == Math.round(n)){
return [Math.round(n/2),n-Math.round(n/2)];
}else{
var len = n.toString().split(".")[1].length
return [
Math.round(n/2 * 10**len) / 10**len,
n - Math.round(n/2 * 10**len) / 10**len
]
}
}
console.log(GenerateAddends(7))
console.log(GenerateAddends(7.2))
console.log(GenerateAddends(7.3))
console.log(GenerateAddends(7.25))
console.log(GenerateAddends(7.225))
You'll notice that I had the same thought as you of converting to a string and getting the number of decimal places.
Here's a python example:
import math
def split_num(num):
i = 0
while (num != round(num, i)): ## NOTE: guaranteed to terminate
i = i + 1
p1 = math.ceil( ( 10**i * num ) / 2) / 10**i ## using 10**i rounds to the appropriate decimal place
return (p1, num - p1)
## test output
if __name__ == "__main__":
print(split_num(10))
print(split_num(10.1))
print(split_num(10.12))
print(split_num(10.123))
print(split_num(10.1234))
print(split_num(7.3))
>>> python split_num.py
(5.0, 5.0)
(5.1, 5.0)
(5.06, 5.06)
(5.062, 5.060999999999999)
(5.0617, 5.0617)
(3.7, 3.5999999999999996)

Multiplication gives approximate results

Hmm I have an issue with roundings on the client side which is then validated in the backend and the validation is failing due to this issue. Here is the previous question Javascript and C# rounding hell
So what I am doing is:
On client side:
I have 2 numbers: 50 and 2.3659
I multiply them: 50 * 2.3659 //118.29499999999999
Round to 2 decimal places: kendo.toString(50 * 2.3659, 'n2') //118.29
In backend(C#):
I am doing the same: 50 and 2.3659
I multiply them: 50 * 2.3659 //118.2950
Round to 2 decimal places: Math.Round(50 * 2.3659, 2) //118.30
And validation is failing. Can I do something on the client side?
Can you try parseFloat and toFixed functions as follows :
var mulVal = parseFloat(50) * parseFloat(2.3659);
var ans = mulVal.toFixed(2);
console.log(ans);
Javascript Arithmetic is not always accurate, and such erroneous answers are not unusual. I would suggest that you use Math.Round() or var.toFixed(1) for this scenario.
Using Math.Round:
var value = parseFloat(50) * parseFloat(2.3659);
var rounded = Math.round(value);
console.log(rounded);
Prints 118 to the console.
Using toFixed() method:
var value = parseFloat(50) * parseFloat(2.3659);
var rounded = value.toFixed(1);
console.log(rounded);
Prints 118.3 to the console.
Note that using toFixed(2) will give the value as 118.29.
Hope this helps!
Haven't tested this extensively, but the function below should emulate the 'MidPointToEven' rounding:
function roundMidPointToEven(d, f){
f = Math.pow(10, f || 0); // f = decimals, use 0 as default
let val = d * f, r = Math.round(val);
if(r & 1 == 1 && Math.sign(r) * (Math.round(val * 10) % 10) === 5)
r += val > r ? 1 : -1; //only if the rounded value is odd and the next rounded decimal would be 5: alter the outcome to the nearest even number
return r / f;
}
for(let d of [50 * 2.3659, 2.155,2.145, -2.155, 2.144444, 2.1, 2.5])
console.log(d, ' -> ', roundMidPointToEven(d, 2)); //test values correspond with outcome of rounding decimals in C#

JavaScript math, round to two decimal places [duplicate]

This question already has answers here:
How to round to at most 2 decimal places, if necessary
(91 answers)
Closed 5 years ago.
I have the following JavaScript syntax:
var discount = Math.round(100 - (price / listprice) * 100);
This rounds up to the whole number. How can I return the result with two decimal places?
NOTE - See Edit 4 if 3 digit precision is important
var discount = (price / listprice).toFixed(2);
toFixed will round up or down for you depending on the values beyond 2 decimals.
Example: http://jsfiddle.net/calder12/tv9HY/
Documentation: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed
Edit - As mentioned by others this converts the result to a string. To avoid this:
var discount = +((price / listprice).toFixed(2));
Edit 2- As also mentioned in the comments this function fails in some precision, in the case of 1.005 for example it will return 1.00 instead of 1.01. If accuracy to this degree is important I've found this answer: https://stackoverflow.com/a/32605063/1726511 Which seems to work well with all the tests I've tried.
There is one minor modification required though, the function in the answer linked above returns whole numbers when it rounds to one, so for example 99.004 will return 99 instead of 99.00 which isn't ideal for displaying prices.
Edit 3 - Seems having the toFixed on the actual return was STILL screwing up some numbers, this final edit appears to work. Geez so many reworks!
var discount = roundTo((price / listprice), 2);
function roundTo(n, digits) {
if (digits === undefined) {
digits = 0;
}
var multiplicator = Math.pow(10, digits);
n = parseFloat((n * multiplicator).toFixed(11));
var test =(Math.round(n) / multiplicator);
return +(test.toFixed(digits));
}
See Fiddle example here: https://jsfiddle.net/calder12/3Lbhfy5s/
Edit 4 - You guys are killing me. Edit 3 fails on negative numbers, without digging into why it's just easier to deal with turning a negative number positive before doing the rounding, then turning it back before returning the result.
function roundTo(n, digits) {
var negative = false;
if (digits === undefined) {
digits = 0;
}
if (n < 0) {
negative = true;
n = n * -1;
}
var multiplicator = Math.pow(10, digits);
n = parseFloat((n * multiplicator).toFixed(11));
n = (Math.round(n) / multiplicator).toFixed(digits);
if (negative) {
n = (n * -1).toFixed(digits);
}
return n;
}
Fiddle: https://jsfiddle.net/3Lbhfy5s/79/
If you use a unary plus to convert a string to a number as documented on MDN.
For example:+discount.toFixed(2)
The functions Math.round() and .toFixed() is meant to round to the nearest integer. You'll get incorrect results when dealing with decimals and using the "multiply and divide" method for Math.round() or parameter for .toFixed(). For example, if you try to round 1.005 using Math.round(1.005 * 100) / 100 then you'll get the result of 1, and 1.00 using .toFixed(2) instead of getting the correct answer of 1.01.
You can use following to solve this issue:
Number(Math.round(100 - (price / listprice) * 100 + 'e2') + 'e-2');
Add .toFixed(2) to get the two decimal places you wanted.
Number(Math.round(100 - (price / listprice) * 100 + 'e2') + 'e-2').toFixed(2);
You could make a function that will handle the rounding for you:
function round(value, decimals) {
return Number(Math.round(value + 'e' + decimals) + 'e-' + decimals);
}
Example:
https://jsfiddle.net/k5tpq3pd/36/
Alternative
You can add a round function to Number using prototype. I would not suggest adding .toFixed() here as it would return a string instead of number.
Number.prototype.round = function(decimals) {
return Number((Math.round(this + "e" + decimals) + "e-" + decimals));
}
and use it like this:
var numberToRound = 100 - (price / listprice) * 100;
numberToRound.round(2);
numberToRound.round(2).toFixed(2); //Converts it to string with two decimals
Example
https://jsfiddle.net/k5tpq3pd/35/
Source: http://www.jacklmoore.com/notes/rounding-in-javascript/
To get the result with two decimals, you can do like this :
var discount = Math.round((100 - (price / listprice) * 100) * 100) / 100;
The value to be rounded is multiplied by 100 to keep the first two digits, then we divide by 100 to get the actual result.
The best and simple solution I found is
function round(value, decimals) {
return Number(Math.round(value+'e'+decimals)+'e-'+decimals);
}
round(1.005, 2); // 1.01
try using discount.toFixed(2);
I think the best way I've seen it done is multiplying by 10 to the power of the number of digits, then doing a Math.round, then finally dividing by 10 to the power of digits. Here is a simple function I use in typescript:
function roundToXDigits(value: number, digits: number) {
value = value * Math.pow(10, digits);
value = Math.round(value);
value = value / Math.pow(10, digits);
return value;
}
Or plain javascript:
function roundToXDigits(value, digits) {
if(!digits){
digits = 2;
}
value = value * Math.pow(10, digits);
value = Math.round(value);
value = value / Math.pow(10, digits);
return value;
}
A small variation on the accepted answer.
toFixed(2) returns a string, and you will always get two decimal places. These might be zeros. If you would like to suppress final zero(s), simply do this:
var discount = + ((price / listprice).toFixed(2));
Edited:
I've just discovered what seems to be a bug in Firefox 35.0.1, which means that the above may give NaN with some values.
I've changed my code to
var discount = Math.round(price / listprice * 100) / 100;
This gives a number with up to two decimal places. If you wanted three, you would multiply and divide by 1000, and so on.
The OP wants two decimal places always, but if toFixed() is broken in Firefox it needs fixing first.
See https://bugzilla.mozilla.org/show_bug.cgi?id=1134388
Fastest Way - faster than toFixed():
TWO DECIMALS
x = .123456
result = Math.round(x * 100) / 100 // result .12
THREE DECIMALS
x = .123456
result = Math.round(x * 1000) / 1000 // result .123
function round(num,dec)
{
num = Math.round(num+'e'+dec)
return Number(num+'e-'+dec)
}
//Round to a decimal of your choosing:
round(1.3453,2)
Here is a working example
var value=200.2365455;
result=Math.round(value*100)/100 //result will be 200.24
To handle rounding to any number of decimal places, a function with 2 lines of code will suffice for most needs. Here's some sample code to play with.
var testNum = 134.9567654;
var decPl = 2;
var testRes = roundDec(testNum,decPl);
alert (testNum + ' rounded to ' + decPl + ' decimal places is ' + testRes);
function roundDec(nbr,dec_places){
var mult = Math.pow(10,dec_places);
return Math.round(nbr * mult) / mult;
}

Math.round Rounding Error

I Want to round 1.006 to two decimals expecting 1.01 as output
When i did
var num = 1.006;
alert(Math.round(num,2)); //Outputs 1
alert(num.toFixed(2)); //Output 1.01
Similarly,
var num =1.106;
alert(Math.round(num,2)); //Outputs 1
alert(num.toFixed(2));; //Outputs 1.11
So
Is it safe to use toFixed() every time ?
Is toFixed() cross browser complaint?
Please suggest me.
P.S: I tried searching stack overflow for similar answers, but could not get proper answer.
EDIT:
Why does 1.015 return 1.01 where as 1.045 returns 1.05
var num =1.015;
alert(num.toFixed(2)); //Outputs 1.01
alert(Math.round(num*100)/100); //Outputs 1.01
Where as
var num = 1.045;
alert(num.toFixed(2)); //Outputs 1.04
alert(Math.round(num*100)/100); //Outputs 1.05
Try something like...
Math.round(num*100)/100
1) Multiple the original number by 10^x (10 to the power of x)
2) Apply Math.round() to the result
3) Divide result by 10^x
from: http://www.javascriptkit.com/javatutors/round.shtml
(to round any number to x decimal points)
This formula Math.round(num*100)/100 is not always good. Example
Math.round(0.145*100)/100 = 0.14
this is wrong, we want it to be 0.15
Explanation
The problem is that we have floats like that
0.145 * 100 = 14.499999999999998
step one
so If we round, we need to add a little bit to our product.
0.145 * 100 + 1e-14 = 14.500000000000009
I assume that sometimes the product might be something like 1.000000000000001, but it would not be a problem if we add to it, right?
step two
Calculate how much should we add?
We know float in java script is 17 digits.
let num = 0.145
let a = Math.round(num*100)/100
let b = a.toString().length
let c = 17-b-2
let result = Math.round(num*100 + 0.1**c)/100
console.log(result)
console.log('not - ' + a )
(-2) - is just to be sure we are not falling into the same trap of rounding.
One-liner:
let num = 0.145
let result = Math.round(num*100 + 0.1**(17-2-(Math.round(num*100)/100).toString().length))/100
Extras
Remember, that everything above is true for positive numbers. If you rounding negative number you would need to subtract a little bit. So the very final One-liner would be:
let num = -0.145
let result = Math.round(num*100 + Math.sign(num)*0.1**(17-2-(Math.round(num*100)/100).toString().length))/100
I realize this problem is rather old, but I keep running into it even 5 years after the question has been asked.
A working solution to this rounding problem I know of is to convert the number to a string, get the required precision number and round up or down using math rules.
An example where Math.round provides unexpected rounding and an example of string rounding can be found in the following fiddle:
http://jsfiddle.net/Shinigami84/vwx1yjnr/
function round(number, decimals = 0) {
let strNum = '' + number;
let negCoef = number < 0 ? -1 : 1;
let dotIndex = strNum.indexOf('.');
let start = dotIndex + decimals + 1;
let dec = Number.parseInt(strNum.substring(start, start + 1));
let remainder = dec >= 5 ? 1 / Math.pow(10, decimals) : 0;
let result = Number.parseFloat(strNum.substring(0, start)) + remainder * negCoef;
return result.toFixed(decimals);
}
let num = 0.145;
let precision = 2;
console.log('math round', Math.round(num*Math.pow(10, precision))/Math.pow(10, precision));
// 0.145 rounded down to 0.14 - unexpected result
console.log('string round', round(num, precision));
// 0.145 rounded up to 0.15 - expected result
Math.round doesn't work properly here because 0.145 multiplied by 100 is 14.499999999999998, not 14.5. Thus, Math.round will round it down as if it was 14.4. If you convert it to a string and subtract required digit (5), then round it using standard math rules, you will get an expected result of 0.15 (actually, 0.14 + 0.01 = 0.15000000000000002, use "toFixed" to get a nice, round result).

Categories