Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Инкремент числа с плавающей точкой (https://javascript.ru/forum/misc/32420-inkrement-chisla-s-plavayushhejj-tochkojj.html)

antonM 16.10.2012 03:23

Инкремент числа с плавающей точкой
 
Объясните странное поведение операций с числами с плавающей точкой.
Мне надо в цикле производить увеличение целой части исходного числа на 1. Если, например, число от 11 до 15, то десятичная часть через определенный шаг цикла стает больше исходной. Пример:
var numsList = [];
var num = 12.001;
    
    for (var i = 0; i <= 5; i++) {
      numsList.push(num++);
    }
alert(numsList);

В пример, числа нормально увеличиваются до 15.001, затем получаем 16.000999999999998 и т.д.
Надо чтобы десятичная часть оставалась постоянной. Можно ли как-то решить проблему?

Aetae 16.10.2012 03:38

Округлять до нужного знака, без вариантов.

antonM 16.10.2012 04:29

Спасибо большое за пример реализации!
Я так понимаю это особенность вычислительного движка JS.
А такой вариант имеет право на жизнь?:
var numsList = [];
var num = 12.001;
var digits = /(?:\.)(\d+)/.exec(num);
    for (var i = 0; i <= 5; i++) {
      if (digits === null) {
        numsList.push(num++);
      } else {
        numsList.push((num++).toFixed(digits[1].length) * 1);
      }
    }
alert(numsList);
alert(typeof numsList[5]);

Aetae 16.10.2012 04:45

Дзен-трансгуманист, чего-то я не особо вдупляю - накой такие сложности в твоей функции?

(function(a){
    window.alert = function(){
        a(Array.prototype.slice.call(arguments).join('\n'))
    }
}(window.alert))

function maxFraction (value, digits) {
 
  var fixed = (+value).toFixed(digits);
  var i = fixed.length - 1;
 
  loop: while (true) {
 
    switch (fixed.charAt(i)) {
 
    case "0": i--; continue;
    case ".": i--; break loop;
    }
 
    break;
  }
 
  return fixed.slice(0, i+1);
}

Number.prototype.round = function(p){ //почему не так?
  return +this.toFixed(p)
}

num = 0.1 + 0.2;

alert(
  num,
  maxFraction(num, 1),
  num.round(1),
  maxFraction(num+99, 1),
  (num+99).round(1),
  maxFraction(num, 0),
  num.round(),
  maxFraction(num, 5),
  num.round(5)
)

antonM 16.10.2012 05:01

В моей задаче есть два условия:
1. количество десятичных знаков наперед неизвестно (количество должно извлекаться из исходного числа)
2. должно возвращаться число (не строка)

Aetae 16.10.2012 05:06

Цитата:

Сообщение от antonM (Сообщение 210383)
В моей задаче есть два условия:
1. количество десятичных знаков наперед неизвестно
2. должно возвращаться число (не строка)

Печально. Считай кол-во знаков базового числа и по нему округляй.
Xотя, в принципе, погрешность, если вычисления не идут подряд, накапливаться не будет, а потому достаточно округлять до десяти знаков - лишнее отбросится:

(function(a){
    window.alert = function(){
        a(Array.prototype.slice.call(arguments).join('\n'))
    }
}(window.alert))

Number.prototype.round = function(p){ 
  return +this.toFixed(p)
}
num = 0.1 + 0.2;

alert(
  num,
  num.round(10)
)

antonM 16.10.2012 05:12

Спасибо. Вопрос вычислений не стоит. Надо заполнить диапазон ячеек инкрементным набором чисел отталкиваясь от числа в первой ячейке. Соответственно все должно быть красиво без внезапных выскакиваний чисел с умопомрачительным количеством десятичных знаков. Что-то на подобии того, как это делается аутофиллером в Экселе или ООО Кальк.

Maxmaxmахimus 16.10.2012 11:09

сделай тустринг, то что ДО точки преврати в число, инкриментируй, потом сделай тустринг, и вставь до точки в предыдущей строке, потом сделай пфрсфлоат. КЭП

nerv_ 16.10.2012 11:39

Цитата:

Сообщение от antonM
Объясните странное поведение операций с числами с плавающей точкой.

IEEE 754

Цитата:

Сообщение от antonM
Спасибо. Вопрос вычислений не стоит. Надо заполнить диапазон ячеек инкрементным набором чисел отталкиваясь от числа в первой ячейке. Соответственно все должно быть красиво без внезапных выскакиваний чисел с умопомрачительным количеством десятичных знаков. Что-то на подобии того, как это делается аутофиллером в Экселе или ООО Кальк.

не понял, в чем проблема. Уже объяснили как это сделать.

antonM 16.10.2012 14:16

nerv_, за ссылочку спасибо. Вопрос собственно уже решен :)


Часовой пояс GMT +3, время: 07:25.