Math.round()

Привязка к диапазону

Иногда нужно получить значение х, которое должно находиться в пределах определенного диапазона. Например, нужно значение от 1 до 100, но мы получаем значение 123. Чтобы исправить это, можно использовать min() (возвращает наименьшее из чисел) и max (возвращает максимально допустимое число).

Использование:

var lowBound = 1;
var highBound = 100;
var numInput = 123;
var clamped = Math.max(lowBound, Math.min(numInput, highBound));
console.log(clamped);
> 100;

Можно создать функцию или расширение класса Number:

Number.prototype.clamp = function(min, max) {
  return Math.min(Math.max(this, min), max);
};

Использование:

(numInput).clamp(lowBound, highBound);

Round, RoundDown и RoundUp

Функции Round, RoundDown и RoundUp округляют число до указанного количества знаков после запятой (десятичных разрядов).

  • Функция Round округляет число в большую сторону, если следующая цифра после запятой больше или равна 5. В противном случае число округляется в меньшую сторону.
  • Функция RoundDown всегда округляет число в меньшую сторону — до предыдущего (меньшего) числа, в сторону нуля.
  • Функция RoundUp всегда округляет число в большую сторону — до следующего (большего) числа, в сторону от нуля.

Число десятичных знаков, допускаемых для этих функций:

Число десятичных знаков Описание Пример
Больше 0 Число округляется справа от десятичного разделителя. возвращает 12.4.
Число округляется до ближайшего целого числа. возвращает 12.
Меньше 0 Число округляется слева от десятичного разделителя. возвращает 10.

Правила округления

Коммерческое округление

В Коммерческие туры (не отрицательные числа) выглядит следующим образом :

  • Если число в первом десятичном разряде равно 0, 1, 2, 3 или 4, оно округляется в меньшую сторону.
  • Если число в первом десятичном разряде — 5, 6, 7, 8 или 9, то оно округляется в большую сторону.

Это правило округления описано в стандарте DIN 1333 . Округление часто уже преподается в начальной школе.

Примеры (округление до двух знаков после запятой):

  • 13,3749 … € ≈ 13,37 €
  • 13,3750 … € ≈ 13,38 €

Отрицательные числа в зависимости от их величины округлой формы, на 5 , чтобы сказать от нуля ( Engl : от нуля ):

  • −13,3749 … € ≈ −13,37 €
  • −13,3750 … € ≈ −13,38 €

В Коммерческих турах частично в правовой среде , как гражданские раунды , называемых и г. Б. в о поставщиках государственных услуг пояснил следующее:

Симметричное закругление

Коммерческое и симметричное округление отличаются друг от друга только тем, что число округляется точно посередине между двумя числами с выбранным количеством десятичных цифр.

Симметричные (или геодезическим, математический, искажаются, научный ) округление определяются следующим образом (композиция адаптирована):

  1. Если число в первом десятичном разряде равно 0, 1, 2, 3 или 4, оно округляется в меньшую сторону.
  2. Если число представляет собой 5 (за которыми следуют другие цифры, которые не равны нулю), 6, 7, 8 или 9 в первом десятичном разряде, оно округляется в большую сторону.
  3. Если цифра в первом десятичном разряде, которую следует опустить, представляет собой только 5 (или 5, за которой следуют только нули), она округляется таким образом, чтобы последняя сохраняемая цифра была четной.

Этот тип округления используется в числовой математике , инженерии и технике. Он предусмотрен стандартом IEEE 754 для вычислений с двоичными числами с плавающей запятой в компьютерах. В англоязычной литературе это называется Round to Even или Banker’s Rounding .

Примеры (округление до одного десятичного знака):

  • 2,2499 ≈ 2,2 (по правилу 1)
  • 2,2501 ≈ 2,3 (по правилу 2)
  • 2,2500 ≈ 2,2 (округлено до четного числа согласно правилу 3)
  • 2,3500 ≈ 2,4 (округлено до четного числа согласно правилу 3)

