KooiInc
KooiInc

Reputation: 122936

Why does toPrecision return a String?

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

Upvotes: 3

Views: 3792

Answers (6)

user60651
user60651

Reputation:

The problem is the use of toPrecision. Try it without.

var isNotNumber = parseFloat('1.3');
alert(typeof isNotNumber); //=> number

Upvotes: -1

Robert
Robert

Reputation: 2669

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

Upvotes: 6

Godeke
Godeke

Reputation: 16281

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.

Upvotes: 10

Manuel Ferreria
Manuel Ferreria

Reputation: 1232

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.

Upvotes: 10

Nosredna
Nosredna

Reputation: 86226

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

Upvotes: 1

Otávio Décio
Otávio Décio

Reputation: 74290

Because it is a formatting function.

Upvotes: 3

Related Questions