Why does toPrecision return a String? - javascript

View this code:
function testprecision(){
var isNotNumber = parseFloat('1.3').toPrecision(6);
alert(typeof isNotNumber); //=> string
}
I would have expected a number. If 'isNotNumber' should be a real number, recasting is the solution:
alert(typeof parseFloat(isNotNumber)) //=> number
[Edit]
thanks for your answers. Precision is not so precise a term I conclude. It can represent the total number of digits of a number, or the number of fractional digits. Most people in the Netherlands (where I come from) think of precision in the 'number of fractional digits'-way. The javascript toPrecision method concerns the first representation, so this is confusing. Anyway, the method makes it possible to introduce 'false precision', am I right? For the second meaning we have toFixed, the same goes for that (returns string, possibility of false precision).
Anyway, having made reinventing the wheel my main hobby, I played around to construct a javascript float object, using the knowledge I gathered here. Maybe it's usefull for someone out there, or maybe one of you have better ideas?
function Float(f,nDec) {
var Base = this,val;
setPrecision( nDec || 2 );
set( f || 0, nDec || Base.precision );
Base.set = set;
Base.ndec = setPrecision;
/** public setprecision
* sets a value for the number of fractional
* digits (decimals) you would like getf to
* return. NB: can't be more than 20.
* Returns the Float object, so allows method
* chaining
* #param {Number} iPrecision
*/
function setPrecision(iPrecision) {
var ix = parseInt(iPrecision,10) || 2;
Base.precision = ix >= 21 ? 20 : ix;
return Base;
}
/** public set
* sets the 'internal' value of the object. Returns
* the Float object, so allows method chaining
* #param {Number} f
* #param {Number} ndec
*/
function set(f,ndec) {
val = parseFloat(f) || 0;
if (ndec) { setPrecision(ndec); }
Base.val = val;
return Base;
}
/** public get:
* return number value (as a float)
*/
Base.get = function(){
var ndec = Math.pow(10,Base.precision),
ival = parseInt(val*ndec,10)/ndec;
Base.val = ival;
return Base.val;
};
/** public getf
* returns formatted string with precision
* (see Base.setPrecision)
* if [hx] is supplied, it returns
* the float as hexadecimal, otherwise
* #param {Boolean} hx
*/
Base.getf = function(hx){
var v = Base.val.toFixed(Base.precision);
return hx ? v.toString(16) : v;
};
/** public add
* adds [f] to the current value (if [f] is a
* Float, otherwise returns current value)
* optionally sets a new number of decimals
* from parameter [ndec]
* #param {Number} f
* #param {Number} ndec
*/
Base.add = function(f,ndec){
if ( parseFloat(f) || val===0) {
set(Base.val+parseFloat(f));
if (ndec) { setPrecision(ndec);}
}
return Base.get();
};
/** toString
* returns the internal value of the Float object
* functions like a getter (supposedly)
*/
Base.toString = Base.get;
}
usage/example:
var xf = new Float(); //=> value now 0.0
xf.set(0.86/0.8765,17).add(3.459);
alert(xf+'|'+xf.getf()); //=> 4.440175128351398|4.44017512835139800

From the docs: "Returns a string representing the Number object to the specified precision."
toPrecision() seems intended for formatting output, in which case a string is the most reasonable outcome. It represents the final output in a form that will not be mangled by further manipulation.
If you are looking to do some truncation of precision for calculation reasons, I tend to multiply by 10^n where n is the digits I want to keep, take an integer from that and then divide again by the same. This isn't perfect though: in some situations you may invite an overflow. Frankly, I prefer to do more complex financial calculations on the server, where I have a currency, binary coded decimal or similar numeric types.

Assume you have a number like '1.6'. If you format it to have 6 zeroes to the right, you would get a '1.600000'. To the computer, it is still the same number as 1.6, but to you and your website, it is not the same if all your numbers are of different lenghts (which could hurt a parser, for instance).
So, as to avoid it, toPrecision returns a string, or else the interpreter would reformat the number to become '1.6' again.

