Spec-Zone.ru › Julia 1.5

Целые и вещественные числа

Целые и вещественные значения являются основными строительными блоками арифметики и вычислений. Встроенные представления таких значений называются числовыми примитивами, а представления целых и вещественных чисел как непосредственных значений в коде известны как числовые литералы. Например, 1 является целочисленным литералом, а 1.0 — вещественным литералом; их двоичные представления в памяти как объекты являются числовыми примитивами.

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

Следующие типы являются примитивными числовыми типами Julia:

  • Целочисленные типы:
Тип Целочисленный? Количество битов Наименьшее значение Наибольшее значение
Int8 ✓ 8 -27 27 - 1
UInt8 8 0 28 - 1
Int16 ✓ 16 -215 215 - 1
UInt16 16 0 216 - 1
Int32 ✓ 32 -231 231 - 1
  • Вещественные типы:
Тип Точность Количество битов
Float16 половинная 16

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

Целые числа

... (rest of the document) ...

Напомним, что переменная ans устанавливается в значение последнего выражения, вычисленного в интерактивной сессии. Это не происходит при выполнении кода Julia другими способами.

Также поддерживаются двоичные и восьмеричные литералы:

julia> 0b10
0x02

julia> typeof(ans)
UInt8

julia> 0o010
0x08

julia> typeof(ans)
UInt8

julia> 0x00000000000000001111222233334444
0x00000000000000001111222233334444

julia> typeof(ans)
UInt128

Что касается шестнадцатеричных литералов, двоичные и восьмеричные литералы создают типы беззнаковых целых чисел. Размер двоичного элемента данных — минимальный необходимый размер, если ведущая цифра литерала не 0. В случае ведущих нулей размер определяется минимальным необходимым размером для литерала, имеющего такую же длину, но с ведущей цифрой 1. Это позволяет пользователю управлять размером. Значения, которые не могут быть сохранены в UInt128 , не могут быть записаны как такие литералы.

Двоичные, восьмеричные и шестнадцатеричные литералы могут быть со знаком - , непосредственно предшествующим беззнаковому литералу. Они производят беззнаковое целое число того же размера, что и беззнаковый литерал, с обратным дополнением значения:

julia> -0x2
0xfe

julia> -0x0002
0xfffe

Минимальные и максимальные представимые значения примитивных числовых типов, таких как целые числа, задаются функциями typemin и typemax:

julia> (typemin(Int32), typemax(Int32))
(-2147483648, 2147483647)

julia> for T in [Int8,Int16,Int32,Int64,Int128,UInt8,UInt16,UInt32,UInt64,UInt128]
           println("$(lpad(T,7)): [$(typemin(T)),$(typemax(T))]")
       end
   Int8: [-128,127]
  Int16: [-32768,32767]
  Int32: [-2147483648,2147483647]
  Int64: [-9223372036854775808,9223372036854775807]
 Int128: [-170141183460469231731687303715884105728,170141183460469231731687303715884105727]
  UInt8: [0,255]
 UInt16: [0,65535]
 UInt32: [0,4294967295]
 UInt64: [0,18446744073709551615]
UInt128: [0,340282366920938463463374607431768211455]

Значения, возвращаемые typemin и typemax, всегда относятся к типу указанного аргумента. (Вышеприведенное выражение использует несколько функций, которые ещё не были представлены, включая циклы for, строки и интерполяцию, но должно быть достаточно понятным для пользователей с некоторым опытом программирования.)

Поведение при переполнении

В Julia превышение максимального представимого значения данного типа приводит к поведению с обнулением:

julia> x = typemax(Int64)
9223372036854775807

julia> x + 1
-9223372036854775808

julia> x + 1 == typemin(Int64)
true

Таким образом, арифметика с целыми числами Julia фактически представляет собой вид модульной арифметики. Это отражает характеристики базовой арифметики целых чисел, реализованной на современных компьютерах. В приложениях, где возможно переполнение, важно явно проверять обнуление, вызванное переполнением; в противном случае рекомендуется использовать тип BigInt в разделе Арифметика с произвольной точностью.

Пример поведения при переполнении и способы его потенциального решения приведены ниже:

julia> 10^19
-8446744073709551616

julia> big(10)^19
10000000000000000000

Ошибки при делении

Деление целых чисел (функция div ) имеет два исключительных случая: деление на ноль и деление наименьшего отрицательного числа (typemin) на -1. В обоих случаях возникает исключение DivideError. Функции остатка и модуля (rem и mod) вызывают исключение DivideError, когда их второй аргумент равен нулю.

Числа с плавающей точкой

Литералы чисел с плавающей точкой представлены в стандартных форматах, используя экспоненциальную запись при необходимости:

julia> 1.0
1.0

julia> 1.
1.0

julia> 0.5
0.5

julia> .5
0.5

julia> -1.23
-1.23

julia> 1e10
1.0e10

julia> 2.5e-4
0.00025

Все вышеперечисленные результаты являются значениями типа Float64. Литералы типа Float32 можно ввести, написав f вместо e:

julia> 0.5f0
0.5f0

julia> typeof(ans)
Float32

julia> 2.5f-4
0.00025f0

Значения могут быть легко преобразованы в Float32:

julia> Float32(-1.5)
-1.5f0

julia> typeof(ans)
Float32

Шестнадцатеричные литералы с плавающей запятой также допустимы, но только как значения Float64, с p перед показателем в двоичной системе:

julia> 0x1p0
1.0

julia> 0x1.8p3
12.0

julia> 0x.4p-1
0.125

julia> typeof(ans)
Float64

Также поддерживаются числа с плавающей запятой полуточной точности (Float16), но они реализованы в программном обеспечении и используют Float32 для вычислений.

julia> sizeof(Float16(4.))
2

julia> 2*Float16(4.)
Float16(8.0)

Подчеркивание _ может использоваться в качестве разделителя цифр:

julia> 10_000, 0.000_000_005, 0xdead_beef, 0b1011_0010
(10000, 5.0e-9, 0xdeadbeef, 0xb2)

Нуль с плавающей запятой

Числа с плавающей запятой имеют два нуля, положительный и отрицательный. Они равны друг другу, но имеют разные двоичные представления, как можно увидеть, используя функцию bitstring:

julia> 0.0 == -0.0
true

julia> bitstring(0.0)
"0000000000000000000000000000000000000000000000000000000000000000"

julia> bitstring(-0.0)
"1000000000000000000000000000000000000000000000000000000000000000"

Специальные значения с плавающей запятой

Существует три стандартных значения с плавающей запятой, которые не соответствуют никакой точке на числовой прямой:

Float16 Float32 Float64 Имя Описание
Inf16 Inf32 Inf положительная бесконечность значение, большее всех конечных значений с плавающей запятой
-Inf16 -Inf32 -Inf отрицательная бесконечность значение, меньшее всех конечных значений с плавающей запятой
NaN16 NaN32 NaN не число значение, не == ни одному значению с плавающей запятой (включая само себя)

Для дальнейшего обсуждения того, как эти бесконечные значения с плавающей запятой упорядочены по отношению друг к другу и другим числам с плавающей запятой, см. Числовые сравнения. Согласно стандарту IEEE 754, эти значения с плавающей запятой являются результатами определенных арифметических операций:

julia> 1/Inf
0.0

julia> 1/0
Inf

julia> -5/0
-Inf

julia> 0.000001/0
Inf

julia> 0/0
NaN

julia> 500 + Inf
Inf

julia> 500 - Inf
-Inf

julia> Inf + Inf
Inf

julia> Inf - Inf
NaN

julia> Inf * Inf
Inf

julia> Inf / Inf
NaN

julia> 0 * Inf
NaN

Функции typemin и typemax также применяются к типам с плавающей запятой:

julia> (typemin(Float16),typemax(Float16))
(-Inf16, Inf16)

julia> (typemin(Float32),typemax(Float32))
(-Inf32, Inf32)

julia> (typemin(Float64),typemax(Float64))
(-Inf, Inf)

Машинная эпсилон

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

Julia предоставляет eps, которая дает расстояние между 1.0 и следующим за ним представимым значением с плавающей запятой:

julia> eps(Float32)
1.1920929f-7

julia> eps(Float64)
2.220446049250313e-16

julia> eps() # same as eps(Float64)
2.220446049250313e-16

Эти значения являются 2.0^-23 и 2.0^-52 соответственно как значениями Float32 и Float64. Функция eps также может принимать число с плавающей запятой в качестве аргумента и возвращает абсолютную разницу между этим значением и следующим представимым значением с плавающей запятой. То есть eps(x) возвращает значение того же типа, что и x таким образом, что x + eps(x) является следующим представимым значением с плавающей запятой, большим, чем x:

julia> eps(1.0)
2.220446049250313e-16

julia> eps(1000.)
1.1368683772161603e-13

julia> eps(1e-27)
1.793662034335766e-43

julia> eps(0.0)
5.0e-324

Расстояние между двумя соседними представимыми числами с плавающей запятой не является постоянным, но меньше для меньших значений и больше для больших значений. Другими словами, представимые числа с плавающей запятой плотнее на числовой прямой возле нуля и становятся разреженнее экспоненциально по мере удаления от нуля. По определению, eps(1.0) равно eps(Float64) так как 1.0 - это 64-битное значение с плавающей запятой.

