Spec-Zone.ru › OCaml 5.0

Модуль Float.ArrayLabels

module ArrayLabels: sig .. end

Массивы чисел с плавающей точкой с упакованным представлением (меченые функции).

type t = floatarray 

Тип массивов чисел с плавающей точкой с упакованным представлением.

  • Since 4.08.0
val length : t -> int

Возвращает длину (количество элементов) заданного массива чисел с плавающей точкой.

val get : t -> int -> float

get a n возвращает номер элемента n массива чисел с плавающей точкой a.

  • Raises Invalid_argument если n находится вне диапазона от 0 до (length a - 1).
val set : t -> int -> float -> unit

set a n x изменяет массив чисел с плавающей точкой a на месте, заменяя элемент с номером n на x.

  • Raises Invalid_argument если n находится вне диапазона от 0 до (length a - 1).
val make : int -> float -> t

make n x возвращает новый массив чисел с плавающей точкой длиной n, инициализированный значением x.

  • Raises Invalid_argument если n < 0 или n > Sys.max_floatarray_length.
val create : int -> t

create n возвращает новый массив чисел с плавающей точкой длиной n, с неинициализированными данными.

  • Raises Invalid_argument если n < 0 или n > Sys.max_floatarray_length.
val init : int -> f:(int -> float) -> t

init n ~f возвращает новый массив чисел с плавающей точкой длиной n, с элементом под номером i инициализированным результатом f i. Другими словами, init n ~f табулирует результаты f для целых чисел от 0 до n-1.

  • Raises Invalid_argument если n < 0 или n > Sys.max_floatarray_length.
val append : t -> t -> t

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

  • Raises Invalid_argument если length v1 + length v2 > Sys.max_floatarray_length.
val concat : t list -> t

То же, что и Float.ArrayLabels.append, но конкатенирует список массивов чисел с плавающей точкой.

val sub : t -> pos:int -> len:int -> t

sub a ~pos ~len возвращает новый массив чисел с плавающей точкой длиной len, содержащий элементы с номерами от pos до pos + len - 1 массива a.

  • Raises Invalid_argument если pos и len не обозначают допустимый подмассив a; то есть, если pos < 0, или len < 0, или pos + len > length a.
val copy : t -> t

copy a возвращает копию a, то есть новый массив чисел с плавающей точкой, содержащий те же элементы, что и a.

val fill : t -> pos:int -> len:int -> float -> unit

fill a ~pos ~len x изменяет массив чисел с плавающей точкой a на месте, сохраняя x в элементах с номерами от pos до pos + len - 1.

  • Raises Invalid_argument если pos и len не обозначают допустимый подмассив a.
val blit : src:t ->       src_pos:int -> dst:t -> dst_pos:int -> len:int -> unit

blit ~src ~src_pos ~dst ~dst_pos ~len копирует len элементов из массива src, начиная с элемента под номером src_pos, в массив dst, начиная с элемента под номером dst_pos. Это работает корректно даже если src и dst — один и тот же массив, и фрагменты источника и назначения перекрываются.

  • Raises Invalid_argument если src_pos и len не обозначают допустимый подмассив src, или если dst_pos и len не обозначают допустимый подмассив dst.
val to_list : t -> float list

to_list a возвращает список всех элементов a.

val of_list : float list -> t

of_list l возвращает новый массив чисел с плавающей точкой, содержащий элементы l.

  • Raises Invalid_argument если длина l больше Sys.max_floatarray_length.

Итераторы

val iter : f:(float -> unit) -> t -> unit

iter ~f a применяет функцию f к каждому элементу a по очереди. Это эквивалентно f a.(0); f a.(1); ...; f a.(length a - 1); ().

val iteri : f:(int -> float -> unit) -> t -> unit

То же, что и Float.ArrayLabels.iter, но функция применяется к индексу элемента как первому аргументу, а к самому элементу как второму.

val map : f:(float -> float) -> t -> t

map ~f a применяет функцию f ко всем элементам a и создаёт массив чисел с плавающей точкой из результатов, возвращённых функцией f.

val mapi : f:(int -> float -> float) -> t -> t

То же, что и Float.ArrayLabels.map, но функция применяется к индексу элемента как первому аргументу, а к самому элементу как второму.

val fold_left : f:('a -> float -> 'a) -> init:'a -> t -> 'a

fold_left ~f x ~init вычисляет f (... (f (f x init.(0)) init.(1)) ...) init.(n-1), где n — длина массива чисел с плавающей точкой init.

val fold_right : f:(float -> 'a -> 'a) -> t -> init:'a -> 'a

fold_right f a init вычисляет f a.(0) (f a.(1) ( ... (f a.(n-1) init) ...)), где n — длина массива чисел с плавающей точкой a.

Итераторы над двумя массивами

val iter2 : f:(float -> float -> unit) ->       t -> t -> unit

Array.iter2 ~f a b применяет функцию f ко всем элементам массивов a и b.

  • Raises Invalid_argument если массивы чисел с плавающей точкой имеют разную длину.
val map2 : f:(float -> float -> float) ->       t -> t -> t

map2 ~f a b применяет функцию f ко всем элементам a и b, и создаёт массив чисел с плавающей точкой из результатов, возвращённых f: [| f a.(0) b.(0); ...; f a.(length a - 1) b.(length b - 1)|].

  • Raises Invalid_argument если массивы чисел с плавающей точкой имеют разную длину.

Сканирование массивов

val for_all : f:(float -> bool) -> t -> bool