Коммерческое округление приводит к небольшим систематическим ошибкам, так как округление на 0,5 происходит в большую сторону, а в меньшую сторону на 0,5 никогда не происходит; это может немного исказить статистику. Математическое округление всегда округляется в большую или меньшую сторону от точной середины между двумя цифрами до следующей четной цифры. В результате среднее значение округляется вверх и вниз примерно так же часто, по крайней мере, если исходные числа являются стохастическими . (Контрпример: если маленькие числа встречаются чаще, чем большие, их можно систематически округлять в меньшую сторону, чем в большую, см . Закон Бенфорда .)

Округление с сохранением суммы

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

Важными приложениями являются распределение мест в пропорциональном представительстве и распределение всего НДС в счете-фактуре по его отдельным позициям.

Случай, когда все слагаемые положительные, был тщательно исследован, см. Процедуру распределения мест .

Метод Харе-Нимейера может быть обобщен для слагаемых с обоими знаками : вы округляете все числа до ближайших круглых чисел, и пока сумма слишком велика (или слишком мала), вы выбираете одно из округленных (или округленных) чисел. ) нумерует с наибольшим округление (или самое большое количество округления вниз) и изменяет его округления в направлении , противоположном. Это означает, что сумма изменений минимальна .

Функция isNaN

Функция isNaN
предназначена для определения того, является ли аргумент числом или может ли быть преобразован к нему. Если это так, то функция isNaN возвращает false. В противном случае она возвращает true.

IsNaN(NaN); //true
isNaN(«25px»); //true, т.к. 20px — это не число
isNaN(25.5); //false
isNaN(«25.5″); //false
isNaN(» «); //false, т.к. пробел или неcколько пробелов преобразуется к 0
isNaN(null); //false, т.к. значение null преобразуется к 0
isNaN(true); //false, т.к. значение true преобразуется к 1
isNaN(false); //false, т.к. значение false преобразуется к 0

Если это действие нужно выполнить без приведения типа, то используйте метод Number.isNaN
. Данный метод был введён в язык, начиная с ECMAScript 6.

Комментарии

Используйте с соответствующими перегрузками Math.Round , MathF.Round и, Decimal.Round чтобы обеспечить больший контроль над процессом округления.

Существует две общие стратегии округления: округление до ближайшего числа и направление округления, а каждое поле перечисления участвует в точности в одной из этих стратегий.

Округлить до ближайшего

Поля

Операция «цикл-к-ближайшей» принимает исходное число с неявной или заданной точностью; проверяет следующую цифру, которая находится в той же точности, что и единица. и возвращает ближайшее число с той же точностью, что и исходное число. Для положительных чисел, если следующая цифра находится в направлении от 0 до 4, ближайшее число отдается отрицательной бесконечности. Если следующая цифра — от 6 до 9, то ближайшее число будет в сторону положительной бесконечности. Для отрицательных чисел, если следующая цифра находится в направлении от 0 до 4, ближайшее число отдается плюс бесконечности. Если следующая цифра — от 6 до 9, то ближайшее число будет в сторону отрицательной бесконечности.

Если следующая цифра — от 0 до 4 или от 6 до 9, то и не влияет на результат операции округления. Однако если следующая цифра равна 5, то есть середина между двумя возможными результатами, а оставшиеся цифры равны нулю или нет оставшихся цифр, то ближайшее число неоднозначно. В этом случае в режиме «цикл по ближайшему» в можно указать, будет ли операция округления возвращать ближайшее число от нуля или ближайшего четного числа.

В следующей таблице показаны результаты округления некоторых отрицательных и положительных чисел в сочетании с режимами «округление до ближайшего числа». Точность, используемая для округления чисел, равна нулю. Это означает, что число после десятичной запятой влияет на операцию округления. Например, для числа 2,5 цифра после десятичной запятой — 5. Так как эта цифра является средней, можно использовать значение для определения результата округления. Если указан параметр, возвращается значение-3, так как это ближайшее число от нуля до точности, равной нулю. Если указан параметр, возвращается значение-2, так как оно является ближайшим четным числом с точностью до нуля.

