Сводка
Глобальное свойство NaN
является значением, представляющим не-число (Not-A-Number).
Атрибуты свойства NaN |
|
---|---|
Записываемое | нет |
Перечисляемое | нет |
Настраиваемое | нет |
Интерактивный пример
Описание
NaN
является свойством глобального объекта.
Начальным значением NaN
является Not-A-Number (не-число) — то же самое значение, что и у Number.NaN
. В современных браузерах NaN
является ненастраиваемым и незаписываемым свойством. Даже когда это не так, избегайте его переопределения.
В программах NaN
используется довольно редко. Это возвращаемое значение в ситуациях, когда математические (Math
) функции не срабатывают должным образом (например, при вызове Math.sqrt(-1)
) или когда функция, пытающаяся считать число из строки, терпит неудачу по причине того, что в строке не число (parseInt('blabla')
).
Проверка на равенство NaN
NaN
является неравным (посредством сравнения через ==
, !=
, ===
, and !==
) любому другому значению, включая другое значение NaN. Используйте Number.isNaN()
или isNaN()
, чтобы наиболее понятным образом определить является ли значение значением NaN. Или выполните само-сравнение: NaN, и только NaN, в результате такого сравнения будет неравным самому себе.
NaN === NaN; // false
Number.NaN === NaN; // false
isNaN(NaN); // true
isNaN(Number.NaN); // true
function valueIsNaN(v) { return v !== v; }
valueIsNaN(1); // false
valueIsNaN(NaN); // true
valueIsNaN(Number.NaN); // true
Тем не менее, обратите внимание на разницу между функцией isNaN()
и методом Number.isNaN()
: первая вернёт true
, если значение в настоящий момент является NaN
, или если оно станет NaN
после того, как преобразуется в число, в то время как последний вернёт true
, только если текущим значением является NaN
:
isNaN('hello world'); // true
Number.isNaN('hello world'); // false
Спецификации
Specification |
---|
ECMAScript Language Specification # sec-value-properties-of-the-global-object-nan |
Совместимость с браузерами
BCD tables only load in the browser
Смотрите также
NaN
Глобальное свойство NaN
— это значение, представляющее Not-A-Number.
Атрибуты свойства NaN
|
|
---|---|
Writable | no |
Enumerable | no |
Configurable | no |
Try it
Description
NaN
— это свойство глобального объекта . Другими словами, это переменная в глобальной области видимости.
Начальное значение NaN
равно Not-A-Number — то же, что и значение Number.NaN
. В современных браузерах NaN
является ненастраиваемым и недоступным для записи свойством. Даже если это не так, избегайте переопределения. NaN
в программе довольно редко .
Существует пять различных типов операций, возвращающих NaN
:
- Число не может быть проанализировано (например,
parseInt("blabla")
илиNumber(undefined)
) - Математическая операция, результат которой не является действительным числом (например,
Math.sqrt(-1)
) - Операнд аргумента —
NaN
(например,7 ** NaN
) - Неопределенная форма (например,
0 * Infinity
илиundefined + undefined
) - Любая операция, которая включает строку и не является операцией сложения (например,
"foo" / 3
)
Examples
Тестирование против NaN
NaN
сравнивает unequal (через ==
, !=
, ===
и !==
) с любым другим значением, в том числе с другим значением NaN
. Используйте Number.isNaN()
или isNaN()
, чтобы наиболее четко определить, является ли значение NaN
. Или выполните самосравнение: NaN
и только NaN
будут сравниваться неравно самому себе.
NaN === NaN; Number.NaN === NaN; isNaN(NaN); isNaN(Number.NaN); Number.isNaN(NaN); function valueIsNaN(v) { return v !== v; } valueIsNaN(1); valueIsNaN(NaN); valueIsNaN(Number.NaN);
Однако обратите внимание на разницу между isNaN()
и Number.isNaN()
: первый вернет true
если значение в настоящее время равно NaN
, или если оно будет NaN
после приведения его к числу, а последнее вернет true
только если значение в настоящее время NaN
:
isNaN('hello world'); Number.isNaN('hello world');
По той же причине использование значения bigint
вызовет ошибку с isNaN()
, а не с Number.isNaN()
:
isNaN(1n); Number.isNaN(1n);
Кроме того, некоторые методы массива не могут найти NaN
, а другие -.
const arr = [2, 4, NaN, 12]; arr.indexOf(NaN); arr.includes(NaN); arr.findIndex((n) => Number.isNaN(n));
Specifications
Browser compatibility
Desktop | Mobile | Server | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Chrome | Edge | Firefox | Internet Explorer | Opera | Safari | WebView Android | Chrome Android | Firefox для Android | Opera Android | Safari на IOS | Samsung Internet | Deno | Node.js | |
NaN |
1 |
12 |
1 |
4 |
4 |
1 |
4.4 |
18 |
4 |
10.1 |
1 |
1.0 |
1.0 |
0.10.0 |
See also
Number.NaN
Number.isNaN()
isNaN()
JavaScript
-
Math.tanh()
Функция Math.tanh()возвращает гиперболический тангенс числа,то есть tanh x sinh cosh e 2 1 frac{sinh x}{cosh {e^x frac{e^{2x}1}{e^{2x}+1}Число.
-
Math.trunc()
Функция Math.trunc()возвращает целую часть числа,удаляя все дробные цифры.
-
Number
Number-это примитивный объект-обертка,используемый для представления и манипулирования числами,такими как 37 -9.25.
-
Number.EPSILON
Свойство Number.EPSILON представляет разницу между 1 и наименьшим значением с плавающей точкой больше чем Вы не должны создавать объект Number для доступа к этому свойству.
NaN
is a global property that represents the value of Not-A-Number, hence the name. It is possible to get the value NaN
returned when doing an arithmetic operation or coercing some value to a number. Here are some operations that result in NaN
0 / 0; // NaN
Infinity / Infinity; // NaN
1 / undefined; // NaN
undefined / 1; // NaN
// [almost] all arithmetic operation involving NaN
NaN + 1; // NaN
NaN - 1; // NaN
NaN * 1; // NaN
NaN / 1; // NaN
NaN ** 1; // NaN
NaN % 1; // NaN
// with the exception of
NaN ** 0; // 1
// Finally, coercing any value that does not have a numeric value
parseInt('hi', 10); // NaN
parseFloat(undefined); // NaN
+"hi"; // NaN
Number({}); // NaN
"hi" - 1; // NaN
"hi" * 1; // NaN
"hi" / 1; // NaN
"hi" % 1; // NaN
"hi" ** 1; // NaN
Enter fullscreen mode
Exit fullscreen mode
it is worth mentioning that most of the confusion about NaN
comes from the behavior of coercing a non-numeric-value to a numeric-value which results in NaN
. For this reason, I recommend getting yourself familiarized with the last few examples from the code above and better yet why some values such as booleans, [1]
and ''
do not result in NaN
Interesting facts about NaN
NaN
has a bad reputation for being tricky, however, if you familiarize yourself with the following few facts you will be able to work with NaN
with no issue.
NaN
unlike it’s name is actually from the type Number
typeof NaN; // 'number'
Enter fullscreen mode
Exit fullscreen mode
NaN
Has a falsy value
Boolean(NaN); // false
Enter fullscreen mode
Exit fullscreen mode
NaN
is the only value in JavaScript that does not equal itself. Hint: this will become useful later on.
NaN === NaN; // false
NaN == NaN; // false
NaN !== NaN; // true
// No, it is not pointing to a differnt NaN object (no such thing)
const iAmNaN = NaN;
iAmNaN == iAmNaN; //false
Enter fullscreen mode
Exit fullscreen mode
You can access NaN
in four different ways.
NaN;
this.NaN;
globalThis.NaN;
Number.NaN
Enter fullscreen mode
Exit fullscreen mode
Avoid comparisons with NaN
NaN > 0; // false
NaN >= 0; // false
NaN < 0; // false
Enter fullscreen mode
Exit fullscreen mode
Let’s look at an example
Let’s say we have a function that takes one argument and increments it by 10
. We want to accept both numbers and strings representing a number so we will use parseFloat
const incrementByTen = function(val) {
const n = parseFloat(val, 10);
return n + 10;
};
incrementByTen(0); // 10 ✅
incrementByTen('2.3'); // 12.3 ✅
/*
result of parseFloat will be NaN in examples below
hence the addition operations will also return NaN
*/
incrementByTen(NaN); // NaN ❌
incrementByTen(false); // NaN ❌
incrementByTen({}); // NaN ❌
incrementByTen([]); // NaN ❌
incrementByTen('a'); // NaN ❌
incrementByTen(true); // NaN ❌
incrementByTen(['a', 1]); // NaN ❌
Enter fullscreen mode
Exit fullscreen mode
We just learned there are plenty of arguments which would result in NaN
. Perhaps a better way to handle this is to throw an error for those cases. However, as we learned earlier the usual comparisons will not work for NaN
as we can see below. For this reason, we will use the global function isNaN
.
typeof NaN === NaN; // false
NaN === NaN; // false
Enter fullscreen mode
Exit fullscreen mode
what is isNaN
and how it works?
isNaN
is a global function, takes a single argument and returns a boolean indicating whether or not the argument passed is NaN
. MDN explains isNaN
as such:
The function [
isNaN
] should be interpreted as answering the question, «is this value, when coerced to a numeric value, an IEEE-754 ‘Not A Number’ value?»
We now write our function with isNaN
to throw an error when the result of the parseFloat
is NaN
.
const incrementByTen = function(val) {
const n = parseFloat(val, 10);
if (isNaN(n)) {
throw new Error('Resulted in NaN!');
}
return n + 10;
};
incrementByTen(0); // 10 ✅
incrementByTen('2.3'); // 12.3 ✅
incrementByTen(NaN); // Error: Resulted in NaN! ✅
incrementByTen(false); // Error: Resulted in NaN! ✅
incrementByTen({}); // Error: Resulted in NaN! ✅
incrementByTen([]); // Error: Resulted in NaN! ✅
incrementByTen('a'); // Error: Resulted in NaN! ✅
incrementByTen(true); // Error: Resulted in NaN! ✅
incrementByTen(['a', 1]); // Error: Resulted in NaN! ✅
Enter fullscreen mode
Exit fullscreen mode
Great, our function works as expected. Now let’s learn a bit more about isNaN
. Best way to understand how isNaN
works is to create our own [basic version] polyfill for it. Polyfill is not required to use isNaN
, It is super old…IE 3 old! 👴🏽
const isNaN = function(value) {
// coercing it into a numeric value. BEWARE OF THIS LINE
const n = Number(value);
// now checking to see if it does not equal itself
// only NaN does not equal itself 🤯
return n !== n;
};
Enter fullscreen mode
Exit fullscreen mode
When working with isNaN
you need to beware of the coercion of the value to a numeric-value. Remember some values cannot be coerced to a numeric-value and will result in NaN
so even though your argument to isNaN
might not have been NaN
it could become one.
Here are a few examples where this happens and isNaN
does not work as we perhaps expect it to:
isNaN(NaN); // true ✅
isNaN(undefined); // true ❌
isNaN('a'); // true ❌
isNaN({}); // true ❌
isNaN(['a']); // true ❌
isNaN(10n); // TypeError: Cannot convert a BigInt value to a number ❌
isNaN(Symbol()); // Uncaught TypeError: Cannot convert a Symbol value to a number ❌
Enter fullscreen mode
Exit fullscreen mode
Number.isNaN
to the rescue 🦸🏻♀️
For the reasons that should be clear from above using isNaN
is not ideal. This is why Number.isNaN
has been added to JavaScript starting from ES6. The main difference between the two functions is that Number.isNaN
does not convert its argument to a numeric-value before determining whether it is NaN
.
Number.isNaN(NaN); // true ✅
Number.isNaN(undefined); // false ✅
Number.isNaN('a'); // false ✅
Number.isNaN({}); // false ✅
Number.isNaN(['a']); // false ✅
Number.isNaN(10n); // false ✅
Number.isNaN(Symbol()); // false ✅
Enter fullscreen mode
Exit fullscreen mode
Great, it is working as expected. I recommend to always use Number.isNaN
. Even if you want to coerce the value to a numeric-value do it yourself and then use Number.isNaN
that way you are clearly expressing your intentions.
// Bad
isNaN(someValue);
// Good
Number.isNaN(someValue)
// And if we do need someValue to be coerced to a numeric-value
const numericalValue = +someValue; // or Number(someValue)
Number.isNaN(numericalValue);
Enter fullscreen mode
Exit fullscreen mode
Alternatives to native isNaN
and Number.isNaN
As you can imagine before Number.isNaN
was introduced there were some workarounds for us to handle this which perhaps are no longer needed but worth noting.
Write your own
If you are not going to use Number.isNaN
, this is perhaps the quickest and fastest way to get going. The key to understanding this function is that isNaN
is the only value that does not equal itself.
const _isNaN = function(value) {
return value !== value;
}
Enter fullscreen mode
Exit fullscreen mode
Lodash and Underscore
Both of these popular utility libraries have their own version of the functionality which works similar to Number.isNaN
import lodash from 'lodash';
import underscore from 'underscore';
lodash.isNaN();
underscore.isNaN();
Enter fullscreen mode
Exit fullscreen mode
Resources and citations
-
NaN
- MDN https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN
- ECMAScript Spec https://tc39.es/ecma262/#sec-value-properties-of-the-global-object-nan
-
isNaN
- MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN
- ECMAScript Spec https://tc39.es/ecma262/#sec-isnan-number
- Lodash https://lodash.com/docs/4.17.15#isNaN
- Underscore https://underscorejs.org/#isNaN
-
Number.isNaN
- MDN https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN
- ECMAScript Spec https://tc39.es/ecma262/#sec-number.isnan
- Related topics
- freeCodeCamp: JavaScript type coercion explained https://www.freecodecamp.org/news/js-type-coercion-explained-27ba3d9a2839/
- SitePoint ES6 New Number Methods https://www.sitepoint.com/es6-number-methods/
Числа
Все числа в JavaScript, как целые так и дробные, имеют тип Number
и хранятся в 64-битном формате IEEE-754, также известном как «double precision».
Здесь мы рассмотрим различные тонкости, связанные с работой с числами в JavaScript.
Способы записи
В JavaScript можно записывать числа не только в десятичной, но и в шестнадцатеричной (начинается с 0x
) системе счисления:
alert( 0xFF ); // 255 в шестнадцатиричной системе
Также доступна запись в «научном формате» (ещё говорят «запись с плавающей точкой»), который выглядит как <число>e<количество нулей>
.
Например, 1e3
— это 1
с 3
нулями, то есть 1000
.
// еще пример научной формы: 3 с 5 нулями alert( 3e5 ); // 300000
Если количество нулей отрицательно, то число сдвигается вправо за десятичную точку, так что получается десятичная дробь:
// здесь 3 сдвинуто 5 раз вправо, за десятичную точку. alert( 3e-5 ); // 0.00003 <-- 5 нулей, включая начальный ноль
Деление на ноль, Infinity
Представьте, что вы собираетесь создать новый язык… Люди будут называть его «JavaScript» (или «LiveScript»… неважно).
Что должно происходить при попытке деления на ноль?
Как правило, ошибка в программе… Во всяком случае, в большинстве языков программирования это именно так.
Но создатель JavaScript решил пойти математически правильным путем. Ведь чем меньше делитель, тем больше результат. При делении на очень-очень маленькое число должно получиться очень большое. В математическом анализе это описывается через пределы, и если подразумевать предел, то в качестве результата деления на 0
мы получаем «бесконечность», которая обозначается символом ∞
(в JavaScript Infinity
).
alert( 1 / 0 ); // Infinity alert( 12345 / 0 ); // Infinity
Infinity
— особенное численное значение, которое ведет себя в точности как математическая бесконечность ∞
.
Infinity
больше любого числа.- Добавление к бесконечности не меняет её.
alert( Infinity > 1234567890 ); // true alert( Infinity + 5 == Infinity ); // true
Бесконечность можно присвоить и в явном виде: var x = Infinity
.
Бывает и минус бесконечность -Infinity
:
alert( -1 / 0 ); // -Infinity
Бесконечность можно получить также, если сделать ну очень большое число, для которого количество разрядов в двоичном представлении не помещается в соответствующую часть стандартного 64-битного формата, например:
alert( 1e500 ); // Infinity
NaN
Если математическая операция не может быть совершена, то возвращается специальное значение NaN
(Not-A-Number).
Например, деление 0/0
в математическом смысле неопределено, поэтому его результат NaN
:
Значение NaN
используется для обозначения математической ошибки и обладает следующими свойствами:
-
Значение
NaN
— единственное в своем роде, которое не равно ничему, включая себя.Следующий код ничего не выведет:
if (NaN == NaN) alert( "==" ); // Ни один вызов if (NaN === NaN) alert( "===" ); // не сработает
-
Значение
NaN
можно проверить специальной функциейisNaN(n)
, которая преобразует аргумент к числу и возвращаетtrue
, если получилосьNaN
, иfalse
— для любого другого значения.var n = 0 / 0; alert( isNaN(n) ); // true alert( isNaN("12") ); // false, строка преобразовалась к обычному числу 12
-
Значение
NaN
«прилипчиво». Любая операция сNaN
возвращаетNaN
.
Если аргумент isNaN
— не число, то он автоматически преобразуется к числу.
««smart header=»Забавный способ проверки на NaN
«
Отсюда вытекает забавный способ проверки значения на NaN
: можно проверить значение на равенство самому себе, если не равно — то NaN
:
var n = 0 / 0; if (n !== n) alert( 'n = NaN!' );
Это работает, но для наглядности лучше использовать isNaN(n)
.
```smart header="Математические операции в JS безопасны"
Никакие математические операции в JavaScript не могут привести к ошибке или "обрушить" программу.
В худшем случае результат будет `NaN`.
```
## isFinite(n)
Итак, в JavaScript есть обычные числа и три специальных числовых значения: `NaN`, `Infinity` и `-Infinity`.
Тот факт, что они, хоть и особые, но числа, демонстрируется работой оператора `+`:
```js run
var value = prompt("Введите Infinity", 'Infinity');
*!*
var number = +value;
*/!*
alert( number ); // Infinity, плюс преобразовал строку "Infinity" к такому "числу"
```
Обычно если мы хотим от посетителя получить число, то `Infinity` или `NaN` нам не подходят. Для того чтобы отличить "обычные" числа от таких специальных значений, существует функция `isFinite`.
**Функция `isFinite(n)` преобразует аргумент к числу и возвращает `true`, если это не `NaN/Infinity/-Infinity`:**
```js run
alert( isFinite(1) ); // true
alert( isFinite(Infinity) ); // false
alert( isFinite(NaN) ); // false
```
## Преобразование к числу
Большинство арифметических операций и математических функций преобразуют значение в число автоматически.
Для того чтобы сделать это явно, обычно перед значением ставят унарный плюс `'+'`:
```js run
var s = "12.34";
alert( +s ); // 12.34
```
При этом, если строка не является в точности числом, то результат будет `NaN`:
```js run
alert( +"12test" ); // NaN
```
Единственное исключение -- пробельные символы в начале и в конце строки, которые игнорируются:
```js run
alert( +" -12" ); // -12
alert( +" n34 n" ); // 34, перевод строки n является пробельным символом
alert( +"" ); // 0, пустая строка становится нулем
alert( +"1 2" ); // NaN, пробел посередине числа - ошибка
```
Аналогичным образом происходит преобразование и в других математических операторах и функциях:
```js run
alert( '12.34' / "-2" ); // -6.17
```
## Мягкое преобразование: parseInt и parseFloat
В мире HTML/CSS многие значения не являются в точности числами. Например метрики CSS: `10pt` или `-12px`.
Оператор `'+'` для таких значений возвратит `NaN`:
```js run
alert(+"12px") // NaN
```
Для удобного чтения таких значений существует функция [parseInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt):
```js run
alert( parseInt('12px') ); // 12
```
**Функция `parseInt` и ее аналог `parseFloat` преобразуют строку символ за символом, пока это возможно.**
При возникновении ошибки возвращается число, которое получилось. Функция `parseInt` читает из строки целое число, а `parseFloat` -- дробное.
```js run
alert( parseInt('12px') ) // 12, ошибка на символе 'p'
alert( parseFloat('12.3.4') ) // 12.3, ошибка на второй точке
```
Конечно, существуют ситуации, когда `parseInt/parseFloat` возвращают `NaN`. Это происходит при ошибке на первом же символе:
```js run
alert( parseInt('a123') ); // NaN
```
Функция `parseInt` также позволяет указать систему счисления, то есть считывать числа, заданные в шестнадцатиричной и других системах счисления:
```js run
alert( parseInt('FF', 16) ); // 255
```
## Проверка на число
Для проверки строки на число можно использовать функцию `isNaN(str)`.
Она преобразует строку в число аналогично `+`, а затем вернёт `true`, если это `NaN`, то есть если преобразование не удалось:
```js run
var x = prompt("Введите значение", "-11.5");
if (isNaN(x)) {
alert( "Строка преобразовалась в NaN. Не число" );
} else {
alert( "Число" );
}
```
Однако, у такой проверки есть две особенности:
1. Пустая строка и строка из пробельных символов преобразуются к `0`, поэтому считаются числами.
2. Если применить такую проверку не к строке, то могут быть сюрпризы, в частности `isNaN` посчитает числами значения `false, true, null`, так как они хотя и не числа, но преобразуются к ним.
```js run
alert( isNaN(null) ); // false - не NaN, т.е. "число"
alert( isNaN("n n") ); // false - не NaN, т.е. "число"
```
Если такое поведение допустимо, то `isNaN` -- приемлемый вариант.
Если же нужна действительно точная проверка на число, которая не считает числом строку из пробелов, логические и специальные значения, а также отсекает `Infinity` -- используйте следующую функцию `isNumeric`:
```js
function isNumeric(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
}
```
Разберёмся, как она работает. Начнём справа.
- Функция `isFinite(n)` преобразует аргумент к числу и возвращает `true`, если это не `Infinity/-Infinity/NaN`.
Таким образом, правая часть отсеет заведомо не-числа, но оставит такие значения как `true/false/null` и пустую строку `''`, так как они корректно преобразуются в числа.
- Для их проверки нужна левая часть. Вызов `parseFloat(true/false/null/'')` вернёт `NaN` для этих значений.
Так устроена функция `parseFloat`: она преобразует аргумент к строке, то есть `true/false/null` становятся `"true"/"false"/"null"`, а затем считывает из неё число, при этом пустая строка даёт `NaN`.
В результате отсеивается всё, кроме строк-чисел и обычных чисел.
## toString(система счисления)
Как показано выше, числа можно записывать не только в 10-ричной, но и в 16-ричной системе. Но бывает и противоположная задача: получить 16-ричное представление числа. Для этого используется метод `toString(основание системы)`, например:
```js run
var n = 255;
alert( n.toString(16) ); // ff
```
В частности, это используют для работы с цветовыми значениями в браузере, вида `#AABBCC`.
Основание может быть любым от `2` до `36`.
- Основание `2` бывает полезно для отладки побитовых операций:
```js run
var n = 4;
alert( n.toString(2) ); // 100
```
- Основание `36` (по количеству букв в английском алфавите -- 26, вместе с цифрами, которых 10) используется для того, чтобы "кодировать" число в виде буквенно-цифровой строки. В этой системе счисления сначала используются цифры, а затем буквы от `a` до `z`:
```js run
var n = 1234567890;
alert( n.toString(36) ); // kf12oi
```
При помощи такого кодирования можно "укоротить" длинный цифровой идентификатор, например чтобы выдать его в качестве URL.
## Округление
Одна из самых частых операций с числом -- округление. В JavaScript существуют целых 3 функции для этого.
`Math.floor`
: Округляет вниз
`Math.ceil`
: Округляет вверх
`Math.round`
: Округляет до ближайшего целого
```js run no-beautify
alert( Math.floor(3.1) ); // 3
alert( Math.ceil(3.1) ); // 4
alert( Math.round(3.1) ); // 3
```
````smart header="Округление битовыми операторами"
[Битовые операторы](/bitwise-operators) делают любое число 32-битным целым, обрезая десятичную часть.
В результате побитовая операция, которая не изменяет число, например, двойное битовое НЕ -- округляет его:
```js run
alert( ~~12.3 ); // 12
```
Любая побитовая операция такого рода подойдет, например XOR (исключающее ИЛИ, `"^"`) с нулем:
```js run
alert( 12.3 ^ 0 ); // 12
alert( 1.2 + 1.3 ^ 0 ); // 2, приоритет ^ меньше, чем +
```
Это удобно в первую очередь тем, что легко читается и не заставляет ставить дополнительные скобки как `Math.floor(...)`:
```js
var x = a * b / c ^ 0; // читается как "a * b / c и округлить"
```
Округление до заданной точности
Для округления до нужной цифры после запятой можно умножить и поделить на 10 с нужным количеством нулей. Например, округлим 3.456
до 2-го знака после запятой:
var n = 3.456; alert( Math.round(n * 100) / 100 ); // 3.456 -> 345.6 -> 346 -> 3.46
Таким образом можно округлять число и вверх и вниз.
num.toFixed(precision)
Существует также специальный метод num.toFixed(precision)
, который округляет число num
до точности precision
и возвращает результат в виде строки:
var n = 12.34; alert( n.toFixed(1) ); // "12.3"
Округление идёт до ближайшего значения, аналогично Math.round
:
var n = 12.36; alert( n.toFixed(1) ); // "12.4"
Итоговая строка, при необходимости, дополняется нулями до нужной точности:
var n = 12.34; alert( n.toFixed(5) ); // "12.34000", добавлены нули до 5 знаков после запятой
Если нам нужно именно число, то мы можем получить его, применив '+'
к результату n.toFixed(..)
:
var n = 12.34; alert( +n.toFixed(5) ); // 12.34
««warn header=»Метод toFixed
не эквивалентен `Math.round`!»
Например, произведём округление до одного знака после запятой с использованием двух способов: `toFixed` и `Math.round` с умножением и делением:
var price = 6.35; alert( price.toFixed(1) ); // 6.3 alert( Math.round(price * 10) / 10 ); // 6.4
Как видно результат разный! Вариант округления через Math.round
получился более корректным, так как по общепринятым правилам 5
округляется вверх. А toFixed
может округлить его как вверх, так и вниз. Почему? Скоро узнаем!
## Неточные вычисления
Запустите этот пример:
```js run
alert( 0.1 + 0.2 == 0.3 );
```
Запустили? Если нет -- все же сделайте это.
Ок, вы запустили его. Он вывел `false`. Результат несколько странный, не так ли? Возможно, ошибка в браузере? Поменяйте браузер, запустите еще раз.
Хорошо, теперь мы можем быть уверены: `0.1 + 0.2` это не `0.3`. Но тогда что же это?
```js run
alert( 0.1 + 0.2 ); // 0.30000000000000004
```
Как видите, произошла небольшая вычислительная ошибка, результат сложения `0.1 + 0.2` немного больше, чем `0.3`.
```js run
alert( 0.1 + 0.2 > 0.3 ); // true
```
Всё дело в том, что в стандарте IEEE 754 на число выделяется ровно 8 байт(=64 бита), не больше и не меньше.
Число `0.1 (одна десятая)` записывается просто в десятичном формате. Но в двоичной системе счисления это бесконечная дробь, так как единица на десять в двоичной системе так просто не делится. Также бесконечной дробью является `0.2 (=2/10)`.
Двоичное значение бесконечных дробей хранится только до определенного знака, поэтому возникает неточность. Её даже можно увидеть:
```js run
alert( 0.1.toFixed(20) ); // 0.10000000000000000555
```
Когда мы складываем `0.1` и `0.2`, то две неточности складываются, получаем незначительную, но всё же ошибку в вычислениях.
Конечно, это не означает, что точные вычисления для таких чисел невозможны. Они возможны. И даже необходимы.
Например, есть два способа сложить `0.1` и `0.2`:
1. Сделать их целыми, сложить, а потом поделить:
```js run
alert( (0.1 * 10 + 0.2 * 10) / 10 ); // 0.3
```
Это работает, так как числа `0.1*10 = 1` и `0.2*10 = 2` могут быть точно представлены в двоичной системе.
2. Сложить, а затем округлить до разумного знака после запятой. Округления до 10-го знака обычно бывает достаточно, чтобы отсечь ошибку вычислений:
```js run
var result = 0.1 + 0.2;
alert( +result.toFixed(10) ); // 0.3
```
````smart header="Забавный пример"
Привет! Я -- число, растущее само по себе!
```js run
alert( 9999999999999999 ); // выведет 10000000000000000
```
Причина та же -- потеря точности.
Из `64` бит, отведённых на число, сами цифры числа занимают до `52` бит, остальные `11` бит хранят позицию десятичной точки и один бит -- знак. Так что если `52` бит не хватает на цифры, то при записи пропадут младшие разряды.
Интерпретатор не выдаст ошибку, но в результате получится "не совсем то число", что мы и видим в примере выше. Как говорится: "как смог, так записал".
Ради справедливости заметим, что ошибка в точности вычислений для чисел с плавающей точкой сохраняется в любом другом языке, где используется формат IEEE 754, включая Java, C, PHP, Ruby, Perl, Python.
Другие математические методы
JavaScript предоставляет базовые тригонометрические и некоторые другие функции для работы с числами.
Тригонометрия
Встроенные функции для тригонометрических вычислений:
Math.acos(x)
: Возвращает арккосинус x
(в радианах)
Math.asin(x)
: Возвращает арксинус x
(в радианах)
Math.atan(x)
: Возвращает арктангенс x
(в радианах)
Math.atan2(y, x)
: Возвращает угол до точки (y, x)
. Описание функции: Atan2.
Math.sin(x)
: Вычисляет синус x
Math.cos(x)
: Вычисляет косинус x
Math.tan(x)
: Возвращает тангенс x
Функции общего назначения
Разные полезные функции:
Math.sqrt(x)
: Возвращает квадратный корень из x
.
Math.log(x)
: Возвращает натуральный (по основанию e
) логарифм x
.
Math.pow(x, exp)
: Возводит число в степень, возвращает xexp
, например Math.pow(2,3) = 8
. Работает в том числе с дробными и отрицательными степенями, например: Math.pow(4, -1/2) = 0.5
.
Math.abs(x)
: Возвращает абсолютное значение числа
Math.exp(x)
: Возвращает ex
, где e
— основание натуральных логарифмов.
Math.max(a, b, c...)
: Возвращает наибольший из списка аргументов
Math.min(a, b, c...)
: Возвращает наименьший из списка аргументов
Math.random()
: Возвращает псевдослучайное число в интервале [0,1) — то есть между 0 (включительно) и 1 (не включая). Генератор случайных чисел инициализуется текущим временем.
Форматирование
Для красивого вывода чисел в стандарте ECMA 402 есть метод toLocaleString()
:
var number = 123456789; alert( number.toLocaleString() ); // 123 456 789
Его поддерживают все современные браузеры, кроме IE10- (для которых нужно подключить библиотеку Intl.JS). Он также умеет форматировать валюту и проценты. Более подробно про устройство этого метода можно будет узнать в статье info:intl, когда это вам понадобится.
Итого
- Числа могут быть записаны в десятеричной, шестнадцатиричной системах, а также «научным» способом.
- В JavaScript существует числовое значение бесконечность
Infinity
. - Ошибка вычислений дает
NaN
. - Арифметические и математические функции преобразуют строку в точности в число, игнорируя начальные и конечные пробелы.
- Функции
parseInt/parseFloat
делают числа из строк, которые начинаются с числа. - Есть четыре способа округления:
Math.floor
,Math.round
,Math.ceil
и битовый оператор. Для округления до нужного знака используйте+n.toFixed(p)
или трюк с умножением и делением на10p
. - Дробные числа дают ошибку вычислений. При необходимости ее можно отсечь округлением до нужного знака.
- Случайные числа от
0
до1
генерируются с помощьюMath.random()
, остальные — преобразованием из них.
Существуют и другие математические функции. Вы можете ознакомиться с ними в справочнике в разделах Number и Math.