Julia также предоставляет функции nextfloat и prevfloat, которые возвращают следующее большее или меньшее представимое число с плавающей запятой к аргументу соответственно:

julia> x = 1.25f0
1.25f0

julia> nextfloat(x)
1.2500001f0

julia> prevfloat(x)
1.2499999f0

julia> bitstring(prevfloat(x))
"00111111100111111111111111111111"

julia> bitstring(x)
"00111111101000000000000000000000"

julia> bitstring(nextfloat(x))
"00111111101000000000000000000001"

Этот пример подчеркивает общий принцип, что соседние представимые числа с плавающей запятой также имеют соседние двоичные целочисленные представления.

Режимы округления

Если число не имеет точного представления с плавающей запятой, оно должно быть округлено до соответствующего представимого значения. Однако способ выполнения этого округления можно изменить при необходимости в соответствии с режимами округления, представленными в стандарте IEEE 754.

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

Обзор и ссылки

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

  • Определяющим руководством по арифметике с плавающей запятой является стандарт IEEE 754-2008; однако он не доступен в свободном доступе в интернете.
  • Для краткого, но ясного представления о том, как представлены числа с плавающей запятой, см. статью Джона Д. Кука на эту тему, а также его введение в некоторые вопросы, возникающие из-за того, как это представление отличается от идеализированной абстракции действительных чисел.
  • Рекомендуется также серия постов в блоге Брюса Доусона о числах с плавающей запятой.
  • Для отличного глубокого обсуждения чисел с плавающей запятой и проблем с точностью вычислений при работе с ними см. статью Дэвида Голдберга Что каждый компьютерный ученый должен знать об арифметике с плавающей запятой.
  • Для еще более подробной документации о истории, обосновании и проблемах чисел с плавающей запятой, а также обсуждения многих других тем в вычислительной науке, см. собранные работы Уильяма Кахана, известного как «Отец чисел с плавающей запятой». Особого внимания заслуживает интервью со стариком чисел с плавающей запятой.

Арифметика с произвольной точностью

Для выполнения вычислений с целыми числами и числами с плавающей запятой произвольной точности Julia использует библиотеку GNU Multiple Precision Arithmetic Library (GMP) и GNU MPFR Library соответственно. Типы BigInt и BigFloat доступны в Julia для целых и чисел с плавающей запятой произвольной точности соответственно.

Существуют конструкторы для создания этих типов из примитивных числовых типов, и литерал строки @big_str или parse может использоваться для их создания из AbstractString. После создания они участвуют в арифметических операциях со всеми другими числовыми типами благодаря механизму повышения и преобразования типов Julia преобразования и повышения типа:

julia> BigInt(typemax(Int64)) + 1
9223372036854775808

julia> big"123456789012345678901234567890" + 1
123456789012345678901234567891

julia> parse(BigInt, "123456789012345678901234567890") + 1
123456789012345678901234567891

julia> big"1.23456789012345678901"
1.234567890123456789010000000000000000000000000000000000000000000000000000000004

julia> parse(BigFloat, "1.23456789012345678901")
1.234567890123456789010000000000000000000000000000000000000000000000000000000004

julia> BigFloat(2.0^66) / 3
2.459565876494606882133333333333333333333333333333333333333333333333333333333344e+19

julia> factorial(BigInt(40))
815915283247897734345611269596115894272000000000

Однако, автоматическое преобразование между примитивными типами выше и BigInt/BigFloat не выполняется и должно быть указано явно.

julia> x = typemin(Int64)
-9223372036854775808

julia> x = x - 1
9223372036854775807

julia> typeof(x)
Int64

julia> y = BigInt(typemin(Int64))
-9223372036854775808

julia> y = y - 1
-9223372036854775809

julia> typeof(y)
BigInt

Значение по умолчанию точности (в количестве битов мантиссы) и режим округления операций BigFloat могут быть изменены глобально путем вызова setprecision и setrounding, и все последующие вычисления будут учитывать эти изменения. В качестве альтернативы, точность или режим округления можно изменить только в рамках выполнения определенного блока кода, используя те же функции с do блоком:

julia> setrounding(BigFloat, RoundUp) do
           BigFloat(1) + parse(BigFloat, "0.1")
       end
1.100000000000000000000000000000000000000000000000000000000000000000000000000003

julia> setrounding(BigFloat, RoundDown) do
           BigFloat(1) + parse(BigFloat, "0.1")
       end
1.099999999999999999999999999999999999999999999999999999999999999999999999999986

julia> setprecision(40) do
           BigFloat(1) + parse(BigFloat, "0.1")
       end
1.1000000000004