Исходный номер AwayFromZero ToEven
3,5 4 4
2.8 3 3
2.5 3 2
2.1 2 2
-2.1 -2 -2
-2.5 –3 -2
-2.8 –3 –3
-3.5 –4 –4

Направленное округление

Поля

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

В следующей таблице показаны результаты округления отрицательных и положительных чисел в сочетании с режимами с направлением округления. Точность, используемая для округления чисел, равна нулю, что означает, что операция округления повлияет на число до десятичной запятой.

Исходный номер тонегативеинфинити топоситивеинфинити тозеро
3.5 3 4 3
2.8 2 3 2
2.5 2 3 2
2.1 2 3 2
-2.1 –3 -2 -2
-2.5 –3 -2 -2
-2.8 –3 -2 -2
-3.5 –4 –3 –3

Методы округления чисел

В JavaScript имеется
встроенный объект Math, предоставляющий различные математические методы.
Здесь мы рассмотрим функции, связанные с округлением чисел. Они следующие:

  • Math.floor – округление в
    меньшую сторону;

  • Math.ceil – округление в
    большую сторону;

  • Math.round – округление до
    ближайшего целого.

Например:

let dig = 1.5;
let res = Math.floor(dig);
console.log( res );       	     // 1
console.log( Math.ceil(dig) );       // 2
console.log( Math.round(1.4) );      // 1
console.log( Math.round(1.5) );      // 2

А что если мы
хотим округлить число до второго знака после запятой (до сотых)? Это можно
сделать, например, так:

let dig = 1.23456;
let res = Math.round(dig*100)100;
 
console.log( res );

Но для такой
операции в JavaScript имеется
встроенный числовой метод toFixed(n), где n – число знаков
после запятой. Наш пример можно переписать так:

console.log( dig.toFixed(2) );

Оператор WorksheetFunction.Round

Если вам необходимо общепринятое математическое округление, используйте встроенную функцию рабочего листа —  WorksheetFunction.Round.

Скопируйте в модуль VBA процедуру с использованием WorksheetFunction.Round и запустите ее выполнение:

1
2
3
4
5
6
7
8
9
10
11

SubTest_2()

Dima1 AsSingle,a2 AsSingle,a3 AsSingle,a4 AsSingle

a1=WorksheetFunction.Round(1.5,)

a2=WorksheetFunction.Round(2.5,)

a3=WorksheetFunction.Round(3.5,)

a4=WorksheetFunction.Round(4.5,)

MsgBox»WorksheetFunction.Round(1.5, 0)=»&a1&vbNewLine&_

«WorksheetFunction.Round(2.5, 0)=»&a2&vbNewLine&_

«WorksheetFunction.Round(3.5, 0)=»&a3&vbNewLine&_

«WorksheetFunction.Round(4.5, 0)=»&a4

EndSub

Результат будет следующий:

Получилось то, что мы и ожидали.

Проверим погрешность:

  1. Сумма исходных чисел: 1.5 + 2.5 + 3.5 +4.5 = 12
  2. Сумма округленных чисел: 2 + 3 + 4 + 5 = 14

Результат очевиден — в данном случае сумма округленных чисел на 2 единицы больше суммы исходных.

Исходя из этого результата, можно сделать вывод, что «банковское» округление с помощью оператора Round дает более точные результаты при массовых операциях с округленными числами. Но в повседневной жизни чаще встречается обычное математическое округление.

Выбирайте округление, которое вам больше подходит для решаемой задачи!

Сравнение чисел

Для сравнения чисел в JavaScript используются следующие операторы: == (равно), != (не равно), > (больше), = (больше или равно),

Например, сравним два числа:

Console.log(2>3); //false
console.log(5>=3); //true

При сравнении чисел с дробной частью необходимо учитывать погрешности, которые могут возникать во время этих вычислений.

Например, в JavaScript сумма чисел (0.2 + 0.4) не равна 0.6:

