Spec-Zone.ru › OCaml 5.0

Модуль Float.Array

module Array: sig .. end

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

type t = floatarray 

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

  • Since 4.08.0
val length : t -> int

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

val get : t -> int -> float

get a n возвращает элемент с номером n floatarray a.

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

set a n x изменяет floatarray a на месте, заменяя элемент с номером n на x.

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

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

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

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

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

init n f возвращает новый floatarray длины 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 возвращает новый floatarray, содержащий конкатенацию floatarrays v1 и v2.

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

То же, что и Float.Array.append, но конкатенирует список floatarrays.

val sub : t -> int -> int -> t

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

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

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

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

fill a pos len x изменяет floatarray a на месте, сохраняя x в элементы с номерами pos по pos + len - 1.

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

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

  • 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 возвращает новый floatarray, содержащий элементы l.

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

Итераторы

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

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

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

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

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

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

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

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

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

fold_left f x init вычисляет f (... (f (f x init.(0)) init.(1)) ...) init.(n-1), где n - длина floatarray init.

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

fold_right f a init вычисляет f a.(0) (f a.(1) ( ... (f a.(n-1) init) ...)), где n - длина floatarray a.

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

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

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

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

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

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

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

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

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

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

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

val mem : float -> t -> bool

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

val mem_ieee : float -> t -> bool

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

Сортировка

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

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

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

Спецификация функции сравнения: Пусть a - floatarray, а 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 : (float -> float -> int) -> t -> unit

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

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

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

Аналогично Float.Array.sort или Float.Array.stable_sort, что быстрее на типичных входных данных.

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

val to_seq : t -> float Seq.t

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

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

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

val of_seq : float Seq.t -> t

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

val map_to_array : (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 : ('a -> float) -> 'a array -> t

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

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

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

Атомарность

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

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

let size = 100_000_000
  let a = Float.Array.make size 1.
  let update a f () =
     Float.Array.iteri (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.Array.html

Spec-Zone.ru

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