numbers and toFixed , toPrecision in Javascript? - javascript

Regarding the famous issue of 1.01+1.02 which is 2.0300000000000002
one of the workarounds is to use toFixed : e.g.
(1.01+1.02).toFixed(2) --->"2.03"
But I saw a solution with toPrecision
parseFloat((1.01+1.02).toPrecision(10))-->"2.03"
But lets have a look at n in
toFixed(n)
toPrecision(n)
How would I know what is n ?
0.xxxxxxxxxxx
+
0.yyyyyyyyyyyyy
---------------------
0.zzzzzzzzzzzzzzzzzzzzzzzzz
^
|
-----??????------
each number being added can have a different decimal digits...
for example :
1.0002+1.01+1.03333--> 3.0435300000000005
how would I calculate the n here ? what is the best practice for this (specific) issue ?

For addition as in this situation I would check the number of decimal places in each operand.
In the simplest of situations the number of decimal places in the operand with the greatest number of decimal places is the value of n.
Once you have this, use which ever method you like to truncate your value. Then get rid of trailing zeros.
You may encounter trailing zeros in situations such as 1.06 + 1.04, the first step would take you to 1.10 then truncating the zero would give 1.1
In your last example 1.0002+1.01+1.03333 greatest number of decimal places is 5 so you are left with 3.04353 and there are no trailing zeros to truncate.

This returns the expected output:
function add(){
// Initialize output and "length" properties
var length = 0;
var output = 0;
// Loop through all arguments supplied to this function (So: 1,4,6 in case of add(1,4,6);)
for(var i = 0; i < arguments.length; i++){
// If the current argument's length as string is longer than the previous one (or greater than 0 in case of the first argument))
if(arguments[0].toString().length > length){
// Set the current length to the argument's length (+1 is to account for the decimal point taking 1 character.)
length = arguments[0].toString().length +1;
}
// Add the current character to the output with a precision specified by the longest argument.
output = parseFloat((output+arguments[i]).toPrecision(length));
}
// Do whatever you with with the result, here. Usually, you'd 'return output;'
console.log(output);
}
add(); // Returns 0
add(1,2,3); // Returns 6
add(1.01,2.01,3.03); // Returns 6.05
add(1.01,2.0213,3.3333); // Returns 6.3646
add(11.01,2.0213,31.3333); // Returns 44.3646
parseFloat even gets rid of trailing zero's for you.
This function accepts as many numbers as parameters as you wish, then adds these together taking the numbers' string length into account, when adding them. The precision used in the addition is dynamically modified to fit the "currently added" argument's length.
Fiddle

If you're doing calculations, you have a couple of choices:
multiply the numbers by eg 100, to convert to integers, then do the calculations, then convert back again
do the calculations, dont worry about the rounding errors, then round the result at display time
If you're dealing with money/currencies, the first option is probably not a bad option. If you're just doing scientific maths, I would personally not worry about it, and just round the results at display time, eg to 6 significant figures which is the default for my c++ compiler (gcc; not sure if it is in the c++ standards or not, but if you print 1.234567890 in gcc c++, the output is 1.23457, and the problem is avoided)

var a = 216.57421;
a.toPrecision(1); // => '200' because 216 with 1 < 5;
a.toPrecision(2); // => '220' because 216 with 6 >= 5;
a.toFixed(1); // => 216.6 because 7 >= 5;
a.toFixed(2); // => 216.57 because 4 < 5;

Related

How to get digits from a BigInt in javascript?

