Крупные числа в Golang

После изучения урока вы сможете:

  • Как сэкономить место вместо нулей используя экспонент;
  • Использование пакета big для крупных чисел;
  • Использование крупных констант и значений литералов.

Программирование построено на компромиссах. Числа с плавающей запятой float хранят значения любого размера, однако их точность временами оставляет желать лучшего. Целые числа integer точны, но их диапазон весьма ограничен. Что же делать, когда нужно использовать крупное, точное число? В данном уроке будут рассмотрены две альтернативы нативным типам float64 и int.

Форум Гоферов

Мы работаем над форумом для программистов на Golang. Очень нужны модераторы которые хотят помочь с ответами для новичков и помочь в развитии Go-сообщества.

Go на Форум

Уроки, статьи и Видео

Мы публикуем в паблике ВК и Telegram качественные обучающие материалы для быстрого изучения Go. Подпишитесь на нас в ВК и в Telegram. Поддержите сообщество Go программистов.

Go в ВК Go в Telegram

Содержание статьи

Центральный процессор CPU оптимизирован для математических операций с целыми и вещественными числами, однако другие цифровые представления также возможны. Go может работать и с крупными значениями. В каких случаях целое число слишком мало, вещественное недостаточно точное, и какой-то другой цифровой тип будет более предпочтителен?

Работа с крупными числовыми значениями в Go

Это может быть очевидным не сразу, но 64-битные целые числа невообразимо огромны — намного больше, чем 32-битные.

Для сравнения, ближайшая к нам звезда Альфа Центавра находится на расстоянии 41.3 триллионов километров. Триллион записывается как единица с 12 нулями, или 1012. Неудобно каждый раз набирать такое количество нулей, поэтому в Go числа подобного рода можно записывать с экспонентой, как показано в примере:

int32 или uint32 не может работать с таким крупным значением, однако int64 справится без труда. Теперь мы можем рассчитать нужное значение. К примеру, сколько дней потребуется для полета до Альфа Центавры. Решение представлено ниже:

Какими бы крупными не были 64-битные целые числа, всегда есть кое-что намного больше — космос. Галактика Андромеды находится на расстоянии 24 квинтиллионов (1018) километров от нас. Даже самые крупные неподписанные целые числа (uint64) могут содержать значения до 18 квинтиллионов. При попытке объявить переменную, превышающую 18 квинтиллионов выйдет ошибка:

Паниковать не стоит — у вас несколько вариантов. Можно задействовать математику чисел с плавающей запятой. Это неплохая идея, тем более, что нам уже известно, как такие числа работают. Есть и другой способ. В следующей части рассмотрим один из пакетов Go — big.

На заметку: Если тип переменной не уточняется, Go отнесет числа с экспонентой к типу float64.

Задание для проверки:

Расстояние от Земли до Марса варьируется от 56 000 000 км до 401 000 000 км. Представьте эти два значения в виде целых числе с помощью синтаксиса экспоненты (е).

Пакет big для крупных чисел в Golang

Пакет big предоставляет три типа данных:

  • big.Int для крупных целых чисел, когда 18 квинтиллионов недостаточно;
  • big.Float для вещественных чисел с плавающей запятой производной точности;
  • big.Rat для дробей вроде 1/3.

На заметку: Код Go также может назначать новые типы данных. Мы поговорим об этом в одном из следующих уроков.

Тип big.Int может свободно хранить и оперировать таким крупным значением, как расстояние до галактики Андромеды, то есть около 24 квинтиллионов км.

Задействование big.Int требует, чтобы оно использовалось для всех чисел в уравнении, даже если определенные константы использовались ранее. Функция NewInt принимает значение int64 и возвращает big.Int:

NewInt не поможет числу вроде 24 квинтиллионов. Оно не подойдет для int64, поэтому вместо  этого можно создать big.Int из строки string:

После создания нового big.Int дадим ему значение в 24 квинтиллиона, вызвав метод SetString. В основе 24 квинтиллионов 10 (десятичное значение), поэтому вторым аргументом будет 10.

Со всеми значениями на местах метод Div осуществляет необходимое деление, так что результат может отображаться как в листинге ниже:

Как видно, данные большие типы более громоздки для работы, нежели нативные типы int и float64. Они также медленнее. Это компромиссы, на которые нужно идти ради точности и представления чисел любого размера.

Вопрос для проверки:

Назовите два способа добиться big.Int для числа 86400.

Константы нестандартного размера в Golang

Константы, как и переменные, могут объявляться с указанием типа. И, также как и переменные, константы типа uint64 не могут содержать числа вроде 24 квинтиллионов:

При объявлении константы без указания типа происходит нечто интересное. Переменным Go автоматически назначает тип, в случае с 24 квинтиллионами это будет переполненный тип int. С константами все несколько иначе. Вместо автоматического назначения типа, константы могут стать нетипизированными. Следующая строка не выводит никаких ошибок переполнения:

Константы объявляются с помощью ключевого слова const, однако каждое значение литерала в программе также является константой. Это значит, что числа нестандартного размера могут использоваться напрямую, как показано далее:

Вычисления над константами и литералами осуществляются во время компиляции, а не во время работы программы. Компилятор Go написан на Go. Нетипированные цифровые константы поддерживаются пакетом big, позволяя использовать все обычные операции с числами, значение которых 18 квинтиллионов, как показано в коде ниже:

Значения констант могут присваиваться переменным, пока размер позволяет. int не может вместить 24 квинтиллиона, но 926 568 346 поместится без проблем:

Существует предостережение для констант необычного размера. Хотя компилятор Go использует пакет big для нетипизированных числовых констант, константы и значения big.Int не являются взаимозаменяемыми. В листинге 2 показано значение big.Int, что содержит 24 квинтиллиона, но вы не можете отобразить distance из-за ошибки переполнения:

Очень крупные константы определенно полезны, но они не заменят пакет big.

Вопрос для проверки:

Когда проводятся вычисления над константами и литералами?

Заключение

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

Итоговое задание для проверки:

Карликовая галактика в Большом Псе является ближайшей известной к Земле галактикой, что находится на расстоянии 236 000 000 000 000 000 км от нашего Солнца. Используйте константы для конвертации данного расстояния в световые годы.

Понравилась статья?

Поддержи наш проект, чтобы мы могли создать больше хорошего контента!