The purpose of toPrecision is to truncate the significant decimal digits of a Number to a specified amount. But the datatype of the internal representations of Numbers is binary IEEE-754 double. Therefore it's impossible to store the precise return value in a Number most of the times. As a result of this impreciseness, the return value would have an infinite amount of decimal digits which would render toPrecision void.
So the only reasonable solution to this problem is to return decimal digits. And currently the only reasonable JS datatype for decimal digits is a String.
Here's an example to clarify the impreciseness of Numbers if used for decimal digits:
// the following looks like something with 2 decimal digits:
var number = 1.6;
// but in fact it's a number with an infinite amount of decimal digits.
// let's look at the first 30 of them:
alert(number.toPrecision(30));
// 1.60000000000000008881784197001

Because it is a formatting function.

You need a string for trailing zeros. Currency display is a good example.

The problem is the use of toPrecision. Try it without.
var isNotNumber = parseFloat('1.3');
alert(typeof isNotNumber); //=> number

Related

JS/TSDoc comment on object | number type parameter not typed

I want my function to be typed in 2 scenarios depending on how the user uses the function. If the user uses just a number they type of param will be number. if they use an object for options it will be of type { num: number; dp: number }. This I have working but I want it to be typed for intellisense so when the user hovers they can see type num represents the input number and type dp represents the number of digits to round to but if they just type a number as param then that to be typed as 'a number to round to the nearest int' This is the code I have but cannot get it to do exactly what I want. Any help would be appreciated! Thank you.
/**
* Returns a rounded numbers. If dp isn't entered the number returned will be rounded to the nearest integer.
* #param param - The rounding options or a number to round to an int.
* #param dp - The decimal places to round to.
* #param num - The number to round.
* #returns An rounded number.
*/
const round = (param: { num: number; dp: number } | number) => {
if (typeof param === 'number') return Math.round(param);
const { dp, num } = param;
return Math.round(num * Math.pow(10, dp)) / Math.pow(10, dp);
};
Simply the problem is how to detect both scenarios in TS/JSDoc and type for it

Parse to float with 2 decimal places

I need to round a value with 2 decimal places that I receive from a web service. To do this i use this methods toFixed and parseFloat because I need the final value in a float.
However when I have this value "5.5000000" he shows me the value with only one decimal place "5.5"...
I did in that way:
var num = 5.5000000;
var n = num.toFixed(2);
var numFinal = parseFloat(n);
You have to call toFixed after parseFloat:
parseFloat(yourString).toFixed(2)
You can do something like this
/**
* Convert the value to the Number with the precision.
* #param {Number} value value to be converted
* #param {Number} [precision=0] number of decimal places
* #returns {Number} converted number.
*/
function toNumber (value, precision) {
precision = precision || 0;
if (precision === 0) {
return value * 1;
} else {
return Number((value * 1).toFixed(precision));
}
}
Short Answer: There is no way in JS to have Number datatype value with trailing zeros after a decimal.
Long Answer: Its the property of toFixed or toPrecision function of JavaScript, to return the String. The reason for this is that the Number datatype cannot have value like a = 2.00, it will always remove the trailing zeros after the decimal, This is the inbuilt property of Number Datatype. So to achieve the above in JS we have 2 options
Either use data as a string or
Agree to have truncated value with case '0' at the end ex 2.50 -> 2.5. Number Cannot have trailing zeros after decimal

Adding Two Decimal Places using JavaScript

