логотип PurpleSchool
  • Бесплатно
      Карта развитияОсновы разработкиCSS Flexbox
    • Новостные рассылкиИконка стрелки
    • База знанийИконка стрелки
    • Карьерные пути
      • Frontend React разработчик
      • Frontend Vue разработчик
      • Backend разработчик Node.js
      • Fullstack разработчик React / Node.js
      • Mobile разработчик React Native
      • Backend разработчик Golang
      • Devops инженер
    • О нас
      • Отзывы
      • Реферальная программа
      • О компании
      • Контакты
    • Иконка открытия меню
      • Сообщество
      • PurpleПлюс
      • AI тренажёр
      • Проекты
    логотип PurpleSchool
    ютуб иконка
    Telegram иконка
    VK иконка
    Курсы
    ГлавнаяКаталог курсовFrontendBackendFullstack
    Практика
    КарьераПроектыPurpleПлюс
    Материалы
    БлогБаза знаний
    Документы
    Договор офертаПолитика конфиденциальностиПроверка сертификатаМиграция курсовРеферальная программа
    Реквизиты
    ИП Ларичев Антон АндреевичИНН 773373765379contact@purpleschool.ru

    PurpleSchool © 2020 -2025 Все права защищены

  • Курсы
    Иконка слояПерейти в каталог курсов
    • FrontendИконка стрелки
    • BackendИконка стрелки
    • DevOpsИконка стрелки
    • MobileИконка стрелки
    • ТестированиеИконка стрелки
    • Soft-skillsИконка стрелки
    • ДизайнИконка стрелки
    • Картинка группы Общее

      Общее


      • Основы разработки
      • Основы Git
      • HTML и CSS
      • CSS Flexbox
      • Основы JavaScript
      • Продвинутый JavaScript
      • TypeScript с нуля
      • Neovim
    • Картинка группы React

      React


      • React и Redux Toolkit
      • Zustand
      • Next.js - с нуля
      • Feature-Sliced Design
    • Картинка группы Vue.js

      Vue.js


      • Vue 3 и Pinia
      • Nuxt
      • Feature-Sliced Design
    • Картинка группы Angular

      Angular


      • Angular 19 Иконка курсаСкоро!
    • Картинка группы Node.js

      Node.js


      • Основы Git
      • Основы JavaScript
      • Продвинутый JavaScript
      • Telegraf.js Иконка курсаСкоро!
      • TypeScript с нуля
      • Node.js с нуля
      • Nest.js с нуля
    • Картинка группы Golang

      Golang


      • Основы Git
      • Основы Golang
      • Продвинутый Golang
      • Golang - Templ Fiber HTMX
    • Картинка группы C#

      C#


      • Основы C#
    • Картинка группы PHP

      PHP


      • Основы PHP Иконка курсаСкоро!
    • Картинка группы Python

      Python


      • Основы Python
      • Продвинутый Python
    • Картинка группы Общее

      Общее


      • Основы разработки
      • Docker и Ansible
      • Kubernetes и Helm
      • Микросервисы
      • Neovim
    • Картинка группы Общее

      Общее


      • Основы разработки
      • Основы Git
      • Основы Linux
      • Bash скрипты
      • Docker и Ansible
      • Kubernetes и Helm
      • Микросервисы
      • Neovim
    • Картинка группы Общее

      Общее


      • Основы разработки
      • Основы Git
      • Neovim
    • Картинка группы React Native

      React Native


      • HTML и CSS
      • Основы JavaScript
      • Продвинутый JavaScript
      • TypeScript с нуля
      • React и Redux Toolkit
      • React Native и Expo Router
    • Картинка группы Swift

      Swift


      • Основы Swift и iOS
    • Картинка группы Общее

      Общее


      • Продвинутое тестирование Иконка курсаСкоро!
      • Основы тестирования ПО
    • Картинка группы Общее

      Общее


      • Собеседование
      • Современный Agile
    • Картинка группы Figma

      Figma


      • Основы дизайна
  • логотип PurpleSchool
    • Сообщество
    • PurpleПлюс
    • AI тренажёр
    • Проекты
    Главная
    Сообщество
    Number и BigInt: Насколько точны числовые типы данных в JavaScript.

    Number и BigInt: Насколько точны числовые типы данных в JavaScript.

    Аватар автора Number и BigInt: Насколько точны числовые типы данных в JavaScript.

    Валерий Шестернин

    Иконка календаря23 августа 2023

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

    Number и BigInt

    С момента своего создания в 1995 году, в JavaScript был только один числовой тип данных - Number, который имеет ограничения в пределах 64-битового формата IEEE-754. Это означает, что безопасно доступны целые числа в диапазоне от-(2^53 - 1) до (2^53 - 1) из-за ограничений на хранение позиции точки. Поэтому числа, выходящие за эти границы, будут преобразованы в Infinity или -Infinity. Однако с выходом ES2020 появился новый тип данных - BigInt, который позволяет работать с целыми числами любой длинны. Для создания значения с таким типом достаточно добавить n в конце числа при вводе вручную или передать нужное значение в функцию BigInt.

    console.log(10 ** 1000); //Infinity
    console.log(10n ** 1000n); //выведет все значение огромным числом
    

    BigInt во многих ситуациях ведет себя как Number, например с большинством математических операторов, а так же при преобразовании в Boolean, использовании логических операторов ||, && , ! и при проверке условий. Но не может его полностью заменить т.к. имеет ряд ограничений:

    • Оператор деления округляет результат в меньшую сторону до целого потому что BigInt представляет только целые числа.
    • BigInt нельзя смешивать в одних выражениях с Number, для подобных операций следует приводить значения к одному типу данных, но не стоит забывать, что при приведении Number к BigInt потеряется вся дробная часть, а при приведении BigInt к Number - точность и обход ограничения максимального значения.
    • Унарный плюс не подойдет для приведения BigInt к Number поэтому следует использовать глобальный объект Number.
    • Строгое сравнение “одинаковых” значений этих двух типов данных вернет false (1n === 1 //false), при этом другие операторы сравнения будут работать как обычно вне зависимости от того, какими типами данных представлены числа, как и метод .sort массивов, элементы которых являются любым из числовых типов.
    • Для использования объекта Math BigInt так же придется приводить к Number.
    • Если вы попытаетесь использовать функцию JSON.stringify() на значении типа BigInt, то столкнетесь с ошибкой TypeError. Это происходит потому что по умолчанию значения BigInt не могут быть правильно преобразованы в формат JSON.
    console.log(3n / 2n); //1n
    //результат округлен с 1,5 до целого 1
    console.log(3n / 2); //TypeError: Cannot mix BigInt and other types
    console.log(BigInt(1.5));
    //RangeError: The number 1.5 cannot be converted to a BigInt because it is not an integer
    console.log(BigInt(Math.round(1.5))); //2n
    //для преобразования Number в BigInt придется округлять значение
    console.log(+2n); //TypeError: Cannot convert a BigInt value to a number
    console.log(Number(2n)); //2
    //Для конвертации BigInt в Number нужно использовать глобальный объект Number
    console.log(JSON.stringify(2n)); //TypeError: Do not know how to serialize a BigInt
    

    Неточности при вычислениях в JavaScript

    BigInt призван не только снять ограничение по размеру положительных и отрицательных числе в JavaScript, но и решить проблему неточности при работе с большими числами. Как мы уже знаем, JavaScript хранит Number в 64-битном формате IEEE-754. Из этих 64 бит один хранит знак числа, 11 - позицию десятичной дроби и оставшиеся 52 - само число и если число занимает больше 52 бит - часть информации будет утрачена. BigInt предотвращает такую потерю.

    console.log(9999999999999999);
    //выведет 10000000000000000
    console.log(9999999999999999n);
    //выведет 9999999999999999n
    

    Однако BigInt подходит только для целых чисел. При работе дробями так же могут возникать неточности вычислений из-за переполнения памяти, отведенной под знаки после запятой. На самом деле такие неточности возникают чаще, чем кажется, но формат IEEE-754 незаметно для нас округляет дробь до ближайшего возможного числа. Видим же мы последствия переполнения 11 бит, в основном при математических операциях с дробями. Тут уже нам самим нужно при написании кода позаботиться о корректности вывода результатов операций с дробями, например округлив этот результат до допустимого знака после запятой с помощью метода .toFixed() .

    console.log((0.1).toFixed(18)); //0.100000000000000006
    //можно увидеть 'отрезаную' стандартом неточность дроби
    const sum = 0.1 + 0.2;
    console.log(sum); //0.30000000000000004
    //христоматийный пример неточности вычислений с плавающей запятой
    console.log(sum.toFixed(1));//0.3
    //а так легко его можно исправить, если нам важен только один знак после запятой
    

    Способы записи чисел в JavaScript

    В JavaScript существует несколько способов записать число с большим количеством знаков так, что бы его было удобно прочесть. Так знак нижнего подчеркивания ( _ ) внутри записи числа не повлияет на его значение, но упростит прочтение, а для очень больших или очень маленьких чисел, с большим количеством знаков знаков после запятой, можно добавить букву “e” и указать после нее количество нулей (положительное для записи целого числа и отрицательное для дроби). Так миллиард можно записать как 1e9, а одну миллиардную долю как 1e-9. Важно помнить что запись через “e” не доступна в BigInt и не защищает от неточности вычислений.

    console.log(1_000_000); //1000000
    console.log(1_000_000n); //1000000n
    console.log(1e23n);//SyntaxError: Invalid or unexpected token
    console.log(0.00000000000000000000001);//1e-23
    
    const myNum = 1e23;
    const myBigInt = 99999999999999991611392n;
    console.log(myBigInt == myNum); //true
    

    Довольно часто встречаются записи значений в виде строки с единицей измерения, например 100px или 20$. Что бы извлечь из такой записи числовое значение можно воспользоваться функциями parseInt() для целых чисел или parseFloat() для дробей. Однако стоит помнить, что обе эти функции “ищут” числовые значения с начала строки и вернут NaN при парсинге строки типа “у Саши было 2 яблока”, проигнорировав цифру 2. Для поиска по подобным строкам лучше использовать регулярные выражения.

    console.log(parseInt("100px")); //100
    console.log(parseFloat("192.168.0.1")); //192.168
    //поиск останавливается после первого нечислового знака
    console.log(parseInt("I am 23 years old")); //NaN
    console.log("I am 23 years old".match(/-?\d+(\.\d+)?/g)); //[ '23' ]
    

    Заключение

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

    Иконка глаза4 002

    Комментарии

    0

    Постройте личный план изучения Основы разработки до уровня Middle — бесплатно!

    Основы разработки — часть карты развития Frontend, Backend, Mobile

    • step100+ шагов развития
    • lessons30 бесплатных лекций
    • lessons300 бонусных рублей на счет

    Бесплатные лекции

    Лучшие курсы по теме

    изображение курса

    Основы Git

    Антон Ларичев
    AI-тренажеры
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.9
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    HTML и CSS

    Антон Ларичев
    AI-тренажеры
    Практика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.9
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    CSS Flexbox

    Антон Ларичев
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.9
    бесплатно
    Подробнее
    Иконка чипа0