I am working on problem n°104 of project Euler Problem 104 and would like to do it in javascript.
In order to solve this problem I need to compute large values of the Fibonacci sequence, but the numbers produced by this sequence are too large to be handle by classic Number, so I'm using BigInt supported in the latest versions of javascript.
Once I've got a particular result stored in a BigInt, I need to check it's 10 first, and last digits.
To get the digits from a Number we usually do something like in the code below, but when the number becomes very large, things go wrong:
let number = BigInt(123456789)
console.log(number.toString())
console.log(number.toString()[3]) // Result is fine
let bigNumber = BigInt(1234567891111111111111111111111111111)
console.log(bigNumber.toString())
console.log(bigNumber.toString()[30]) // unpredictable result
It seems like the "toString()" methods is only using the precision of the Number type (2^53 I believe), thus we are quickly losing precision on the last digits of the BigInt number. The problem is I can't find other methods to extract those digits.
Edit :
I need the precision to be perfect because basicaly what i'm doing for example is :
Compute Fibonacci(500) = 280571172992510140037611932413038677189525
Get the 10 last digits of this number : 8677189525 (this is where is lose the precision)
And then to solve my problem I need to check that those 10 last digits contains all the digits from 1 to 9
For big numbers, I think you should add the n suffix:
let number = BigInt(123456789)
console.log(number.toString())
console.log(number.toString()[3]) // Result is fine
let bigNumber = 1234567891111111111111111111111111111n // <-- n suffix, literal syntax
console.log(bigNumber.toString())
console.log(bigNumber.toString()[30]) // result
let bigNumber2 = BigInt('1234567891111111111111111111111111111') // <-- also works as a string, in case you can't use the literal for some reason
console.log(bigNumber2.toString())
console.log(bigNumber2.toString()[30]) // result

How can I round a float such that there are only two trailing digits after the decimal point?

I have a float number like 137.57667565656 but I would like to round it such that there are only two trailing digits after the decimal point like the new float number will be 137.58.
I tried this so far:
(Math.round((value*100)/100)).toFixed(2).toString();
But unfortunately, it rounds my value to 137.00. It adds the decimals places as zeroes, why?
How can I achieve the above?
What did you expect?
(value*100)/100
simply returns the original value of value, so
Math.round((value*100)/100))
is identical to:
Math.round(value)
you then have:
Math.round(value).toFixed(2).toString();
so value is rounded to an integer, toFixed will add two decimal places and return a string so the toString part is redundant. If you wish to round value to four decimal places, then:
value.toFixed(4)
will do the job:
var x = 137.57667565656;
console.log(x.toFixed(4)); // 137.5767
If you want to round it to 2 places but present it as 4, then:
Number(x.toFixed(2)).toFixed(4) // 137.5800
I have a simpler answer that works for all significant figures, not just four.
JavaScript provides a built-in Number.toPrecision() function that returns a string representing a number in significant digits.
var value = 137.57667565656;
var strVal = value.toPrecision(4);
>> 137.6
There have been a lot of misconceptions about significant figures on this post. See Wikipedia to refresh your memory. See #RobG's answer for why your original method was incorrect.
Two zeroes are added because prior to all you do Math.round:
If the fractional portion of number is .5 or greater, the argument is
rounded to the next higher integer. If the fractional portion of
number is less than .5, the argument is rounded to the next lower
integer.
(taken from here)
What you need is to drop Math.round:
(value*100)/100).toFixed(4).toString();
See it on JSFiddle: http://jsfiddle.net/0fe5mm95/
Edit Apparently i misunderstood the question. When I tried to answer it was (at least in the title) about significant digits.
This answer lines up with Wikipedia's definition of significant digits. It solves the general problem, for any number of significant digits, in three steps:
figure out number of digits with log10 (negative if -1<x<1, e.g 5 for 12345, or -2 for 0.01)
round the number at the correct position (e.g. if x=12345 with three significant digits, then round the 45 to 00)
append the required number of zeros on the right
And that's all. Except the zero, which has no significant digits. (I went for "0.00" when asking for three significant digits, but 0 or 0.0 would be fine also)
function toStringWithSignificantDigits( x, len ){
if(x==0) return x.toFixed(len-1); // makes little sense for 0
var numDigits = Math.ceil(Math.log10(Math.abs(x)));
var rounded = Math.round(x*Math.pow(10,len-numDigits))*Math.pow(10,numDigits-len);
return rounded.toFixed(Math.max(len-numDigits,0));
}
function testIt(x,len){
console.log( "format " + x + " to " + len + " significant digits: " + toStringWithSignificantDigits(x,len));
}
testIt(12.345,6); // 12.3450
testIt(12.345,5); // 12.345
testIt(12.345,4); // 12.35
testIt(12.345,3); // 12.3
testIt(12.345,2); // 12
testIt(12.345,1); // 10
testIt(0.012345,7); // 0.01234500
testIt(0.012345,6); // 0.0123450
testIt(0.012345,5); // 0.012345
testIt(0.012345,4); // 0.01235
testIt(0.012345,3); // 0.0123
testIt(0.012345,2); // 0.012
testIt(0.012345,1); // 0.01
testIt(0,3); // 0.00, zero is a special case, as it has no significant digit