Good day Everyone!
I want to know how to return the output with two decimal places. Instead of 10,000 I want it to return 10,000.00. Also I already put .toFixed(2) but it's not working.
When the amount has decimal number other than zero, the values appear on the printout, but when the decimal number has a zero value, the Zeros won't appear on the printout.
Also, I have added a value of Wtax that was pulled-out on a "Bill Credit" Transaction.
Output:
Numeral.js - is a library that you can use for number formatting.
With that you can format your number as follows:
numeral(10000).format('$0,0.00');
Hope this will help you.
You can try this
var x = 1000; // Raw input
x.toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,') //returns you 1,000.00
Alternately you can use Netsuite's currency function too
nlapiFormatCurrency('1000'); // returns you 1,000.00
nlapiFormatCurrency('1000.98'); // returns you 1,000.98
You might consider below code. It can round off decimal values based on the decimal places.
This also addresses the issue when rounding off negative values by getting first the absolute value before rounding it off. Without doing that, you will have the following results which the 2nd sample is incorrect.
function roundDecimal(decimalNumber, decimalPlace)
{
//this is to make sure the rounding off is correct even if the decimal is equal to -0.995
var bIsNegative = false;
if (decimalNumber < 0)
{
decimalNumber = Math.abs(decimalNumber);
bIsNegative = true;
}
var fReturn = 0.00;
(decimalPlace == null || decimalPlace == '') ? 0 : decimalPlace;
var multiplierDivisor = Math.pow(10, decimalPlace);
fReturn = Math.round((parseFloat(decimalNumber) * multiplierDivisor).toFixed(decimalPlace)) / multiplierDivisor;
fReturn = (bIsNegative) ? (fReturn * -1) : fReturn;
fReturn = fReturn.toFixed(decimalPlace)
return fReturn;
}
Below are the test sample
And this test sample after addressing the issue for negative values.

What's the most elegant way to cap a number to a segment?

Let's say x, a and b are numbers. I need to limit x to the bounds of the segment [a, b].
In other words, I need a clamp function:
clamp(x) = max( a, min(x, b) )
Can anybody come up with a more readable version of this?
The way you do it is pretty standard. You can define a utility clamp function:
/**
* Returns a number whose value is limited to the given range.
*
* Example: limit the output of this computation to between 0 and 255
* (x * 255).clamp(0, 255)
*
* #param {Number} min The lower boundary of the output range
* #param {Number} max The upper boundary of the output range
* #returns A number in the range [min, max]
* #type Number
*/
Number.prototype.clamp = function(min, max) {
return Math.min(Math.max(this, min), max);
};
(Although extending language built-ins is generally frowned upon)
a less "Math" oriented approach, but should also work, this way, the < / > test is exposed (maybe more understandable than minimaxing) but it really depends on what you mean by "readable"
function clamp(num, min, max) {
return num <= min
? min
: num >= max
? max
: num
}
There's a proposal to add an addition to the built-in Math object to do this:
Math.clamp(x, lower, upper)
But note that as of today, it's a Stage 1 proposal. Until it gets widely supported (which is not guaranteed), you can use a polyfill.
A simple way would be to use
Math.max(min, Math.min(number, max));
and you can obviously define a function that wraps this:
function clamp(number, min, max) {
return Math.max(min, Math.min(number, max));
}
Originally this answer also added the function above to the global Math object, but that's a relic from a bygone era so it has been removed (thanks #Aurelio for the suggestion)
This does not want to be a "just-use-a-library" answer but just in case you're using Lodash you can use .clamp:
_.clamp(yourInput, lowerBound, upperBound);
So that:
_.clamp(22, -10, 10); // => 10
Here is its implementation, taken from Lodash source:
/**
* The base implementation of `_.clamp` which doesn't coerce arguments.
*
* #private
* #param {number} number The number to clamp.
* #param {number} [lower] The lower bound.
* #param {number} upper The upper bound.
* #returns {number} Returns the clamped number.
*/
function baseClamp(number, lower, upper) {
if (number === number) {
if (upper !== undefined) {
number = number <= upper ? number : upper;
}
if (lower !== undefined) {
number = number >= lower ? number : lower;
}
}
return number;
}
Also, it's worth noting that Lodash makes single methods available as standalone modules, so in case you need only this method, you can install it without the rest of the library:
npm i --save lodash.clamp
If you are able to use es6 arrow functions, you could also use a partial application approach:
const clamp = (min, max) => (value) =>
value < min ? min : value > max ? max : value;
clamp(2, 9)(8); // 8
clamp(2, 9)(1); // 2
clamp(2, 9)(10); // 9
or
const clamp2to9 = clamp(2, 9);
clamp2to9(8); // 8
clamp2to9(1); // 2
clamp2to9(10); // 9
If you don’t want to define any function, writing it like Math.min(Math.max(x, a), b) isn’t that bad.
This expands the ternary option into if/else which minified is equivalent to the ternary option but doesn't sacrifice readability.
const clamp = (value, min, max) => {
if (value < min) return min;
if (value > max) return max;
return value;
}
Minifies to 35b (or 43b if using function):
const clamp=(c,a,l)=>c<a?a:c>l?l:c;
Also, depending on what perf tooling or browser you use you get various outcomes of whether the Math based implementation or ternary based implementation is faster. In the case of roughly the same performance, I would opt for readability.
In the spirit of arrow sexiness, you could create a micro
clamp/constrain/gate/&c. function using rest parameters
var clamp = (...v) => v.sort((a,b) => a-b)[1];
Then just pass in three values
clamp(100,-3,someVar);
That is, again, if by sexy, you mean 'short'
My favorite:
[min,x,max].sort()[1]

