Big Int в Go: работа с большими числами
Иногда нам нужно выполнять математические операции, которые включают в себя очень большие целочисленные вычисления, выходящие за пределы всех доступных примитивных типов данных. Например, факториал 100 содержит 158 цифр, поэтому мы не можем сохранить его ни в одном доступном примитивном типе данных. Golang не проверяет переполнение неявно, поэтому это может привести к неожиданным результатам, если в int64 хранится число, превышающее 64 бита.
Для решения этой проблемы Go предоставляет пакет «big», который реализует арифметику произвольной точности (большие числа).
Описание
Поддерживаются следующие числовые типы:
Int signed integers
Rat rational numbers
Float floating-point numbers
Нулевое значение для Int, Rat или Float соответствует 0. Таким образом, новые значения могут быть объявлены обычными способами и обозначать 0 без дальнейшей инициализации:
var x Int // &x is an *Int of value 0
var r = &Rat{} // r is a *Rat of value 0
y := new(Float) // y is a *Float of value 0
Фабричные функции
В качестве альтернативы новые значения могут быть выделены и инициализированы с помощью фабричных функций формы:
func NewT(v V) *T
Например, NewInt(x)
возвращает *Int
, установленный в значение аргумента x int64, NewRat(a, b)
возвращает *Rat, установленный в дроби a/b, где a и b - значения int64, а NewFloat(f)
возвращает *Float
, инициализированный аргументом f float64. Большая гибкость обеспечивается явными сеттерами, например:
var z1 Int
z1.SetUint64(123) // z1 := 123
z2 := new(Rat).SetFloat64(1.25) // z2 := 5/4
z3 := new(Float).SetInt(z1) // z3 := 123.0
Использование: число Фибоначчи
Теперь давайте рассмотрим пример.
В этом примере показано, как использовать big.Int для вычисления наименьшего числа Фибоначчи со 100 десятичными знаками и для проверки того, является ли оно простым. Это дает обзор использования большого пакета.
Преобразование в другие типы и обратно
Другая трудность, с которой я сталкиваюсь при работе с пакетом big
- это преобразование типов. Преобразование типов - это то, что мы делаем регулярно, когда пишем код для разработки приложений.
Данные, доступные нам для использования в качестве входных данных для пакета big, часто являются примитивными типами данных. Самый простой способ - передать эти данные в строковом формате, обычно как свойства некоторого объекта JSON. Вот несколько примеров преобразования значений в и из big.Int
.
Преобразование из int
Преобразовать int
в big.Int
просто, но вы обязательно должны передать int64
, например:
newBigInt := big.newInt(int64(someInt))
Преобразование в int
Чтобы преобразовать большое целое число в uint64, запустите этот код:
var smallnum, _ = new(big.Int).SetString("2188824200011112223", 10)
num := smallnum.Uint64()
Обратите внимание, что Go не выполняет проверку границ - если значение большого целого не помещается в uint64, вы не получите никакого предупреждения, а num будет переполняться и содержать неправильное значение.
Преобразование из строки
Предполагая, что вы храните большое целое число как string
, вы создаете big.Int
следующим образом:
var bignum, ok = new(big.Int).SetString("218882428714186575617", 0)
Если передаваемая строка в setString()
начинается с «0x», будет использоваться основание 16 (шестнадцатеричное). Если строка начинается с «0», будет использоваться восьмеричная система счисления. В противном случае будет использоваться основание 10 (десятичное). Также можно указать базу вручную (до 62). Возвращаемое значение имеет тип *big.Int
. Если Go не удается создать big.Int, для ok устанавливается значение false.
Преобразование в строку
Преобразование в строку позволяет сериализовать данные как JSON, выводить на консоль и т.д., поэтому это очень полезно.
Чтобы преобразовать big.Int
к string
в шестнадцатеричном виде, используйте:
str1 := prime1.Text(16) // or: str1 := fmt.Sprintf("0x%x", bigInt)
Чтобы преобразовать в десятичную систему счисления, используйте:
str1 := prime1.Text(10) // fmt.Sprintf("%v", bigInt)