How to output the number 2.00 as a complete string?

Before this, i want to say sorry. But this is not duplicate. Any answer on other posting has same problem. No float or int in JS (only number). When you make isInt() function, 2.00 always detected true as integer. I want 2.00 detected as float. So, i have to stringify it first.
function isInt(i) {
if ( i.toFixed ) {
if ( i % 1 === 0 ) {
return true; // the problem is 2.00 always detected true as integer.
// i want 2.00 detected as float
} else {
return false;
}
} else {
return false;
}
}
then i think i will stringify the 2.00 and then split it with split('.') . But toString doesn't do it
var i = 2.00;
alert(i.toString());
// Why this always result 2 . i want the character behind point
So, how to do that? i want 2.00 result "2.00" , not only "2"
Thank you for answering
You can use Number.toFixed(n);
var i = 2;
alert( i.toFixed(2) ); // "2.00"
var i = 1.2345;
alert( i.toFixed(2) ); // "1.23"
Also note that 2 === 2.00 but 2 !== "2.00".
Answer to revision:
Within javascript there is absolutely no way to distinguish between 2 2.0 and 2.000. Therefore, you will never without some additional decimal place supplied, be able to detect from var a = 2.00 that 2 was ever anything other than an integer (per your method) after it's been assigned.
Case in point, despite the [misleading] built-in methods:
typeof parseInt('2.00', 10) == typeof parseFloat('2.00')
'number' == 'number'
/* true */
Original Answer:
JavaScript doesn't have hard-based scalar types, just simply a Number. For that reason, and because you really only have 1 significant figure, JavaScript is taking your 2.00 and making it an "integer" [used loosly] (therefore no decimal places are present). To JavaScript: 2 = 2.0 = 2.00 = 2.00000).
Case in point, if I gave you the number 12.000000000000 and asked you to remember it and give it to someone a week from now, would you spend the time remember how many zeros there were, or focus on the fact that I handed you the number 12? (twelve takes a lot less effort to remember than twelve with as many decimal places)
As far as int vs float/double/real, you're really only describing the type of number from your perspective and not JavaScript's. Think of calling a number in JavaScript an int as giving it a label and not a definition. to outline:
Value: To JavaScript: To Us:
------ -------------- ------
1 Number integer
1.00 Number decimal
1.23 Number decimal
No matter what we may classify it as, JavaScript still only sees it as a Number.
If you need to keep decimal places, Number.toFixed(n) is going to be your best bet.
For example:
// only 1 sig-fig
var a = 2.00;
console.log(''+a); // 2
console.log(a.toFixed(2)); // 2.00
// 3 sig-figs
var b = 2.01
console.log(''+b); // 2.01
console.log(b.toFixed(2)); // 2.01
BTW, prefixing the var with ''+ is the same as calling a .toString(), it's just cast just shorthand. The same outcome would result if I had used a.toString() or b.toString()
To stringify (Chrome at least does so) use this:
i.toPrecision(3)
This will show 2 decimal digits.
Also NULL's solution does it very well without having to calculate the exact precision. i.e. .toFixed(decimals) is your best friend
You can't do exactly what you want to do.
2.00 gets converted to the number 2 in JavaScript, without decimal points. You can add it back in if you want using .toFixed(2), shown above.
I suggest keeping "2.00" as a string, as well as parsing it as a number, if necessary, for arithmetic. That way you can distinguish whether the number 2 was entered as "2", or "2.00", or "2.000000". Output the string, not the number, if you want to preserve the original number of decimal places.

Fastest way to create this number?