Console.log((0.2+0.4)==0.6); //false

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

Например, число 0.25 10 в двоичную систему преобразуется точно.

0.125 × 2 = 0.25 | 0
0.25 × 2 = 0.5 | 0
0.5 × 2 = 1 | 1
0.125 10 = 0.001 2

Например, число 0.2 10 можно преобразовать в 2 систему только с определённой точностью:

0.2 × 2 = 0.4 | 0
0.4 × 2 = 0.8 | 0
0.8 × 2 = 1.6 | 1
0.6 × 2 = 1.2 | 1
0.2 × 2 = 0.4 | 0
0.4 × 2 = 0.8 | 0
0.8 × 2 = 1.6 | 1
0.6 × 2 = 1.2 | 1
0.2 × 2 = 0.4 | 0
0.4 × 2 = 0.8 | 0
0.8 × 2 = 1.6 | 1
0.6 × 2 = 1.2 | 1

0.2 10 = 0.001100110011… 2

В результате эти погрешности скажутся при вычисления суммы двух чисел и результатах сравнения. Т.е. получится что на самом деле JavaScript будет видет эту запись следующим образом:

0.6000000000000001==0.6

При вычислениях или отображении чисел с дробной частью необходимо всегда указывать точность, с которой это необходимо делать.

Например, сравнить числа до 2 знаков после запятой используя методы toFixed() и toPrecision() :

//метод toFixed()
console.log((0.2+0.4).toFixed(2)==(0.6).toFixed(2)); //true
//метод toPrecision()
console.log((0.2+0.4).toPrecision(2)==(0.6).toPrecision(2)); //true

Основные математические операции

В JavaScript существуют следующие математические операторы: + (сложение), — (вычитание), * (умножение), / (деление), % (остаток от деления), ++ (увелить значение на 1), — (уменьшить значение на 1).

6+3 //9
6-3 //3
6*3 //18
6/3 //2
6%3 //0, т.е. 6:3=2 => 6-3*2 => ост(0)
5%2 //1, т.е. 5:2=2(.5) => 5-2*2 => ост(1)
7.3%2 //1.3, т.е. 7.3:2=3(.65) => 7.3-2*3 => ост(1.3)
//знак результата операции % равен знаку первого значения
-9%2.5 //-1.5, т.е. 9:2.5=3(.6) => 9-2.5*3 => ост(1.5)
-9%-2.5 //-1.5, т.е. 9:2.5=3(.6) => 9-2.5*3 => ост(1.5)
-2%5 //-2, т.е. 2:5=0(.4) => 2-5*0 => ост(2)
x = 3;
console.log(x++); //выводит 3, у уже потом устанавливает 4
console.log(x); //4
x = 3;
console.log(++x); //устанавливает 4 и выводит
x = 5;
console.log(x—); //выводит 5, у уже потом устанавливает 4
console.log(x); //4
x = 5;
console.log(—x); //устанавливает 4 и выводит
Кроме этого в JavaScript есть комбинированные операторы: x+=y (x=x+y), x-=y (x=x-y), x*=y (x=x*y), x/=y (x=x/y), x%=y (x=x%y).
x = 3;
y = 6;
x+=y;
console.log(x); //9
x = 3;
y = 6;
x-=y;
console.log(x); //-3
x = 3;
y = 6;
x*=y;
console.log(x); //18
x = 3;
y = 6;
x/=y;
console.log(x); //0.5
x = 3;
y = 6;
x%=y;
console.log(x); //3

Demonstrative Implementation

Below is a snippet of code that is functionally equivelent to math.round except that the snippet of code below is slower than Math.round. The purpose of the snippet of code below is to demonstrate how Math.round works.

Function vanilla_round(x) {
var y = Math.abs(x) + 0.5; // so that less than 1/2 rounds down; greater rounds up
return Math.floor(x+0.5)
}

The modulus operator above gets the decimal part of x. Further, the above code snippet could be modified to round to a certain precision on a number:

Function round_to_precision(x, precision) {
var y = +x + (precision === undefined ? 0.5: precision/2);
return y — (y % (precision === undefined ? 1: +precision));
}

Round_to_precision(11, 2); // outputs 12
round_to_precision(11, 3); // outputs 12
round_to_precision(11, 4); // outputs 12
round_to_precision(11, 5); // outputs 10
round_to_precision(11, 6); // outputs 12
round_to_precision(11, 7); // outputs 14
round_to_precision(11, 8); // outputs 8
round_to_precision(3.7, 0.5); // outputs 3.5
round_to_precision(3.75, 0.5); // outputs 4
round_to_precision(3.8, 0.5); // outputs 4

Conclusion

Normally, I would have something witty to say here. Actually, who am
I kidding? My conclusions are usually pretty awful. In fact, nobody even
reads this section. I could write whatever I want and nobody would
notice. Besides, what is there to conclude about rounding numbers?

Got a question or just want to chat? Comment below or drop by our forums (they are actually the same thing!) where a bunch of the friendliest people you’ll ever run into will be happy to help you out!

When Kirupa isn’t busy writing about himself in 3rd person, he is practicing social distancing…even on his , , and LinkedIn profiles.

Hit Subscribe to get cool tips, tricks, selfies, and more personally hand-delivered to your inbox.

Округлить до

MulTEx » 13 Январь 2020 Дмитрий 2507 просмотров

Данная функция является частью надстройки MulTEx

  • Описание, установка, удаление и обновление
  • Полный список команд и функций MulTEx
  • Часто задаваемые вопросы по MulTEx

Вызов команды: MulTEx -группа Ячейки/Диапазоны —Ячейки —Округлить до

Команда округляет все числа в выделенных ячейках до указанного количества десятичных разрядов:

Округлить значения выделенных ячеек до — указывается количество десятичных разрядов, до которого надо округлить число. Например, если в ячейке записано число 45 127,1384. и указано 2, то число будет округлено до двух знаков после запятой, при этом произойдет округление ровно так же, как это делает Excel: 45 127,14. Но есть и другие ситуации — когда округлить надо не просто знаки — а целые числа. К примеру, число 45 127,13 необходимо округлить до тысяч, чтобы получить 45 000. Тогда надо будет указать количество знаков после запятой с минусом: -3. Если число надо просто округлить до целого, то необходимо указать количество знаков после запятой — 0. Диапазон знаков работает от -15 до 15.

Не изменять ячейки с формулами — если установлен, то округление будет производится исключительно для ячеек, не содержащих формулы. Может пригодиться, если на листе перемешаны ячейки с данными, вводимыми вручную и формулами, которые производят вычисления на основании введенных вручную. Тогда можно выделить все ячейки, не задумываясь в каких формулы, а в каких нет, установить флажок Не изменять ячейки с формулами и выполнить команду.

Преобразовывать числа, записанные как текст, в числа — по умолчанию команда игнорирует ячейки, в которых записан текст. При этом если в ячейке записано число, но записано как текст, то команда воспримет его как текст и проигнорирует. Заметка: Что такое число, записанное как текст? Это когда в ячейке отображается число, но по типу данных является текстом. Как правило такие числа помечаются зеленым треугольником в левом верхнем углу ячейки. Формат отображения для таких чисел невозможно изменить напрямую через Формат ячеек, многие функции не учитывают(например СУММ(SUM)).

Если установить флажок Преобразовывать числа, записанные как текст, в числа, то команда Округлить до сама определит такие числа, преобразует их в реальные числа и округлит. Иначе команда будет игнорировать такие числа, считая их текстом.

Так же надо быть осторожным с датами и временем. Т.к. эти данные являются для Excel числовыми, то они так же будут округлены, что может быть нежелательным. Читать подробнее про то, как Excel воспринимает данные >>