Коэффициенты числовых литералов

Для повышения ясности общих числовых формул и выражений, Julia позволяет переменным предшествовать числовому литералу, подразумевая умножение. Это делает запись полиномиальных выражений намного чище:

julia> x = 3
3

julia> 2x^2 - 3x + 1
10

julia> 1.5x^2 - .5x + 1
13.0

Это также делает запись экспоненциальных функций более элегантной:

julia> 2^2x
64

Предпорядок числовых коэффициентов-литералов немного ниже, чем у унарных операторов, таких как унарный минус. Таким образом, -2x парсится как (-2) * x и √2x парсится как (√2) * x. Однако числовые коэффициенты-литералы парсятся аналогично унарным операторам при совместном использовании с операцией возведения в степень. Например, 2^3x парсится как 2^(3x), а 2x^3 парсится как 2*(x^3).

Числовые литералы также работают как коэффициенты для выражений в скобках:

julia> 2(x-1)^2 - 3(x-1) + 1
3

Предпорядок числовых коэффициентов-литералов, используемых для неявного умножения, выше, чем у других бинарных операторов, таких как умножение (*) и деление (/, \, и //). Это означает, например, что 1 / 2im равно -0.5im, а 6 // 2(2 + 1) равно 1 // 1.

Кроме того, выражения в скобках могут использоваться как коэффициенты для переменных, подразумевая умножение выражения на переменную:

julia> (x-1)x
6

Однако ни конкатенация двух выражений в скобках, ни размещение переменной перед выражением в скобках не могут использоваться для подразумеваемого умножения:

julia> (x-1)(x+1)
ERROR: MethodError: objects of type Int64 are not callable

julia> x(x+1)
ERROR: MethodError: objects of type Int64 are not callable

Оба выражения интерпретируются как применение функции: любое выражение, которое не является числовым литералом, за которым сразу следует скобочное выражение, интерпретируется как функция, применённая к значениям в скобках (подробнее о функциях см. Функции). Таким образом, в обоих этих случаях возникает ошибка, так как левое значение не является функцией.

Вышеупомянутые синтаксические улучшения значительно уменьшают визуальный шум, возникающий при записи распространённых математических формул. Обратите внимание, что между числовым коэффициентом-литералом и идентификатором или выражением в скобках, на которые он умножается, пробелы быть не должно.

Синтаксические конфликты

Синтаксис конкатенации коэффициентов-литералов может вступать в конфликт с двумя синтаксисами числовых литералов: шестнадцатеричными целыми литералами и инженерной записью для чисел с плавающей точкой. Вот некоторые ситуации, в которых возникают синтаксические конфликты:

  • Шестнадцатеричный целочисленный литерал 0xff может интерпретироваться как числовой литерал 0, умноженный на переменную xff.
  • Выражение с числом с плавающей точкой 1e10 может интерпретироваться как числовой литерал 1, умноженный на переменную e10, и аналогично с эквивалентной формой E.
  • Выражение с 32-битовым числом с плавающей точкой 1.5f22 может интерпретироваться как числовой литерал 1.5, умноженный на переменную f22.

Во всех случаях неоднозначность разрешается в пользу интерпретации как числовых литералов:

  • Выражения, начинающиеся с 0x всегда являются шестнадцатеричными литералами.
  • Выражения, начинающиеся с числового литерала, за которым следуют e или E всегда являются литералами чисел с плавающей точкой.
  • Выражения, начинающиеся с числового литерала, за которым следует f всегда являются литералами 32-битовых чисел с плавающей точкой.

В отличие от E, которое по историческим причинам эквивалентно e в числовых литералах, F — это просто другая буква и не ведет себя как f в числовых литералах. Следовательно, выражения, начинающиеся с числового литерала, за которым следует F интерпретируются как числовой литерал, умноженный на переменную, что означает, например, что 1.5F22 равно 1.5 * F22.

Литералы ноль и единица

Julia предоставляет функции, возвращающие литералы 0 и 1, соответствующие указанному типу или типу заданной переменной.

Функция Описание
zero(x) Литеральное нулевое значение типа x или типа переменной x
one(x) Литеральное единичное значение типа x или типа переменной x

Эти функции полезны в Числовых сравнениях, чтобы избежать накладных расходов от ненужного преобразования типа.

Примеры:

julia> zero(Float32)
0.0f0

julia> zero(1.0)
0.0

julia> one(Int32)
1

julia> one(BigFloat)
1.0

© 2009–2020 Jeff Bezanson, Stefan Karpinski, Viral B. Shah, and other contributors
Licensed under the MIT License.
https://docs.julialang.org/en/v1.5.3/manual/integers-and-floating-point-numbers/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API