module Array:sig
..end
具有封裝表示法的浮點數陣列。
typet =
floatarray
具有封裝表示法的浮點數陣列型別。
val length : t -> int
返回給定浮點數陣列的長度(元素數量)。
val get : t -> int -> float
get a n
返回浮點數陣列 a
的第 n
個元素。
n
超出 0 到 (length a - 1)
的範圍,則引發 Invalid_argument
。val set : t -> int -> float -> unit
set a n x
就地修改浮點數陣列 a
,將第 n
個元素替換為 x
。
n
超出 0 到 (length a - 1)
的範圍,則引發 Invalid_argument
。val make : int -> float -> t
make n x
返回一個長度為 n
的全新浮點數陣列,並以 x
初始化。
n < 0
或 n > Sys.max_floatarray_length
,則引發 Invalid_argument
。val create : int -> t
create n
返回一個長度為 n
的全新浮點數陣列,且資料未初始化。
n < 0
或 n > Sys.max_floatarray_length
,則引發 Invalid_argument
。val init : int -> (int -> float) -> t
init n f
返回一個長度為 n
的全新浮點數陣列,其中第 i
個元素初始化為 f i
的結果。換句話說,init n f
會將 f
應用於整數 0
到 n-1
的結果製成表格。
n < 0
或 n > Sys.max_floatarray_length
,則引發 Invalid_argument
。val make_matrix : int -> int -> float -> t array
make_matrix dimx dimy e
返回一個二維陣列(陣列的陣列),第一個維度為 dimx
,第二個維度為 dimy
,其中所有元素都以 e
初始化。
dimx
或 dimy
為負數或大於 Sys.max_floatarray_length
,則引發 Invalid_argument
。val init_matrix : int -> int -> (int -> int -> float) -> t array
init_matrix dimx dimy f
返回一個二維陣列(陣列的陣列),第一個維度為 dimx
,第二個維度為 dimy
,其中索引 (x,y
) 處的元素以 f x y
初始化。
dimx
或 dimy
為負數或大於 Sys.max_floatarray_length
,則引發 Invalid_argument
。val append : t -> t -> t
append v1 v2
返回一個全新的浮點數陣列,其中包含浮點數陣列 v1
和 v2
的串聯。
length v1 + length v2 > Sys.max_floatarray_length
,則引發 Invalid_argument
。val concat : t list -> t
與 Float.Array.append
相同,但串聯一個浮點數陣列列表。
val sub : t -> int -> int -> t
sub a pos len
返回一個長度為 len
的全新浮點數陣列,其中包含浮點數陣列 a
的第 pos
到 pos + len - 1
個元素。
pos
和 len
沒有指定 a
的有效子陣列,則引發 Invalid_argument
;也就是說,如果 pos < 0
、或 len < 0
、或 pos + len > length a
。val copy : t -> t
copy a
返回 a
的副本,也就是說,一個全新的浮點數陣列,其中包含與 a
相同的元素。
val fill : t -> int -> int -> float -> unit
fill a pos len x
就地修改浮點數陣列 a
,在第 pos
到 pos + len - 1
個元素中儲存 x
。
pos
和 len
沒有指定 a
的有效子陣列,則引發 Invalid_argument
。val blit : t -> int -> t -> int -> int -> unit
blit src src_pos dst dst_pos len
從浮點數陣列 src
的第 src_pos
個元素開始,將 len
個元素複製到浮點數陣列 dst
的第 dst_pos
個元素開始的位置。即使 src
和 dst
是相同的浮點數陣列,並且來源和目的地區塊重疊,它也能正常運作。
src_pos
和 len
沒有指定 src
的有效子陣列,或者如果 dst_pos
和 len
沒有指定 dst
的有效子陣列,則引發 Invalid_argument
。val to_list : t -> float list
to_list a
返回 a
的所有元素的列表。
val of_list : float list -> t
of_list l
返回一個全新的浮點數陣列,其中包含 l
的元素。
l
的長度大於 Sys.max_floatarray_length
,則引發 Invalid_argument
。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
的所有元素,並使用 f
返回的結果建立一個浮點數陣列。
val map_inplace : (float -> float) -> t -> unit
map_inplace f a
將函數 f
應用於 a
的所有元素,並就地更新它們的值。
val mapi : (int -> float -> float) -> t -> t
與 Float.Array.map
相同,但是將元素的索引作為第一個參數,元素本身作為第二個參數來應用函數。
val mapi_inplace : (int -> float -> float) -> t -> unit
與 Float.Array.map_inplace
相同,但是將元素的索引作為第一個參數,元素本身作為第二個參數來應用函數。
val fold_left : ('acc -> float -> 'acc) -> 'acc -> t -> 'acc
fold_left f x init
計算 f (... (f (f x init.(0)) init.(1)) ...) init.(n-1)
,其中 n
是浮點數陣列 init
的長度。
val fold_right : (float -> 'acc -> 'acc) -> t -> 'acc -> 'acc
fold_right f a init
計算 f a.(0) (f a.(1) ( ... (f a.(n-1) init) ...))
,其中 n
是浮點數陣列 a
的長度。
val iter2 : (float -> float -> unit) -> t -> t -> unit
Array.iter2 f a b
將函數 f
應用於 a
和 b
的所有元素。
Invalid_argument
。val map2 : (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)|]
。
Invalid_argument
。val for_all : (float -> bool) -> t -> bool
for_all f [|a1; ...; an|]
檢查浮點數陣列的所有元素是否都滿足謂詞 f
。也就是說,它返回 (f a1) && (f a2) && ... && (f an)
。
val exists : (float -> bool) -> t -> bool
exists f [|a1; ...; an|]
檢查浮點數陣列中是否至少有一個元素滿足謂詞 f
。也就是說,它返回 (f a1) || (f a2) || ... || (f an)
。
val mem : float -> t -> bool
mem a set
如果且僅當 set
中存在一個與 a
結構相等的元素時,則為 true,也就是說,set
中存在一個 x
,使得 compare a x = 0
。
val mem_ieee : float -> t -> bool
與 Float.Array.mem
相同,但使用 IEEE 相等性而不是結構相等性。
val find_opt : (float -> bool) -> t -> float option
val find_index : (float -> bool) -> t -> int option
find_index f a
返回 Some i
,其中 i
是陣列 a
中滿足 f x
的第一個元素的索引,如果存在這樣的元素。
如果不存在這樣的元素,則返回 None
。
val find_map : (float -> 'a option) -> t -> 'a option
val find_mapi : (int -> float -> 'a option) -> t -> 'a option
與 find_map
相同,但謂詞應用於元素的索引(從 0 開始計數)作為第一個參數,元素本身作為第二個參數。
val sort : (float -> float -> int) -> t -> unit
根據比較函數按遞增順序對浮點數陣列進行排序。如果其參數比較為相等,則比較函數必須返回 0;如果第一個較大,則返回正整數;如果第一個較小,則返回負整數(請參閱下面的完整規格)。例如,compare
是一個合適的比較函數。呼叫 sort
後,陣列會就地按遞增順序排序。sort
保證以恆定的堆疊空間和(最多)對數的堆空間執行。
目前的實作使用堆積排序。它在恆定的堆疊空間中執行。
比較函數的規格:讓 a
為浮點數陣列,而 cmp
為比較函數。以下對於 a
中的所有 x
、y
、z
都必須為真
cmp y x
< 0 時,cmp x y
> 0cmp x y
>= 0 且 cmp y z
>= 0,則 cmp x z
>= 0當 sort
返回時,a
包含與之前相同的元素,重新排序的方式為,對於 a
的所有有效索引 i 和 j
cmp a.(i) a.(j)
>= 0val stable_sort : (float -> float -> int) -> t -> unit
與 Float.Array.sort
相同,但排序演算法是穩定的(也就是說,比較相等的元素會保留其原始順序),並且不保證以恆定的堆空間執行。
目前的實作使用合併排序。它使用一個長度為 n/2
的臨時浮點數陣列,其中 n
是浮點數陣列的長度。它通常比目前 Float.Array.sort
的實作更快。
val fast_sort : (float -> float -> int) -> t -> unit
與 Float.Array.sort
或 Float.Array.stable_sort
相同,以典型輸入較快的速度為主。
val shuffle : rand:(int -> int) -> t -> unit
shuffle rand a
使用 rand
進行隨機性,隨機排列 a
的元素。排列的分佈是均勻的。
rand
必須使得呼叫 rand n
會返回範圍 [0
;n-1
] 中均勻分佈的隨機數。可以使用 Random.int
來實現此目的(不要忘記初始化產生器)。
val to_seq : t -> float Seq.t
依遞增順序迭代浮點數陣列。在迭代期間修改浮點數陣列會反映在序列中。
val to_seqi : t -> (int * float) Seq.t
以遞增順序迭代 floatarray,產生元素及其索引。迭代期間對 floatarray 的修改將會反映在序列中。
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
返回的結果建立一個 floatarray。
當從多個域同時存取 float 陣列時,必須小心:存取陣列永遠不會導致程式崩潰,但未同步的存取可能會產生令人驚訝(非循序一致)的結果。
每個存取多個陣列元素的 float 陣列操作都不是原子性的。這包括迭代、掃描、排序、分割和組合陣列。
例如,考慮以下程式碼
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
執行此程式碼後,float 陣列 a
的每個欄位不是 2.
、3.
、4.
就是 5.
。如果需要原子性,則使用者必須實作自己的同步機制(例如,使用 Mutex.t
)。
如果兩個域只存取陣列的不相交部分,則觀察到的行為等同於來自兩個域的操作的某種循序交錯。
當兩個域在沒有同步的情況下存取同一個陣列元素,並且至少其中一個存取是寫入時,就會發生資料競爭。在沒有資料競爭的情況下,觀察到的行為等同於來自不同域的操作的某種循序交錯。
應盡可能避免資料競爭,方法是使用同步來協調對陣列元素的存取。
實際上,在存在資料競爭的情況下,程式不會崩潰,但觀察到的行為可能不等同於來自不同域的操作的任何循序交錯。然而,即使在存在資料競爭的情況下,讀取操作也會傳回先前對該位置寫入的值,但有一些例外。
在存在資料競爭的情況下,Float 陣列有兩個額外的注意事項。
首先,blit 操作可能會逐位元組複製陣列。此類 blit 操作與另一個操作之間的資料競爭可能會由於撕裂而產生令人驚訝的值:部分寫入與其他操作交錯可能會建立在循序執行下不存在的浮點數值。
例如,在結束時
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
float 陣列可能包含既不是 0.
也不是 max_float
的值。
其次,在 32 位元架構上,取得或設定欄位涉及兩個獨立的記憶體存取。在存在資料競爭的情況下,使用者可能會在任何操作上觀察到撕裂現象。