for_all ~f [|a1; ...; an|] проверяет, удовлетворяют ли все элементы массива чисел с плавающей точкой предикату f. То есть, он возвращает (f a1) && (f a2) && ... && (f an).

val exists : f:(float -> bool) -> t -> bool

exists f [|a1; ...; an|] проверяет, удовлетворяет ли хотя бы один элемент массива чисел с плавающей точкой предикату f. То есть, он возвращает (f a1) || (f a2) || ... || (f an).

val mem : float -> set:t -> bool

mem a ~set истинно тогда и только тогда, когда существует элемент set, структурно равный a, т.е. существует x в set, такой что compare a x = 0.

val mem_ieee : float -> set:t -> bool

То же, что и Float.ArrayLabels.mem, но использует равенство IEEE вместо структурного равенства.

Сортировка

val sort : cmp:(float -> float -> int) -> t -> unit

Сортирует массив чисел с плавающей точкой в порядке возрастания по функции сравнения. Функция сравнения должна возвращать 0, если её аргументы равны, положительное целое число, если первый больше, и отрицательное целое число, если первый меньше (см. полное описание ниже). Например, compare — подходящая функция сравнения. После вызова sort, массив сортируется на месте в порядке возрастания. sort гарантированно выполняется с постоянным объёмом памяти и (в худшем случае) логарифмическим объёмом стека.

Текущая реализация использует сортировку кучей. Она работает с постоянным объёмом памяти стека.

Описание функции сравнения: пусть a — массив чисел с плавающей точкой, и cmp — функция сравнения. Следующее должно быть истинным для всех x, y, z в a :

  • cmp x y > 0 тогда и только тогда, когда cmp y x < 0
  • если cmp x y >= 0 и cmp y z >= 0, то cmp x z >= 0

После завершения sort массив a содержит те же элементы, что и раньше, но упорядоченные таким образом, что для всех i и j, являющихся допустимыми индексами в a :

  • cmp a.(i) a.(j) >= 0 тогда и только тогда, когда i >= j
val stable_sort : cmp:(float -> float -> int) -> t -> unit

То же, что и Float.ArrayLabels.sort, но алгоритм сортировки устойчивый (т.е. элементы, которые сравниваются как равные, сохраняются в исходном порядке) и не гарантирует работу с постоянным объёмом памяти.

Текущая реализация использует сортировку слиянием. Она использует временный массив чисел с плавающей точкой длиной n/2, где n — длина массива чисел с плавающей точкой. Обычно она быстрее текущей реализации Float.ArrayLabels.sort.

val fast_sort : cmp:(float -> float -> int) -> t -> unit

То же самое, что и Float.ArrayLabels.sort или Float.ArrayLabels.stable_sort, что быстрее на типичных входных данных.

Массивы с плавающей точкой и последовательности

val to_seq : t -> float Seq.t

Итерируйтесь по floatarray в порядке возрастания. Изменения floatarray во время итерации будут отражены в последовательности.

val to_seqi : t -> (int * float) Seq.t

Итерируйтесь по floatarray в порядке возрастания, возвращая индексы вдоль элементов. Изменения floatarray во время итерации будут отражены в последовательности.

val of_seq : float Seq.t -> t

Создать массив из генератора.

val map_to_array : f:(float -> 'a) -> t -> 'a array

map_to_array ~f a применяет функцию f ко всем элементам a, и создает массив с результатами, возвращенными f: [| f a.(0); f a.(1); ...; f a.(length a - 1) |].

val map_from_array : f:('a -> float) -> 'a array -> t

map_from_array ~f a применяет функцию f ко всем элементам a, и создает floatarray с результатами, возвращенными f.

Массивы и безопасность при одновременном доступе

Необходимо соблюдать осторожность при одновременном доступе к массивам с плавающей точкой из нескольких областей: доступ к массиву никогда не приведет к аварийному завершению программы, но несинхронизированный доступ может привести к неожиданным (непоследовательно согласованным) результатам.

Атомарность

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

Например, рассмотрим следующую программу:

let size = 100_000_000
  let a = Float.ArrayLabels.make size 1.
  let update a f () =
     Float.ArrayLabels.iteri ~f:(fun i x -> Float.Array.set a i (f x)) a
  let d1 = Domain.spawn (update a (fun x -> x +. 1.))
  let d2 = Domain.spawn (update a (fun x ->  2. *. x +. 1.))
  let () = Domain.join d1; Domain.join d2
  

После выполнения этого кода каждый элемент массива с плавающей точкой a равен 2., 3., 4. или 5.. Если требуется атомарность, пользователь должен реализовать собственную синхронизацию (например, используя Mutex.t).

Конфликты данных

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

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

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

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

Разрывы

Массивы с плавающей точкой имеют два дополнительных нюанса при наличии конфликтов данных.

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

Например, в конце

let zeros = Float.Array.make size 0.
  let max_floats = Float.Array.make size Float.max_float
  let res = Float.Array.copy zeros
  let d1 = Domain.spawn (fun () -> Float.Array.blit zeros 0 res 0 size)
  let d2 = Domain.spawn (fun () -> Float.Array.blit max_floats 0 res 0 size)
  let () = Domain.join d1; Domain.join d2
  

массив с плавающей точкой res может содержать значения, которые не являются ни 0., ни max_float.

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

© 1995-2022 INRIA.
https://v2.ocaml.org/releases/5.0/htmlman/libref/Float.ArrayLabels.html

Spec-Zone.ru

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