xorshift 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,8 @@
1
+ Metadata-Version: 2.3
2
+ Name: xorshift
3
+ Version: 1.0.0
4
+ Summary: Random values library using `XorShift128+` under the hood.
5
+ Author: Xenely
6
+ Requires-Python: >=3.10
7
+ Description-Content-Type: text/markdown
8
+
File without changes
@@ -0,0 +1,17 @@
1
+ [project]
2
+ name = "xorshift"
3
+ version = "1.0.0"
4
+ description = "Random values library using `XorShift128+` under the hood."
5
+ authors = [
6
+ {name = "Xenely"}
7
+ ]
8
+ readme = "README.md"
9
+ requires-python = ">=3.10"
10
+ dependencies = []
11
+
12
+ [project.scripts]
13
+ xorshift = "xorshift:main"
14
+
15
+ [build-system]
16
+ requires = ["uv_build>=0.10.4,<0.11.0"]
17
+ build-backend = "uv_build"
@@ -0,0 +1,104 @@
1
+ import time
2
+ import typing
3
+
4
+
5
+ class Xorshift:
6
+ """Class of random vairables generator, uses `xorshift` alghoritm for random."""
7
+
8
+ # ==-----------------------------------------------------------------------------== #
9
+ # Public methods #
10
+ # ==-----------------------------------------------------------------------------== #
11
+ def __init__(self, seed: int | None = None):
12
+ """Creates instance to generate random values, collections."""
13
+
14
+ # Save of initial state
15
+ state = int(seed if seed is not None else time.time() * 1_000) & 0xFFFFFFFFFFFFFFFF
16
+
17
+ # Split state into two parts
18
+ self.state = [
19
+ state ^ 0xA5A5A5A5A5A5A5A5,
20
+ (state >> 1) ^ 0x5555555555555555 ^ 0x14057B7EF767814F
21
+ ]
22
+
23
+ # If state values is null
24
+ if not self.state[0] and not self.state[1]:
25
+ self.state = [1, 0x14057B7EF767814F]
26
+
27
+ def randint(self, start: int, end: int) -> int:
28
+ """Gets random integer value from [start, end] range."""
29
+
30
+ # If start less than end
31
+ if start > end:
32
+ start, end = end, start
33
+
34
+ # Random value generation
35
+ if (offset := self.__get_next() % (span := end - start + 1)) < 0:
36
+ offset += span
37
+
38
+ # Return generated random integer value
39
+ return start + offset
40
+
41
+ def randfloat(self, start: float, end: float) -> float:
42
+ """Gets random float value from [start, end) range."""
43
+
44
+ # Start and end of range to generate random values
45
+ start = min(start, end)
46
+ end = max(start, end)
47
+
48
+ # Generate and return random float value
49
+ return start + (end - start) * ((self.__get_next() >> 11) / ((1 << 53) - 1.0))
50
+
51
+ def sample(self, values: list[typing.Any], n: int | None = None) -> list[typing.Any]:
52
+ """Gets `N` random values from source list and creates new one. If `N` is `None` samples the whole list."""
53
+
54
+ # Get min-max avaiable `N` value
55
+ n = max(0, min(len(values), n if n is not None else len(values)))
56
+
57
+ # If sampling is not required
58
+ if not n:
59
+ return list()
60
+
61
+ # Result list
62
+ result = values[:]
63
+
64
+ # Sample list values
65
+ for index in range(len(values) - 1, len(values) - n - 1, -1):
66
+
67
+ # Get random value
68
+ random_value = self.__get_next() % (index + 1)
69
+
70
+ # Shuffle values
71
+ result[index], result[random_value] = result[random_value], result[index]
72
+
73
+ # Return `N` last values in sampled list
74
+ return result[-n:]
75
+
76
+ def choice(self, values: typing.Iterable[typing.Any]) -> typing.Any:
77
+ """Chooses random value from collection."""
78
+
79
+ # If collection is empty
80
+ if not values:
81
+ raise Exception("Collection is empty, unable to chose random value")
82
+
83
+ # Get and return random collection value
84
+ return values[self.randint(0, len(values) - 1)]
85
+
86
+ # ==-----------------------------------------------------------------------------== #
87
+ # Private methods #
88
+ # ==-----------------------------------------------------------------------------== #
89
+ def __get_next(self) -> int:
90
+ """Генерирует следующее псеводо-случайное число."""
91
+
92
+ # Извлечение текущего состояния
93
+ state_0, state_1 = self.state
94
+
95
+ # Генерация случайного числа
96
+ result = (state_0 + state_1) & 0xFFFFFFFFFFFFFFFF
97
+
98
+ # Обновление состояния
99
+ state_1 ^= state_0
100
+ self.state[0] = ((state_0 << 24) | (state_0 >> 40)) ^ state_1 ^ (state_1 << 16)
101
+ self.state[1] = (state_1 << 37) | (state_1 >> 27)
102
+
103
+ # Возврат результата
104
+ return result