Kaelygon

ArrayRandom.py

Jan 11th, 2026 (edited)
141
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 2.02 KB | None | 0 0
  1. import numpy as np
  2. import time
  3.  
  4. #https://rosettacode.org/wiki/Pseudo-random_numbers/Splitmix64
  5. class ArrayRandom:
  6. """
  7. Splitmix64 vectorized pseudo number generator
  8. If no seed is given, a random is generated
  9. """
  10. _state = None
  11. _seed = None #ArrayRandom._seed can be passed to new instance to reproduce the results
  12. MASK = 2**64-1
  13.  
  14. FLOAT_MASK = np.uint64(1023) << 52
  15. CONST_ADD1 = np.uint64(0x9e3779b97f4a7c15)
  16. CONST_MUL1 = np.uint64(0xbf58476d1ce4e5b9)
  17. CONST_MUL2 = np.uint64(0x94d049bb133111eb)
  18.  
  19. #Python int or np.int
  20. def __init__(self, user_seed = None):
  21. buf_seed = user_seed
  22. if buf_seed is None:
  23. #effective starting seed is the output of 1 iteration pass, using _state = time + CONST_ADD1
  24. self._state = np.uint64(time.perf_counter_ns())
  25. buf_seed = self.randomInt((1,))[0]
  26. elif not isinstance(buf_seed, (int,np.uint64)):
  27. raise ValueError("user_seed must be int or np.uint64")
  28. self._state = np.uint64(buf_seed & self.MASK)
  29. self._seed = self._state
  30.  
  31. def randomInt(self, shape: tuple):
  32. """
  33. No safety checks. Shape must be tuple (>=1,) and its product mustn't be higher than 2**63-1
  34. but you'll run out of memory long before that.
  35. """
  36. #have to use np.<operand>() to implicitly suppress overflow warnings
  37. count = np.prod(shape, dtype=int)
  38.  
  39. rand_arr = np.arange(1, count+1, dtype=np.uint64) #n=1,2,3...
  40. rand_arr*=self.CONST_ADD1 #i*n
  41. rand_arr+=self._state #i*n+s
  42.  
  43. #Splitmix64
  44. rand_arr^= rand_arr >> 30
  45. rand_arr*= self.CONST_MUL1
  46. rand_arr^= rand_arr >> 27
  47. rand_arr*= self.CONST_MUL2
  48. rand_arr^= rand_arr >> 31
  49.  
  50. self._state = np.add(self._state, np.multiply(self.CONST_ADD1, np.uint64(count)) )
  51. return rand_arr.reshape(shape)
  52.  
  53. def random(self, shape: tuple):
  54. """randomInt(shape: tuple) -> normalized [0,1) """
  55. return (self.randomInt(shape) >> 12 | self.FLOAT_MASK).view(np.float64) - 1.0
  56.  
  57. def shuffle(self, arr):
  58. count = arr.shape[0]
  59. rand_arr = self.randomInt((count,))
  60. order = np.argsort(rand_arr, kind='stable')
  61. arr[:] = arr[order]
Advertisement
Add Comment
Please, Sign In to add comment