Для чего это вообще может быть нужно? Часто при выгрузке документов из других систем и файлов(вроде 1С, файлов CSV, текстовых файлов и т.п.) в Excel числа выгружаются с «хвостами» — 5 и более знаков после запятой: 546 932,78923. Но в ячейке они могут отображаться с округлением — 546 932,79. Как правило это происходит из-за назначенного формата ячеек через Формат ячеек —Число —Числовой —Число десятичных знаков=2:

Это часто приводит к расхождениям расчетов формулами с расчетами на калькуляторе, т.к. на калькуляторе мы суммируем числа с двумя знаками после запятой, а Excel при суммировании формулами учитывает все 5 знаков, т.е. реальное значение числа. Часто в таких ситуациях применяют функции вроде ОКРУГЛ(ROUND), но далеко не всегда это удобно и практично, т.к. формула должна быть записана в другие ячейки. А это приводит к дополнительным неудобствам(создание доп.столбцов, дублирование листов, таблиц и т.п.). С помощью команды Округлить до это можно сделать прямо в этих же ячейках, при этом допускается выделить несколько несмежных ячеек или всю нужную область на листе, вызвать команду и указать нужное количество десятичных разрядов. Так же можно указать, чтобы преобразовывались исключительно ячейки с числами, а ячейки с формулами пропускались. Для этого надо установить флажок Не изменять ячейки с формулами.

Форматирование чисел

В JavaScript отформатировать вывод числа в соответствии с региональными стандартами (языковыми настройками операционной системы) позволяет метод toLocaleString() .

Например, выполним форматирование числа в соответствии с региональными стандартами, которые установлены в системе по умолчанию:

Var number = 345.46;
console.log(number.toLocaleString()); //»345,46″

Например, выполним форматирование числа в соответствии с региональными стандартами России (ru):

Console.log((108.1).toLocaleString(«ru-RU»)); //»108,1″

Данный метод можно также использовать для форматирования числа в виде валюты:

Console.log((2540.125).toLocaleString(«ru-RU»,{style:»currency», currency:»RUB»})); //»2 540,13 ₽»
console.log((89.3).toLocaleString(«ru-RU»,{style:»currency», currency:»USD»})); //»89,30 $»
console.log((2301.99).toLocaleString(«ru-RU»,{style:»currency», currency:»EUR»})); //»2 301,99 €»

Представление числа в виде процентов:

Console.log((0.45).toLocaleString(«ru-RU»,{style:»percent»})); //»45 %»

Разбить число на разряды (свойство useGrouping):

Console.log((125452.32).toLocaleString(«ru-RU»,{useGrouping:true})); //»125 452,32″

Вывести с число с определённым количеством цифр (2) после запятой:

Console.log((1240.4564).toLocaleString(«ru-RU»,{minimumFractionDigits:2, maximumFractionDigits:2})); //»1 240,46″

Примечания

  1.  (недоступная ссылка). Дата обращения: 8 августа 2015.
  2. Кнут Д. Э. Искусство программирования. Том 1. Основные алгоритмы = The Art of Computer Programming. Volume 1. Fundamental Algorithms / под ред. С. Г. Тригуб (гл. 1), Ю. Г. Гордиенко (гл. 2) и И. В. Красикова (разд. 2.5 и 2.6). — 3. — Москва: Вильямс, 2002. — Т. 1. — 720 с. — ISBN 5-8459-0080-8.
  3. A’Hearn, B., J. Baten, D. Crayen (2009). «Quantifying Quantitative Literacy: Age Heaping and the History of Human Capital», Journal of Economic History 69, 783—808.
  4. ↑ . www.metrologie.ru. Дата обращения: 10 августа 2019.
  5. . StudFiles. Дата обращения: 10 августа 2019.
  6. . sv777.ru. Дата обращения: 8 августа 2019.
  7. В. М. Заварыкин, В. Г. Житомирский, М. П. Лапчик. Техника вычислений и алгоритмизация: Вводный курс: Учебное пособие для студентов педагогических институтов по физико-математическим специальностям. — М: Просвещение, 1987. 160 с.: ил.
  8. цит. по В. Гильде, З. Альтрихтер. «С микрокалькулятором в руках». Издание второе. Перевод с немецкого Ю. А. Данилова. М:Мир, 1987, стр. 64.

