Рациональные, комплексные и произвольная точность

Julia из коробки умеет точные дроби, комплексные числа и арифметику любой разрядности.

Богатая числовая система — встроенная поддержка рациональных, комплексных и сверхбольших чисел без сторонних библиотек.

Здесь Julia заметно опережает Python: то, для чего в Python нужны модули fractions, cmath или decimal, в Julia встроено в язык и работает быстро.

Рациональные числа

Дробь записывается двойной косой чертой //. Julia хранит её точно как пару «числитель/знаменатель» и автоматически сокращает:

r = 3//4
s = 1//6
sum = r + s
println(sum)
println(numerator(sum), " / ", denominator(sum))

Вывод:

11//12
11 / 12

Никаких ошибок округления: 1//3 + 1//3 + 1//3 точно равно 1//1, тогда как 0.1 + 0.2 в Float уже не точно 0.3.

Комплексные числа

Мнимая единица записывается как im. Комплексные числа — полноценная часть языка:

z = 2 + 3im
println(z * (1 - 1im))
println(abs(z))      # модуль
println(real(z), " ", imag(z))

Вывод:

5 + 1im
3.605551275463989
2 3

Работают и функции из математики комплексных чисел: sqrt(-1 + 0im) вернёт 0.0 + 1.0im, а не ошибку.

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

Когда Int64 или Float64 не хватает диапазона, используют BigInt и BigFloat. Чтобы число стало большим, оберните его в big():

f = factorial(big(30))
println(f)

Вывод:

265252859812191058636308480000000

Сравните: factorial(30) с обычным Int64 переполнится и даст бессмысленный результат, а factorial(big(30)) вычислит точное значение.

Преобразование типов

Между числовыми типами есть явные и неявные преобразования. Функции Int, Float64, BigInt приводят значение к нужному типу:

println(Float64(3//4))   # 0.75
println(Int(round(3.7))) # 4

Вывод:

0.75
4

Как работает под капотом

Рациональные и комплексные числа в Julia — это параметрические типы: Rational{Int64} и Complex{Float64}. То есть «дробь из целых» и «комплексное из дробных» — разные конкретные типы, но с общим шаблоном. Эта система типов (её мы разберём отдельно) позволяет компилятору генерировать быстрый специализированный код для каждой комбинации. BigInt и BigFloat опираются на библиотеки GMP и MPFR, поэтому они медленнее машинных типов — используйте их только там, где точность реально нужна.

Частые ошибки

Главная ошибка — оборачивать в big() уже переполнившийся результат. Если написать big(factorial(30)), то factorial(30) сначала переполнится в Int64, и только потом «испорченное» значение станет BigInt. Правильно оборачивать аргумент: factorial(big(30)), чтобы все вычисления шли в большой арифметике.

Итоги

  • Рациональные числа (3//4) хранятся точно, без округления.
  • Комплексные числа встроены: мнимая единица — im.
  • BigInt/BigFloat дают произвольную точность; оборачивайте в big() исходные аргументы.
  • Рациональные и комплексные — параметрические типы, что обеспечивает скорость.
Проверьте себя
1. Как в Julia записать рациональное число «три четверти»?
A3/4
B3//4
C3:4
DRational(3,4) и только так
2. Почему правильно писать factorial(big(30)), а не big(factorial(30))?
AТак короче
BЧтобы вычисления шли в большой арифметике с самого начала и не было переполнения Int64
CРазницы нет
Dbig работает только с аргументами функций