I'm writing a function to extend a number with sign to a wider bit length. This is a very frequently used action in the PowerPC instruction set. This is what I have so far:
function exts(value, from, to) {
return (value | something_goes_here);
}
value is the integer input, from is the number of bits that the value is using, and to is the target bit length.
What is the most efficient way to create a number that has to - from bits set to 1, followed by from bits set to 0?
Ignoring the fact that JavaScript has no 0b number syntax, for example, if I called
exts(0b1010101010, 10, 14)
I would want the function to OR the value with 0b11110000000000, returning a sign-extended result of 0b11111010101010.
A number containing p one bits followed by q zero bits can be generated via
((1<<p)-1)<<q
thus in your case
((1<<(to-from))-1)<<from
or much shorter
(1<<to)-(1<<from)
if you have the number 2^q (= 1 shifted left by q) represented as an integer of width p + q bits, it has the representation:
0...010...0
p-1 q
then 2^q - 1 has the representation
0...01...1
p q
which is exactly the opposite of you want. So just flip the bits
hence what you want is NOT((1 LEFT SHIFT by q) - 1)
= ~((1 << q) - 1) in c notation
I am not overly familiar with binary mathematics in JavaScript... But if you need to OR a number with 0b11110000000000, then I assume you would just convert that to decimal (which would get you 15360), and do value | 15360.
Relevant info that you may find useful: parseInt("11110000000000", 2) converts a binary number (specified as a string) to a decimal number, and (15360).toString(2) converts a decimal number (15360 in this case) to a binary number (the result is a string).
Revised solution
There's probably a more elegant and mathematical method, but here's a quick-and-dirty solution:
var S = "";
for(var i=0;i<p;i++)
S += "1";
for(i=0;i<q;i++)
S += "0";
S = parseInt(S, 2); // convert to decimal

strip decimal points from variable

I have a series of variables that have a decimal point and a few zeros. How do I strip the variable so it goes from 1.000 to 1?
Simply...
Math.round(quantity);
...assuming you want to round 1.7 to 2. If not, use Math.floor for 1.7 to 1.
use parseInt();
parseInt("1.25");//returns 1
parseInt("1.85");//returns 1
parseInt(1.25);//returns 1
parseInt(1.85);//returns 1
Use number = ~~number
This is the fastest substitute to Math.floor()
parseInt is the slowest method
math.floor is the 2nd slowest method
faster methods not listed here are:
var myInt = 1.85 | 0;
myInt = 1;
var myInt = 1.85 >> 0;
myInt = 1;
Speed tests done here:
http://jsperf.com/math-floor-vs-math-round-vs-parseint/2
Use Math.trunc(). It does exactly what you ask. It strips the decimal.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/trunc
For rounding numbers to the nearest Integer you can use Math.round() like so:
Math.round("1.000"); // Will produce 1
Math.round(123.4234); // Will produce 123
You don't need jQuery for this.
You can use parseInt just fine. From the page:
document.write(parseInt("10.33") + "<br />"); // 10
Here's another nice example:
I often use Math.round and toLocateString to convert numbers containing decimal places, into a more readable string, with thousand separators:
var myNumberAsString = "1234567.890123" // "1234567.890123"
var myNumber = Math.round(0.0 + myNumberAsString); // 1234568
return myNumber.toLocaleString(); // "1,234,568"
I find this useful when loading decimal values from, say a JSON Web Service, and need to display them in a friendlier format on a web page (when, of course, I don't need to display all of the decimal places).
A faster, more efficient way would be to use JavaScript's bitwise operators, like so:
function stripDecimals(n) {
return n | 0;
}
// examples:
stripDecimals(23.245); // => 23
stripDecimals(100.015020); // => 100
The | (OR operator) will treat the numbers as 32-bit (binary 0s and 1s), followed by returning the desired result depending on the operands, which in this case would result to an integer stripped of all decimal places.
I suggest you use something called Math.trunc()... put your number in the parentheses. The reason I don't suggest you use Math.round() is that it might change the integer part of your decimal number which some people won't want though you can use Math.round() if you know you want to get the closest integer.

Categories