Javascript: Comparing two float values [duplicate]

This question already has answers here:
Javascript float comparison
(2 answers)
Closed 6 months ago.
I have this JavaScript function:
Contrl.prototype.EvaluateStatement = function(acVal, cfVal) {
var cv = parseFloat(cfVal).toFixed(2);
var av = parseFloat(acVal).toFixed(2);
if( av < cv) // do some thing
}
When i compare float numbers av=7.00 and cv=12.00 the result of 7.00<12.00 is false!
Any ideas why?
toFixed returns a string, and you are comparing the two resulting strings. Lexically, the 1 in 12 comes before the 7 so 12 < 7.
I guess you want to compare something like:
(Math.round(parseFloat(acVal)*100)/100)
which rounds to two decimals
Compare float numbers with precision:
var precision = 0.001;
if (Math.abs(n1 - n2) <= precision) {
// equal
}
else {
// not equal
}
UPD:
Or, if one of the numbers is precise, compare precision with the relative error
var absoluteError = (Math.abs(nApprox - nExact)),
relativeError = absoluteError / nExact;
return (relativeError <= precision);
The Math.fround() function returns the nearest 32-bit single precision float representation of a Number.
And therefore is one of the best choices to compare 2 floats.
if (Math.fround(1.5) < Math.fround(1.6)) {
console.log('yes')
} else {
console.log('no')
}
>>> yes
// More examples:
console.log(Math.fround(0.9) < Math.fround(1)); >>> true
console.log(Math.fround(1.5) < Math.fround(1.6)); >>> true
console.log(Math.fround(0.005) < Math.fround(0.00006)); >>> false
console.log(Math.fround(0.00000000009) < Math.fround(0.0000000000000009)); >>> false
Comparing floats using short notation, also accepts floats as strings and integers:
var floatOne = 2, floatTwo = '1.456';
Math.floor(floatOne*100) > Math.floor(floatTwo*100)
(!) Note: Comparison happens using integers. What actually happens behind the scenes: 200 > 145
Extend 100 with zero's for more decimal precision. For example use 1000 for 3 decimals precision.
Test:
var floatOne = 2, floatTwo = '1.456';
console.log(Math.floor(floatOne*100), '>', Math.floor(floatTwo*100), '=', Math.floor(floatOne*100) > Math.floor(floatTwo*100));
Comparing of float values is tricky due to long "post dot" tail of the float value stored in the memory. The simplest (and in fact the best) way is: to multiply values, for reducing known amount of post dot digits to zero, and then round the value (to rid of the tail).
Obviously both compared values must be multiplied by the same rate.
F.i.: 1,234 * 1000 gives 1234 - which can be compared very easily. 5,67 can be multiplied by 100, as for reducing the float comparing problem in general, but then it couldn't be compared to the first value (1,234 vel 1234). So in this example it need to be multiplied by 1000.
Then the comparition code could look like (in meta code):
var v1 = 1.234;
var v2 = 5.67;
if (Math.round(v1*1000) < Math.round(v2*1000)) ....

Categories

Resources