Spec-Zone.ru › Julia 1.2

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

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

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

Ниже приведены примитивные числовые типы Julia:

  • Целочисленные типы:
Тип Знаковый? Количество битов Наименьшее значение Наибольшее значение
Int8 ✓ 8 -2^7 2^7 - 1
UInt8 8 0 2^8 - 1
Int16 ✓ 16 -2^15 2^15 - 1
UInt16 16 0 2^16 - 1
Int32 ✓ 32 -2^31 2^31 - 1
UInt32 32 0 2^32 - 1
  • Типы чисел с плавающей точкой:
Тип Точность Количество битов

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

Целые числа

Литералы целых чисел представлены стандартным способом:

julia> 1
1

julia> 1234
1234

Тип по умолчанию для целочисленного литерала зависит от того, имеет ли целевая система 32-битную или 64-битную архитектуру:

# 32-bit system:
julia> typeof(1)
Int32

# 64-bit system:
julia> typeof(1)
Int64

Внутренняя переменная Julia Sys.WORD_SIZE указывает, является ли целевая система 32-битной или 64-битной:

# 32-bit system:
julia> Sys.WORD_SIZE
32

# 64-bit system:
julia> Sys.WORD_SIZE
64

Julia также определяет типы Int и UInt, которые являются псевдонимами для знакового и беззнакового нативных целочисленных типов системы соответственно:

# 32-bit system:
julia> Int
Int32
julia> UInt
UInt32

# 64-bit system:
julia> Int
Int64
julia> UInt
UInt64
... (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 в арифметике с произвольной точностью.

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

Целочисленное деление (функция 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; однако он недоступен для бесплатного онлайн-доступа.
  • Для краткого, но ясного представления о том, как представлены числа с плавающей запятой, см. статью Джона Д. Кука о этой теме, а также его введение в некоторые проблемы, возникающие из-за того, что это представление отличается от идеализированной абстракции действительных чисел.
  • Также рекомендуется серия постов в блоге Брюса Доусона о числах с плавающей запятой.
  • Для превосходного углубленного обсуждения чисел с плавающей запятой и проблем точности, возникающих при вычислениях с ними, см. статью Дэвида Голдберга What Every Computer Scientist Should Know About Floating-Point Arithmetic.
  • Для еще более подробного описания истории, обоснования и проблем чисел с плавающей запятой, а также обсуждения многих других тем в области вычислительной математики, см. собранные работы Уильяма Кахана, известного как «Отец чисел с плавающей запятой». Особенно интересным может быть интервью со Стариком чисел с плавающей запятой.

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

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

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

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

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

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–2019 Jeff Bezanson, Stefan Karpinski, Viral B. Shah, and other contributors
Licensed under the MIT License.
https://docs.julialang.org/en/v1.2.0/manual/integers-and-floating-point-numbers/

Spec-Zone.ru

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