Почему toPrecision возвращает строку?

Посмотреть этот код:

function testprecision(){
    var isNotNumber = parseFloat('1.3').toPrecision(6);
    alert(typeof isNotNumber); //=> string
}

Я ожидал числа. Если isNotNumber должно быть действительным числом, решение - преобразование:

alert(typeof parseFloat(isNotNumber)) //=> number

[Edit] спасибо за ваши ответы. Я прихожу к выводу, что термин «точность» - не очень точный термин. Он может представлять общее количество цифр числа или количество цифр дробной части. Большинство людей в Нидерландах (откуда я родом) думают о точности «числа дробных цифр». Метод toPrecision в javascript касается первого представления, поэтому это сбивает с толку. В любом случае, метод позволяет ввести «ложную точность», верно? Для второго значения, которое у нас есть toFixed, то же самое и для этого (возвращает строку, вероятность ложной точности).

В любом случае, сделав изобретение колеса своим главным хобби, я поигрался, чтобы создать объект типа javascript с плавающей запятой, используя знания, которые я здесь собрал. Может быть, это полезно для кого-то, а может быть, у кого-то из вас есть идеи получше?

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;
}

использование / пример:

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

person Community    schedule 02.02.2009    source источник


Ответы (6)


Из документации: «Возвращает строку, представляющую объект Number с указанной точностью».

toPrecision () кажется предназначенным для форматирования вывода, и в этом случае строка является наиболее разумным результатом. Он представляет собой окончательный результат в форме, которая не будет искажена дальнейшими манипуляциями.

Если вы хотите уменьшить точность для расчетов, я обычно умножаю на 10 ^ n, где n - цифры, которые я хочу сохранить, беру из этого целое число, а затем делю еще раз на то же самое. Однако это не идеально: в некоторых ситуациях вы можете вызвать переполнение. Честно говоря, я предпочитаю выполнять более сложные финансовые расчеты на сервере, где у меня есть валюта, двоично-десятичная дробь или аналогичные числовые типы.

person Godeke    schedule 02.02.2009

Предположим, у вас есть число вроде «1,6». Если вы отформатируете его так, чтобы справа было 6 нулей, вы получите «1,600000». Для компьютера это тот же номер, что и 1.6, но для вас и вашего веб-сайта это не то же самое, если все ваши номера имеют разную длину (что, например, может повредить синтаксический анализатор).

Чтобы этого избежать, toPrecision возвращает строку, иначе интерпретатор переформатировал бы число, чтобы оно снова стало «1,6».

person Manuel Ferreria    schedule 02.02.2009

Целью toPrecision является усечение значащих десятичных цифр Number до указанного количества. Но тип данных внутренних представлений Numbers - двоичный IEEE-754 double. Поэтому в большинстве случаев невозможно сохранить точное возвращаемое значение в Number. В результате такой неточности возвращаемое значение будет содержать бесконечное количество десятичных цифр, что сделает toPrecision недействительным.

Поэтому единственное разумное решение этой проблемы - возвращать десятичные цифры. И в настоящее время единственным разумным типом данных JS для десятичных цифр является String.


Вот пример, поясняющий неточность Numbers при использовании для десятичных цифр:

// 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
person Community    schedule 11.12.2010

Потому что это функция форматирования.

person Otávio Décio    schedule 02.02.2009

Вам нужна строка для завершающих нулей. Отображение валюты - хороший пример.

person Nosredna    schedule 02.02.2009

Проблема в использовании toPrecision. Попробуйте без него.

var isNotNumber = parseFloat('1.3');
alert(typeof isNotNumber); //=> number
person Community    schedule 02.02.2009
comment
Я совершенно не понимаю о чем вы! - person KooiInc; 03.02.2009