5

Пытаясь посчитать сумму чисел заметил следующее поведение:
0.7 + 0.2 + 0.1 = 0.99999999...
Почему так происходит понятно из этого ответа.

Что с этим делать, если нужно чтобы ответ получался правильным?
В данном случае: 0.7 + 0.2 + 0.1 = 1
Какие есть решения данной проблемы?

Max
  • 2,340
  • например, округлять при преобразовании числа в строку, используя .toFixed(число_знаков_после_запятой) – diralik Dec 24 '17 at 21:03
  • @diraria а если не знаешь числа? например делаешь калькулятор? Я даже сейчас найду вопрос, где о таком спрашивалось, но ответов там никто не дал .......... https://ru.stackoverflow.com/q/735793/191482 – Алексей Шиманский Dec 24 '17 at 21:06
  • @АлексейШиманский вот неправда, там есть ответ подходящий под условия автора – diralik Dec 24 '17 at 21:13
  • 2
    Используйте что-то вроде этого https://github.com/MikeMcl/big.js/. Я как-то пилил калькулятор и каждое число представлял обычной дробью - там числитель и знаменатель целые. А после всех действий с ними делил числитель на знаменатель и выводил. – selya Dec 24 '17 at 21:13
  • @diraria не правда, там обязательно указывать decimals, что опять же, при вычислениях "на лету" - бесполезно – Алексей Шиманский Dec 24 '17 at 21:14
  • @selya каждое число представлял обычной дробью - там числитель и знаменатель целые - и как, получалось? А то var test = 2/10 + 1/10; console.log(test); выведет ответом 0.30000000000000004 ..... а var test = 7/10 + 2/10 + 1/10; console.log(test); соответственно всё также 0.9999999999999999 – Алексей Шиманский Dec 25 '17 at 06:38
  • @АлексейШиманский А вы меня неправильно поняли. Каждое число - объект, в нем целочисленный числитель и знаменатель. При сложении приводим к общему знаменателю, складываем, сокращаем дробь. И так проделываем все операции, а делим дробь лишь для того, чтобы получить представление в виде десятичной – selya Dec 25 '17 at 06:40
  • @selya просто про "При сложении приводим к общему знаменателю" - не было речи %) – Алексей Шиманский Dec 25 '17 at 06:42
  • @АлексейШиманский Я счел это логичным и очевидным) – selya Dec 25 '17 at 06:43
  • Два варианта.
    1. Округлить полученный ответ.

    либо

    1. Использовать тип BigDecimal.

    Я собаку на этом съел.

    – CuprumBur Dec 25 '17 at 09:31

2 Answers2

4

Ошибку вычисления избежать трудно (много танцев с числами).

Лучше будет округлять после вычисления. причем можно округлять до целых если мы хотим видеть только целое число.

Math.round

Но если мы ожидаем увидеть дробное число этот метод не подойдет нужно использовать округление до до разумного знака после запятой. Округления до 10-го знака обычно бывает достаточно, чтобы отсечь ошибку вычислений и при этом получить нужную точность вычислений:

(0.1 + 0.2).toFixed(10) 

но тут мы получаем тип string нужно доработать с помощью

parseFloat

Резюмируя округление можно делать так:

parseFloat((0.1 + 0.2+0.7).toFixed(10));
  • Неплохой вариант. Наверное в большинстве случаев сработает. Хотя если будет требование иметь возможность большое количество знаков после запятой, то parseFloat((0.2+0.1).toFixed(17)); выдаст 0.30000000000000004 %) ...... но в целом - норм – Алексей Шиманский Dec 25 '17 at 06:35
1

Все числа умножить на 10, округлить и просуммировать. Затем результат разделить на 10:

(Math.round(n1*10) + Math.round(n2*10) + ... + Math.round(nn*10)) / 10
0xdb
  • 51,614
  • Любое всякое можно отсечь.... – Air Dec 25 '17 at 05:15
  • 1
    Не является ответом на вопрос. Чтобы оставить свои замечания или попросить у автора внести уточнения, оставьте комментарий к соответствующему сообщению. - Из очереди проверок – Air Dec 25 '17 at 05:16
  • 1
    если вопрос простой, то и ответ на него очевидно тоже должен быть простым, и если для Вас мой ответ по всей видимости в силу простоты не имеет ценности - для автора вопроса ценность может оказаться ощутимой, так как поможет ему лучше понять среду в которой он программирует )) – Eugene Bartosh Dec 25 '17 at 06:00