Функция isFinite

Функция isFinite
позволяет проверить, является ли аргумент конечным числом.

В качестве ответа данная функция возвращает false , если аргумент является Infinity , -Infinity , NaN или будет быть приведён к одному из этих специальных числовых значений. В противном случае данная функция вернёт значение true .

IsFinite(73); // true
isFinite(-1/0); // false
isFinite(Infinity); // false
isFinite(NaN); // false
isFinite(«Текст»); // false

Кроме глобальной функции isFinite
в JavaScript имеется ещё метод Number.isFinite
. Он в отличие от isFinite
не осуществляет принудительное приведения аргумента к числу.

IsFinite(«73»); // true
Number.isFinite(«73»); // false

Неточные вычисления

Внутри JavaScript число представлено в виде 64-битного формата IEEE-754. Для хранения числа используется 64 бита: 52 из них используется для хранения цифр, 11 из них для хранения положения десятичной точки (если число целое, то хранится 0), и один бит отведён на хранение знака.

Если число слишком большое, оно переполнит 64-битное хранилище, JavaScript вернёт бесконечность:

Наиболее часто встречающаяся ошибка при работе с числами в JavaScript – это потеря точности.

Посмотрите на это (неверное!) сравнение:

Да-да, сумма и не равна .

Странно! Что тогда, если не ?

Но почему это происходит?

Число хранится в памяти в бинарной форме, как последовательность бит – единиц и нулей. Но дроби, такие как , , которые выглядят довольно просто в десятичной системе счисления, на самом деле являются бесконечной дробью в двоичной форме.

Другими словами, что такое ? Это единица делённая на десять — , одна десятая. В десятичной системе счисления такие числа легко представимы, по сравнению с одной третьей: , которая становится бесконечной дробью .

Деление на гарантированно хорошо работает в десятичной системе, но деление на – нет. По той же причине и в двоичной системе счисления, деление на обязательно сработает, а становится бесконечной дробью.

В JavaScript нет возможности для хранения точных значений 0.1 или 0.2, используя двоичную систему, точно также, как нет возможности хранить одну третью в десятичной системе счисления.

Числовой формат IEEE-754 решает эту проблему путём округления до ближайшего возможного числа. Правила округления обычно не позволяют нам увидеть эту «крошечную потерю точности», но она существует.

Пример:

И когда мы суммируем 2 числа, их «неточности» тоже суммируются.

Вот почему – это не совсем .

Не только в JavaScript

Справедливости ради заметим, что ошибка в точности вычислений для чисел с плавающей точкой сохраняется в любом другом языке, где используется формат IEEE 754, включая PHP, Java, C, Perl, Ruby.

Можно ли обойти проблему? Конечно, наиболее надёжный способ — это округлить результат используя метод toFixed(n):

Также можно временно умножить число на 100 (или на большее), чтобы привести его к целому, выполнить математические действия, а после разделить обратно. Суммируя целые числа, мы уменьшаем погрешность, но она все равно появляется при финальном делении:

Таким образом, метод умножения/деления уменьшает погрешность, но полностью её не решает.

Забавный пример

Попробуйте выполнить его:

Причина та же – потеря точности. Из 64 бит, отведённых на число, сами цифры числа занимают до 52 бит, остальные 11 бит хранят позицию десятичной точки и один бит – знак. Так что если 52 бит не хватает на цифры, то при записи пропадут младшие разряды.

Интерпретатор не выдаст ошибку, но в результате получится «не совсем то число», что мы и видим в примере выше. Как говорится: «как смог, так записал».

Два нуля

Другим забавным следствием внутреннего представления чисел является наличие двух нулей: и .

Все потому, что знак представлен отдельным битом, так что, любое число может быть положительным и отрицательным, включая нуль.

В большинстве случаев это поведение незаметно, так как операторы в JavaScript воспринимают их одинаковыми.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector