@@ -143,7 +143,7 @@ mt_setempty!(r::MersenneTwister) = r.idx = MTCacheLength
143
143
mt_pop! (r:: MersenneTwister ) = @inbounds return r. vals[r. idx+= 1 ]
144
144
145
145
function gen_rand (r:: MersenneTwister )
146
- Base . @gc_preserve r dsfmt_fill_array_close1_open2! (r. state, pointer (r. vals), length (r. vals))
146
+ @gc_preserve r dsfmt_fill_array_close1_open2! (r. state, pointer (r. vals), length (r. vals))
147
147
mt_setfull! (r)
148
148
end
149
149
@@ -264,12 +264,14 @@ rand(r::MersenneTwister, ::SamplerType{Int128}) = rand(r, UInt128) % Int128
264
264
265
265
# ### arrays of floats
266
266
267
- function rand_AbstractArray_Float64! (r:: MersenneTwister , A:: AbstractArray{Float64} ,
268
- region:: AbstractUnitRange , I:: FloatInterval_64 )
269
- # region should be a subset of linearindices(A)
267
+ # #### AbstractArray
268
+
269
+ function rand! (r:: MersenneTwister , A:: AbstractArray{Float64} ,
270
+ I:: SamplerTrivial{<:FloatInterval_64} )
271
+ region = linearindices (A)
270
272
# what follows is equivalent to this simple loop but more efficient:
271
273
# for i=region
272
- # @inbounds A[i] = rand(r, I)
274
+ # @inbounds A[i] = rand(r, I[] )
273
275
# end
274
276
m = Base. checked_sub (first (region), 1 )
275
277
n = last (region)
@@ -281,53 +283,99 @@ function rand_AbstractArray_Float64!(r::MersenneTwister, A::AbstractArray{Float6
281
283
end
282
284
m2 = min (n, m+ s)
283
285
for i= m+ 1 : m2
284
- @inbounds A[i] = rand_inbounds (r, I)
286
+ @inbounds A[i] = rand_inbounds (r, I[] )
285
287
end
286
288
m = m2
287
289
end
288
290
A
289
291
end
290
292
291
- rand! (r:: MersenneTwister , A:: AbstractArray{Float64} , I:: SamplerTrivial{<:FloatInterval_64} ) =
292
- rand_AbstractArray_Float64! (r, A, linearindices (A), I[])
293
+
294
+ # #### Array : internal functions
295
+
296
+ # internal array-like type to circumevent the lack of flexibility with reinterpret
297
+ struct UnsafeView{T} <: DenseArray{T,1}
298
+ ptr:: Ptr{T}
299
+ len:: Int
300
+ end
301
+
302
+ Base. length (a:: UnsafeView ) = a. len
303
+ Base. getindex (a:: UnsafeView , i:: Int ) = unsafe_load (a. ptr, i)
304
+ Base. setindex! (a:: UnsafeView , x, i:: Int ) = unsafe_store! (a. ptr, x, i)
305
+
306
+ # this is essentially equivalent to rand!(r, ::AbstractArray{Float64}, I) above, but due to
307
+ # optimizations which can't be done currently when working with pointers, we have to re-order
308
+ # manually the computation flow to get the performance
309
+ # (see https://discourse.julialang.org/t/unsafe-store-sometimes-slower-than-arrays-setindex)
310
+ function _rand_max383! (r:: MersenneTwister , A:: UnsafeView{Float64} , I:: FloatInterval_64 )
311
+ n = length (A)
312
+ @assert n <= dsfmt_get_min_array_size ()+ 1 # == 383
313
+ mt_avail (r) == 0 && gen_rand (r)
314
+ # from now on, at most one call to gen_rand(r) will be necessary
315
+ m = min (n, mt_avail (r))
316
+ @gc_preserve r unsafe_copy! (A. ptr, pointer (r. vals, r. idx+ 1 ), m)
317
+ if m == n
318
+ r. idx += m
319
+ else # m < n
320
+ gen_rand (r)
321
+ @gc_preserve r unsafe_copy! (A. ptr+ m* sizeof (Float64), pointer (r. vals), n- m)
322
+ r. idx = n- m
323
+ end
324
+ if I isa CloseOpen
325
+ for i= 1 : n
326
+ A[i] -= 1.0
327
+ end
328
+ end
329
+ A
330
+ end
331
+
293
332
294
333
fill_array! (s:: DSFMT_state , A:: Ptr{Float64} , n:: Int , :: CloseOpen_64 ) =
295
334
dsfmt_fill_array_close_open! (s, A, n)
296
335
297
336
fill_array! (s:: DSFMT_state , A:: Ptr{Float64} , n:: Int , :: Close1Open2_64 ) =
298
337
dsfmt_fill_array_close1_open2! (s, A, n)
299
338
300
- function _rand! (r:: MersenneTwister , A:: Array{Float64} , n:: Int ,
301
- I:: FloatInterval_64 )
339
+
340
+ function rand! (r:: MersenneTwister , A:: UnsafeView{Float64} ,
341
+ I:: SamplerTrivial{<:FloatInterval_64} )
302
342
# depending on the alignment of A, the data written by fill_array! may have
303
343
# to be left-shifted by up to 15 bytes (cf. unsafe_copy! below) for
304
344
# reproducibility purposes;
305
345
# so, even for well aligned arrays, fill_array! is used to generate only
306
346
# the n-2 first values (or n-3 if n is odd), and the remaining values are
307
347
# generated by the scalar version of rand
308
- n > length (A) && throw ( BoundsError (A, n) )
348
+ n = length (A)
309
349
n2 = (n- 2 ) ÷ 2 * 2
310
- if n2 < dsfmt_get_min_array_size ()
311
- rand_AbstractArray_Float64! (r, A, 1 : n, I)
350
+ n2 < dsfmt_get_min_array_size () && return _rand_max383! (r, A, I[])
351
+
352
+ pA = A. ptr
353
+ align = Csize_t (pA) % 16
354
+ if align > 0
355
+ pA2 = pA + 16 - align
356
+ fill_array! (r. state, pA2, n2, I[]) # generate the data in-place, but shifted
357
+ unsafe_copy! (pA, pA2, n2) # move the data to the beginning of the array
312
358
else
313
- pA = pointer (A)
314
- align = Csize_t (pA) % 16
315
- Base. @gc_preserve A if align > 0
316
- pA2 = pA + 16 - align
317
- fill_array! (r. state, pA2, n2, I) # generate the data in-place, but shifted
318
- unsafe_copy! (pA, pA2, n2) # move the data to the beginning of the array
319
- else
320
- fill_array! (r. state, pA, n2, I)
321
- end
322
- for i= n2+ 1 : n
323
- @inbounds A[i] = rand (r, I)
324
- end
359
+ fill_array! (r. state, pA, n2, I[])
360
+ end
361
+ for i= n2+ 1 : n
362
+ A[i] = rand (r, I[])
325
363
end
326
364
A
327
365
end
328
366
329
- rand! (r:: MersenneTwister , A:: Array{Float64} , sp:: SamplerTrivial{<:FloatInterval_64} ) =
330
- _rand! (r, A, length (A), sp[])
367
+ # fills up A reinterpreted as an array of Float64 with n64 values
368
+ function _rand! (r:: MersenneTwister , A:: Array{T} , n64:: Int , I:: FloatInterval_64 ) where T
369
+ # n64 is the length in terms of `Float64` of the target
370
+ @assert sizeof (Float64)* n64 <= sizeof (T)* length (A) && isbits (T)
371
+ @gc_preserve A rand! (r, UnsafeView {Float64} (pointer (A), n64), SamplerTrivial (I))
372
+ A
373
+ end
374
+
375
+ # #### Array: Float64, Float16, Float32
376
+
377
+ rand! (r:: MersenneTwister , A:: Array{Float64} , I:: SamplerTrivial{<:FloatInterval_64} ) =
378
+ _rand! (r, A, length (A), I[])
331
379
332
380
mask128 (u:: UInt128 , :: Type{Float16} ) =
333
381
(u & 0x03ff03ff03ff03ff03ff03ff03ff03ff ) | 0x3c003c003c003c003c003c003c003c00
@@ -339,27 +387,27 @@ for T in (Float16, Float32)
339
387
@eval function rand! (r:: MersenneTwister , A:: Array{$T} , :: SamplerTrivial{Close1Open2{$T}} )
340
388
n = length (A)
341
389
n128 = n * sizeof ($ T) ÷ 16
342
- Base . @gc_preserve A _rand! (r, unsafe_wrap (Array, convert (Ptr{Float64}, pointer (A)) , 2 * n128),
343
- 2 * n128, Close1Open2 ())
344
- # FIXME : This code is completely invalid!!!
345
- A128 = unsafe_wrap (Array, convert (Ptr{UInt128}, pointer (A)), n128)
346
- @inbounds for i in 1 : n128
347
- u = A128[i]
348
- u ⊻= u << 26
349
- # at this point, the 64 low bits of u, "k" being the k-th bit of A128[i] and "+"
350
- # the bit xor, are:
351
- # [..., 58+32,..., 53+27, 52+26, ..., 33+7, 32+6, ..., 27+1, 26, ..., 1]
352
- # the bits needing to be random are
353
- # [1:10, 17:26, 33:42, 49:58 ] (for Float16 )
354
- # [1:23, 33:55] (for Float32)
355
- # this is obviously satisfied on the 32 low bits side, and on the high side,
356
- # the entropy comes from bits 33:52 of A128[i] and then from bits 27:32
357
- # (which are discarded on the low side)
358
- # this is similar for the 64 high bits of u
359
- A128[i] = mask128 (u, $ T)
390
+ _rand! (r, A , 2 * n128, Close1Open2 ())
391
+ @gc_preserve A begin
392
+ A128 = UnsafeView {UInt128} ( pointer (A), n128)
393
+ for i in 1 : n128
394
+ u = A128[i]
395
+ u ⊻= u << 26
396
+ # at this point, the 64 low bits of u, "k" being the k-th bit of A128[i] and "+"
397
+ # the bit xor, are:
398
+ # [..., 58+32,..., 53+27, 52+26, ..., 33+7, 32+6, ..., 27+1, 26, ..., 1]
399
+ # the bits needing to be random are
400
+ # [1:10, 17:26, 33:42, 49:58] (for Float16)
401
+ # [1:23, 33:55 ] (for Float32 )
402
+ # this is obviously satisfied on the 32 low bits side, and on the high side,
403
+ # the entropy comes from bits 33:52 of A128[i] and then from bits 27:32
404
+ # (which are discarded on the low side)
405
+ # this is similar for the 64 high bits of u
406
+ A128[i] = mask128 (u, $ T)
407
+ end
360
408
end
361
409
for i in 16 * n128÷ sizeof ($ T)+ 1 : n
362
- @inbounds A[i] = rand (r, $ T) + oneunit ($ T)
410
+ @inbounds A[i] = rand (r, $ T) + one ($ T)
363
411
end
364
412
A
365
413
end
@@ -376,16 +424,14 @@ end
376
424
377
425
# ### arrays of integers
378
426
379
- function rand ! (r:: MersenneTwister , A:: Array{UInt128} , :: SamplerType {UInt128} )
427
+ function _rand ! (r:: MersenneTwister , A:: UnsafeView {UInt128} )
380
428
n:: Int = length (A)
381
- # FIXME : This code is completely invalid!!!
382
- Af = unsafe_wrap (Array, convert (Ptr{Float64}, pointer (A)), 2 n)
383
429
i = n
384
430
while true
385
- _rand ! (r, Af , 2 i, Close1Open2 ())
431
+ rand ! (r, UnsafeView {Float64} (A . ptr , 2 i) , Close1Open2 ())
386
432
n < 5 && break
387
433
i = 0
388
- @inbounds while n- i >= 5
434
+ while n- i >= 5
389
435
u = A[i+= 1 ]
390
436
A[n] ⊻= u << 48
391
437
A[n-= 1 ] ⊻= u << 36
@@ -397,19 +443,17 @@ function rand!(r::MersenneTwister, A::Array{UInt128}, ::SamplerType{UInt128})
397
443
if n > 0
398
444
u = rand (r, UInt2x52Raw ())
399
445
for i = 1 : n
400
- @inbounds A[i] ⊻= u << (12 * i)
446
+ A[i] ⊻= u << (12 * i)
401
447
end
402
448
end
403
449
A
404
450
end
405
451
406
452
for T in BitInteger_types
407
- T === UInt128 && continue
408
453
@eval function rand! (r:: MersenneTwister , A:: Array{$T} , :: SamplerType{$T} )
409
454
n = length (A)
410
455
n128 = n * sizeof ($ T) ÷ 16
411
- # FIXME : This code is completely invalid!!!
412
- rand! (r, unsafe_wrap (Array, convert (Ptr{UInt128}, pointer (A)), n128))
456
+ @gc_preserve A _rand! (r, UnsafeView {UInt128} (pointer (A), n128))
413
457
for i = 16 * n128÷ sizeof ($ T)+ 1 : n
414
458
@inbounds A[i] = rand (r, $ T)
415
459
end
0 commit comments