pcg_random 0.1.4 → 0.1.6
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.
- checksums.yaml +4 -4
- data/README.md +91 -19
- data/Rakefile +3 -5
- data/benchmarks/new_seed.md +6 -6
- data/benchmarks/raw_seed.md +6 -6
- data/ext/pcg_random/pcg_random.c +11 -167
- data/ext/pcg_random/pcg_random.h +0 -14
- data/ext/pcg_random/pcg_rng.c +248 -0
- data/ext/pcg_random/pcg_rng.h +29 -0
- data/lib/pcg_random/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e613759fc11837de964926f2067b38d770100cd6
|
4
|
+
data.tar.gz: c72b3c2996301edeeb5084c5d785342219c99b59
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9dd5e22f22437be3e1cf6fa105f984d12cda521462e284a14d373d1f7c3b45b029a07e84a099f2fdbc833e54fe0748dd69f05f972119fa015a6f7c8da5e1754c
|
7
|
+
data.tar.gz: ac91b8a84e7cdb204905fe05453d63fd7aa23900b3416a5dd60606938156e4a84e05dd9dcee033d18b34ce341096c713865dbff672227545dbefc687991b01e0
|
data/README.md
CHANGED
@@ -1,41 +1,113 @@
|
|
1
|
-
#
|
1
|
+
# PCGRandom
|
2
|
+
[](https://badge.fury.io/rb/pcg_random)
|
2
3
|
|
3
|
-
|
4
|
+
```
|
5
|
+
_____ _____ _____ _____ _
|
6
|
+
| _ | | __| __ |___ ___ _| |___ _____
|
7
|
+
| __| --| | | -| .'| | . | . | |
|
8
|
+
|__| |_____|_____|__|__|__,|_|_|___|___|_|_|_|
|
9
|
+
|
10
|
+
```
|
4
11
|
|
5
|
-
|
12
|
+
Ruby wrappers for the PCGRandom family of random number generators.
|
6
13
|
|
7
14
|
## Installation
|
8
15
|
|
9
|
-
|
16
|
+
### Prerequisites
|
10
17
|
|
11
|
-
|
12
|
-
|
13
|
-
|
18
|
+
* A C-compiler (any modern C compiler is supported on *nix, Windows isn't supported yet)
|
19
|
+
* Modified C source code for pcg_random [available here](https://github.com/vaibhav-y/pcg-c/archive/master.zip) for building libpcg_random.
|
20
|
+
* Follow the build instructions [given here](https://github.com/vaibhav-y/pcg-c#building) to build `libpcg_random`
|
14
21
|
|
15
|
-
|
22
|
+
### Installing the gem:
|
16
23
|
|
17
|
-
|
24
|
+
* Rubygems:
|
18
25
|
|
19
|
-
|
26
|
+
``` bash
|
27
|
+
gem install pcg_random
|
28
|
+
```
|
29
|
+
|
30
|
+
You can also configure the path to `libpcg_random` by specifying it's path explicitly:
|
20
31
|
|
21
|
-
|
32
|
+
``` bash
|
33
|
+
# specify the custome include path
|
34
|
+
gem install pcg_random --with-pcg_random-include=directory/containing/pcg_variants.h
|
22
35
|
|
23
|
-
|
36
|
+
# or, specify the custom path to the libpcg_random binary
|
37
|
+
gem install pcg_random --with-pcg_random-lib=directory/containing/libpcg_random.a
|
24
38
|
|
25
|
-
|
39
|
+
# Or, specify both the lib/ and include/ together to be under path/to/some/directory
|
40
|
+
gem install pcg_random --with-pcg_random-dir=path/to/some/directory
|
41
|
+
```
|
26
42
|
|
27
43
|
## Development
|
44
|
+
`TODO: Create a CONTRIBTING.md`
|
28
45
|
|
29
|
-
|
46
|
+
Install pcg_random *from source* using the above steps. Using the above links are important because the library must be compiled with additional flags to be used for gem-development. There are also some issues in the original repository that are addressed in my fork.
|
30
47
|
|
31
|
-
|
48
|
+
## Using the extension
|
49
|
+
|
50
|
+
Either jump into your REPL of choice:
|
51
|
+
|
52
|
+
``` ruby
|
53
|
+
~$ irb
|
54
|
+
2.3.0 :001 > require 'pcg_random'
|
55
|
+
=> true
|
56
|
+
```
|
57
|
+
|
58
|
+
Or go ahead and try the API, it's built to be as close to `Kernel::Random` as possible!
|
59
|
+
|
60
|
+
``` ruby
|
61
|
+
2.3.0 :002 > seed = PCGRanom.new_seed
|
62
|
+
=> 315431527813695542666700950080169144774
|
63
|
+
2.3.0 :003 > rng = PCGRanom.new 1234
|
64
|
+
=> #<PCGRandom:0x00000001bf3eb0 @seed=1234>
|
65
|
+
```
|
32
66
|
|
33
|
-
|
67
|
+
For detailed instructions, keep checking this repo, I'm working on getting a wiki up.
|
34
68
|
|
35
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/pcg_random.
|
36
69
|
|
70
|
+
## Benchmarks
|
37
71
|
|
38
|
-
|
72
|
+
### PCGRandom.new_seed
|
73
|
+
```
|
74
|
+
Benchmark of Random.new_seed vs PCGRandom.new_seed
|
75
|
+
==================================================
|
76
|
+
|
77
|
+
Benchmark created around: 2016-03-30 14:54:16 +0000
|
78
|
+
|
79
|
+
Running for: 100000 iterations
|
80
|
+
|
81
|
+
Rehearsal ------------------------------------------------------
|
82
|
+
Random.new_seed 0.090000 1.240000 1.330000 ( 1.323970)
|
83
|
+
PCGRandom.new_seed 0.100000 1.150000 1.250000 ( 1.254944)
|
84
|
+
--------------------------------------------- total: 2.580000sec
|
85
|
+
|
86
|
+
user system total real
|
87
|
+
Random.new_seed 0.110000 1.200000 1.310000 ( 1.321571)
|
88
|
+
PCGRandom.new_seed 0.100000 1.130000 1.230000 ( 1.222634)
|
89
|
+
```
|
90
|
+
### PCGRandom.raw_seed(16)
|
91
|
+
```
|
92
|
+
Benchmark of Random.raw_seed(16) vs PCGRandom.raw_seed(16)
|
93
|
+
==================================================
|
94
|
+
|
95
|
+
Benchmark created around: 2016-03-30 14:41:26 +0000
|
96
|
+
|
97
|
+
Running for: 100000 iterations
|
98
|
+
|
99
|
+
Rehearsal ----------------------------------------------------------
|
100
|
+
Random.raw_seed(16) 0.080000 1.440000 1.520000 ( 1.515513)
|
101
|
+
PCGRandom.raw_seed(16) 0.110000 1.320000 1.430000 ( 1.444519)
|
102
|
+
------------------------------------------------- total: 2.950000sec
|
103
|
+
|
104
|
+
user system total real
|
105
|
+
Random.raw_seed(16) 0.080000 1.470000 1.550000 ( 1.563351)
|
106
|
+
PCGRandom.raw_seed(16) 0.090000 1.340000 1.430000 ( 1.441253)
|
107
|
+
```
|
39
108
|
|
40
|
-
|
109
|
+
## Roadmap
|
41
110
|
|
111
|
+
* Achieve full parity with `Kernel::Random`
|
112
|
+
* Get a wiki explaining how to go about using this gem
|
113
|
+
* Showcase benchmarks in some other place
|
data/Rakefile
CHANGED
@@ -1,16 +1,14 @@
|
|
1
1
|
require 'bundler/gem_tasks'
|
2
|
+
require 'bundler'
|
2
3
|
require 'rspec/core/rake_task'
|
3
|
-
|
4
|
-
RSpec::Core::RakeTask.new(:spec)
|
5
|
-
|
6
4
|
require "rake/extensiontask"
|
7
5
|
|
8
|
-
|
6
|
+
RSpec::Core::RakeTask.new(:spec)
|
9
7
|
|
10
8
|
Rake::ExtensionTask.new("pcg_random") do |ext|
|
11
9
|
ext.lib_dir = "lib/pcg_random"
|
12
10
|
end
|
13
11
|
|
12
|
+
task :build => :compile
|
14
13
|
task :cc => [:clean, :compile]
|
15
|
-
|
16
14
|
task :default => [:clobber, :compile, :spec]
|
data/benchmarks/new_seed.md
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
Benchmark of Random.new_seed vs PCGRandom.new_seed
|
3
3
|
==================================================
|
4
4
|
|
5
|
-
Benchmark created around: 2016-03-
|
5
|
+
Benchmark created around: 2016-03-30 14:54:16 +0000
|
6
6
|
|
7
7
|
Running for: 100000 iterations
|
8
8
|
|
9
9
|
Rehearsal ------------------------------------------------------
|
10
|
-
Random.new_seed 0.
|
11
|
-
PCGRandom.new_seed 0.
|
12
|
-
--------------------------------------------- total: 2.
|
10
|
+
Random.new_seed 0.090000 1.240000 1.330000 ( 1.323970)
|
11
|
+
PCGRandom.new_seed 0.100000 1.150000 1.250000 ( 1.254944)
|
12
|
+
--------------------------------------------- total: 2.580000sec
|
13
13
|
|
14
14
|
user system total real
|
15
|
-
Random.new_seed 0.
|
16
|
-
PCGRandom.new_seed 0.
|
15
|
+
Random.new_seed 0.110000 1.200000 1.310000 ( 1.321571)
|
16
|
+
PCGRandom.new_seed 0.100000 1.130000 1.230000 ( 1.222634)
|
17
17
|
```
|
data/benchmarks/raw_seed.md
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
Benchmark of Random.raw_seed(16) vs PCGRandom.raw_seed(16)
|
3
3
|
==================================================
|
4
4
|
|
5
|
-
Benchmark created around: 2016-03-
|
5
|
+
Benchmark created around: 2016-03-30 14:41:26 +0000
|
6
6
|
|
7
7
|
Running for: 100000 iterations
|
8
8
|
|
9
9
|
Rehearsal ----------------------------------------------------------
|
10
|
-
Random.raw_seed(16) 0.
|
11
|
-
PCGRandom.raw_seed(16) 0.
|
12
|
-
------------------------------------------------- total: 2.
|
10
|
+
Random.raw_seed(16) 0.080000 1.440000 1.520000 ( 1.515513)
|
11
|
+
PCGRandom.raw_seed(16) 0.110000 1.320000 1.430000 ( 1.444519)
|
12
|
+
------------------------------------------------- total: 2.950000sec
|
13
13
|
|
14
14
|
user system total real
|
15
|
-
Random.raw_seed(16) 0.
|
16
|
-
PCGRandom.raw_seed(16) 0.
|
15
|
+
Random.raw_seed(16) 0.080000 1.470000 1.550000 ( 1.563351)
|
16
|
+
PCGRandom.raw_seed(16) 0.090000 1.340000 1.430000 ( 1.441253)
|
17
17
|
```
|
data/ext/pcg_random/pcg_random.c
CHANGED
@@ -1,172 +1,20 @@
|
|
1
1
|
#include <ruby.h>
|
2
|
+
#include <ruby/util.h>
|
2
3
|
#include <stdbool.h>
|
3
4
|
#include <stdint.h>
|
5
|
+
#include <limits.h>
|
4
6
|
#include <math.h>
|
5
7
|
#include <pcg_variants.h>
|
6
8
|
|
7
9
|
#include "pcg_random.h"
|
8
10
|
#include "pcg_seed.h"
|
11
|
+
#include "pcg_rng.h"
|
9
12
|
|
10
13
|
VALUE rb_cPCGRandom;
|
11
14
|
|
12
|
-
static void pcg_random_mark(void *ptr);
|
13
|
-
static void pcg_random_free(void *rand_data);
|
14
|
-
static size_t pcg_random_memsize(const void *ptr);
|
15
|
-
static pcg_rb_rand_t *pcg_get_rand_type(VALUE obj);
|
16
|
-
static VALUE pcg_random_alloc(VALUE klass);
|
17
|
-
static VALUE pcg_func_init(int argc, VALUE *argv, VALUE self);
|
18
|
-
static VALUE pcg_func_get_state(VALUE self);
|
19
|
-
static VALUE pcg_func_get_seq(VALUE self);
|
20
|
-
|
21
|
-
/*
|
22
|
-
* Structure wrapping our rng's data type's GC related functions
|
23
|
-
*/
|
24
|
-
static const rb_data_type_t pcg_rand_data_t = {
|
25
|
-
"pcg_random",
|
26
|
-
{
|
27
|
-
pcg_random_mark,
|
28
|
-
pcg_random_free,
|
29
|
-
pcg_random_memsize,
|
30
|
-
},
|
31
|
-
};
|
32
|
-
|
33
|
-
/*
|
34
|
-
* Internal - Mark the internal seed value for garbage collection since a VALUE
|
35
|
-
* inside a C struct is not marked by the GC automatically, and isn't freed
|
36
|
-
* correctly either.
|
37
|
-
*/
|
38
|
-
static void
|
39
|
-
pcg_random_mark(void *ptr)
|
40
|
-
{
|
41
|
-
rb_gc_mark(((pcg_rb_rand_t *) ptr)->seed.val);
|
42
|
-
}
|
43
|
-
|
44
|
-
/*
|
45
|
-
* Internal - Free internal C-types in the `pcg_rb_rand_t` struct
|
46
|
-
*/
|
47
|
-
static void
|
48
|
-
pcg_random_free(void *rand_data)
|
49
|
-
{
|
50
|
-
xfree(((pcg_rb_rand_t *) rand_data)->rng);
|
51
|
-
xfree((pcg_rb_rand_t *)(rand_data));
|
52
|
-
}
|
53
|
-
|
54
|
-
/*
|
55
|
-
* Internal - Get the size of a valid pcg_rb_rand_t pointer
|
56
|
-
*
|
57
|
-
* @return the size of `pcg_rb_rand_t` struct if it is initialized correctly.
|
58
|
-
* 0 if given a NULL pointer
|
59
|
-
*/
|
60
|
-
static size_t
|
61
|
-
pcg_random_memsize(const void *ptr)
|
62
|
-
{
|
63
|
-
return ptr ? sizeof(pcg_rb_rand_t) : 0;
|
64
|
-
}
|
65
|
-
|
66
|
-
/*
|
67
|
-
* Internal - Helper function to get a pointer to a pcg_rb_rand_t struct given
|
68
|
-
* an instance of the `PCGRandom` class
|
69
|
-
*
|
70
|
-
* Returns an object wrapping a C struct, with default initializations
|
71
|
-
*/
|
72
|
-
static pcg_rb_rand_t *
|
73
|
-
pcg_get_rand_type(VALUE obj)
|
74
|
-
{
|
75
|
-
pcg_rb_rand_t *ptr;
|
76
|
-
TypedData_Get_Struct(obj, pcg_rb_rand_t, &pcg_rand_data_t, ptr);
|
77
|
-
return ptr;
|
78
|
-
}
|
79
|
-
|
80
|
-
/*
|
81
|
-
* Memory allocation function that is called by new before `initialize` is
|
82
|
-
* The chain is similar to: `new -> allocate -> initialize`
|
83
|
-
*
|
84
|
-
* Returns an object wrapping a C struct, with default initializations
|
85
|
-
*/
|
86
|
-
static VALUE
|
87
|
-
pcg_random_alloc(VALUE klass)
|
88
|
-
{
|
89
|
-
pcg_rb_rand_t *rand_data;
|
90
|
-
VALUE obj;
|
91
|
-
/*
|
92
|
-
* ISO C forbids braced-groups within expressions
|
93
|
-
* See: http://stackoverflow.com/questions/1238016/
|
94
|
-
*/
|
95
|
-
obj = __extension__ TypedData_Make_Struct(klass, pcg_rb_rand_t, &pcg_rand_data_t, rand_data);
|
96
|
-
|
97
|
-
rand_data->seed.val = INT2FIX(0);
|
98
|
-
rand_data->seed.state = 0;
|
99
|
-
rand_data->seed.seq = 0;
|
100
|
-
rand_data->rng = ALLOC(pcg32_random_t);
|
101
|
-
|
102
|
-
return obj;
|
103
|
-
}
|
104
|
-
|
105
|
-
/*
|
106
|
-
* Internal - Initialize the requested instance using a pre-allocated ruby
|
107
|
-
* object (TypedStruct). Sets the instance variables and relevant accessor
|
108
|
-
* methods where applicable.
|
109
|
-
*/
|
110
|
-
static VALUE
|
111
|
-
pcg_func_init(int argc, VALUE *argv, VALUE self)
|
112
|
-
{
|
113
|
-
VALUE seed;
|
114
|
-
uint64_t cseeds[2];
|
115
|
-
pcg_rb_rand_t* rand_data = pcg_get_rand_type(self);
|
116
|
-
|
117
|
-
if(argc == 0)
|
118
|
-
{
|
119
|
-
seed = DEFAULT_SEED_VALUE;
|
120
|
-
}
|
121
|
-
else
|
122
|
-
{
|
123
|
-
rb_scan_args(argc, argv, "01", &seed);
|
124
|
-
}
|
125
|
-
|
126
|
-
rb_integer_pack(seed, (void *) cseeds, 2, sizeof(uint64_t), 0,
|
127
|
-
INTEGER_PACK_MSWORD_FIRST|INTEGER_PACK_NATIVE_BYTE_ORDER);
|
128
|
-
|
129
|
-
rand_data->seed.val = seed;
|
130
|
-
rand_data->seed.state = cseeds[0];
|
131
|
-
rand_data->seed.seq = cseeds[1];
|
132
|
-
pcg32_srandom_r(rand_data->rng, cseeds[0], cseeds[1]);
|
133
|
-
|
134
|
-
/* Add & set private instance variables */
|
135
|
-
rb_iv_set(self, "@seed", seed);
|
136
|
-
rb_iv_set(self, "state", LONG2NUM(rand_data->seed.state));
|
137
|
-
rb_iv_set(self, "sequence", LONG2NUM(rand_data->seed.seq));
|
138
|
-
return self;
|
139
|
-
}
|
140
|
-
|
141
|
-
/*
|
142
|
-
* Internal - Private method to access internal rng state parameter
|
143
|
-
* (Most significant word of seed)
|
144
|
-
*/
|
145
|
-
static VALUE
|
146
|
-
pcg_func_get_state(VALUE self)
|
147
|
-
{
|
148
|
-
VALUE state;
|
149
|
-
state = rb_iv_get(self, "state");
|
150
|
-
return state;
|
151
|
-
}
|
152
|
-
|
153
|
-
/*
|
154
|
-
* Internal - Private method to access internal rng state parameter
|
155
|
-
* (Most significant word of seed)
|
156
|
-
*/
|
157
|
-
static VALUE
|
158
|
-
pcg_func_get_seq(VALUE self)
|
159
|
-
{
|
160
|
-
VALUE seq;
|
161
|
-
seq = rb_iv_get(self, "sequence");
|
162
|
-
return seq;
|
163
|
-
}
|
164
|
-
|
165
15
|
void
|
166
16
|
Init_pcg_random(void)
|
167
17
|
{
|
168
|
-
/* Initializations */
|
169
|
-
|
170
18
|
/* Constants / Classes */
|
171
19
|
rb_cPCGRandom = rb_define_class("PCGRandom", rb_cObject);
|
172
20
|
|
@@ -176,18 +24,14 @@ Init_pcg_random(void)
|
|
176
24
|
rb_define_singleton_method(rb_cPCGRandom, "new_seed", pcg_func_new_seed, 0);
|
177
25
|
rb_define_singleton_method(rb_cPCGRandom, "raw_seed", pcg_func_raw_seed, 1);
|
178
26
|
|
179
|
-
/*
|
27
|
+
/* Instance methods */
|
180
28
|
rb_define_alloc_func(rb_cPCGRandom, pcg_random_alloc);
|
181
|
-
rb_define_attr(rb_cPCGRandom, "seed", 1, 0);
|
182
|
-
// rb_define_method(rb_cPCGRandom, "rand", pcg_func_rand, -1);
|
183
|
-
// rb_define_method(rb_cPCGRandom, "bytes", pcg_func_rand_bytes, 1);
|
184
|
-
// rb_define_method(rb_cPCGRandom, "initialize_copy", pcg_func_rand_copy, 1);
|
185
|
-
// rb_define_method(rb_cPCGRandom, "==", pcg_func_equal, 1);
|
186
|
-
|
187
|
-
/* Private instance methods */
|
188
29
|
rb_define_method(rb_cPCGRandom, "initialize", pcg_func_init, -1);
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
30
|
+
|
31
|
+
rb_define_attr(rb_cPCGRandom, "seed", 1, 0);
|
32
|
+
|
33
|
+
rb_define_method(rb_cPCGRandom, "rand", pcg_func_rand, -1);
|
34
|
+
rb_define_method(rb_cPCGRandom, "bytes", pcg_func_rand_bytes, 1);
|
35
|
+
|
36
|
+
rb_define_method(rb_cPCGRandom, "==", pcg_func_eql, 1);
|
193
37
|
}
|
data/ext/pcg_random/pcg_random.h
CHANGED
@@ -2,21 +2,7 @@
|
|
2
2
|
#define PCG_RANDOM_H 1
|
3
3
|
|
4
4
|
#include <ruby.h>
|
5
|
-
#include <stdint.h>
|
6
5
|
|
7
6
|
extern VALUE rb_cPCGRandom;
|
8
7
|
|
9
|
-
struct pcg_rb_seed
|
10
|
-
{
|
11
|
-
VALUE val;
|
12
|
-
uint64_t state;
|
13
|
-
uint64_t seq;
|
14
|
-
};
|
15
|
-
|
16
|
-
typedef struct
|
17
|
-
{
|
18
|
-
struct pcg_rb_seed seed;
|
19
|
-
pcg32_random_t *rng;
|
20
|
-
} pcg_rb_rand_t;
|
21
|
-
|
22
8
|
#endif /* PCG_RANDOM_H */
|
@@ -0,0 +1,248 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include <ruby/util.h>
|
3
|
+
#include <stdbool.h>
|
4
|
+
#include <stdint.h>
|
5
|
+
#include <limits.h>
|
6
|
+
#include <math.h>
|
7
|
+
#include <pcg_variants.h>
|
8
|
+
|
9
|
+
#include "pcg_random.h"
|
10
|
+
#include "pcg_seed.h"
|
11
|
+
#include "pcg_rng.h"
|
12
|
+
|
13
|
+
VALUE rb_cPCGRandom;
|
14
|
+
|
15
|
+
static void pcg_random_mark(void *ptr);
|
16
|
+
static void pcg_random_free(void *rand_data);
|
17
|
+
|
18
|
+
static size_t pcg_random_memsize(const void *ptr);
|
19
|
+
|
20
|
+
static VALUE pcg_rb_float64_rand(pcg32_random_t *rng);
|
21
|
+
|
22
|
+
/*
|
23
|
+
* Structure wrapping our rng's data type's GC related functions
|
24
|
+
*/
|
25
|
+
static const rb_data_type_t pcg_rand_data_t = {
|
26
|
+
"pcg_random",
|
27
|
+
{
|
28
|
+
pcg_random_mark,
|
29
|
+
pcg_random_free,
|
30
|
+
pcg_random_memsize,
|
31
|
+
},
|
32
|
+
};
|
33
|
+
|
34
|
+
/*
|
35
|
+
* Internal - Mark the internal seed value for garbage collection since a VALUE
|
36
|
+
* inside a C struct is not marked by the GC automatically, and isn't freed
|
37
|
+
* correctly either.
|
38
|
+
*/
|
39
|
+
static void
|
40
|
+
pcg_random_mark(void *ptr)
|
41
|
+
{
|
42
|
+
rb_gc_mark(((pcg_rb_rand_t *) ptr)->seed.val);
|
43
|
+
}
|
44
|
+
|
45
|
+
/*
|
46
|
+
* Internal - Free internal C-types in the `pcg_rb_rand_t` struct
|
47
|
+
*/
|
48
|
+
static void
|
49
|
+
pcg_random_free(void *rand_data)
|
50
|
+
{
|
51
|
+
xfree(((pcg_rb_rand_t *) rand_data)->rng);
|
52
|
+
xfree(rand_data);
|
53
|
+
}
|
54
|
+
|
55
|
+
/*
|
56
|
+
* Internal - Get the size of a valid pcg_rb_rand_t pointer
|
57
|
+
*
|
58
|
+
* @return the size of `pcg_rb_rand_t` struct if it is initialized correctly.
|
59
|
+
* 0 if given a NULL pointer
|
60
|
+
*/
|
61
|
+
static size_t
|
62
|
+
pcg_random_memsize(const void *ptr)
|
63
|
+
{
|
64
|
+
return ptr ? sizeof(pcg_rb_rand_t) : 0;
|
65
|
+
}
|
66
|
+
|
67
|
+
/*
|
68
|
+
* Internal - Helper function to get a pointer to a pcg_rb_rand_t struct given
|
69
|
+
* an instance of the `PCGRandom` class
|
70
|
+
*
|
71
|
+
* Returns an object wrapping a C struct, with default initializations
|
72
|
+
*/
|
73
|
+
pcg_rb_rand_t *
|
74
|
+
pcg_get_rand_type(VALUE obj)
|
75
|
+
{
|
76
|
+
pcg_rb_rand_t *ptr;
|
77
|
+
TypedData_Get_Struct(obj, pcg_rb_rand_t, &pcg_rand_data_t, ptr);
|
78
|
+
return ptr;
|
79
|
+
}
|
80
|
+
|
81
|
+
/*
|
82
|
+
* Memory allocation function that is called by `new` before `initialize` is
|
83
|
+
* The chain is similar to: `new -> allocate -> initialize`
|
84
|
+
*
|
85
|
+
* Returns an object wrapping a C struct, with default initializations
|
86
|
+
*/
|
87
|
+
VALUE
|
88
|
+
pcg_random_alloc(VALUE klass)
|
89
|
+
{
|
90
|
+
pcg_rb_rand_t *rand_data;
|
91
|
+
VALUE obj;
|
92
|
+
/*
|
93
|
+
* ISO C forbids braced-groups within expressions
|
94
|
+
* See: http://stackoverflow.com/questions/1238016/
|
95
|
+
*/
|
96
|
+
obj = __extension__ TypedData_Make_Struct(klass, pcg_rb_rand_t, &pcg_rand_data_t, rand_data);
|
97
|
+
|
98
|
+
rand_data->seed.val = INT2FIX(0);
|
99
|
+
rand_data->seed.state = 0;
|
100
|
+
rand_data->seed.seq = 0;
|
101
|
+
rand_data->rng = ALLOC(pcg32_random_t);
|
102
|
+
|
103
|
+
return obj;
|
104
|
+
}
|
105
|
+
|
106
|
+
/*
|
107
|
+
* Initialize the requested instance using a pre-allocated ruby
|
108
|
+
* object (TypedStruct). Sets the instance variables and relevant accessor
|
109
|
+
* methods where applicable.
|
110
|
+
*
|
111
|
+
* @param seed [Fixnum, Bignum] The seed to use use for initilization
|
112
|
+
*
|
113
|
+
* @raise TypeError unless parameters are Fixnum / Bignum
|
114
|
+
*/
|
115
|
+
VALUE
|
116
|
+
pcg_func_init(int argc, VALUE *argv, VALUE self)
|
117
|
+
{
|
118
|
+
VALUE seed;
|
119
|
+
uint64_t cseeds[2];
|
120
|
+
pcg_rb_rand_t* rand_data = pcg_get_rand_type(self);
|
121
|
+
|
122
|
+
if(argc == 0)
|
123
|
+
{
|
124
|
+
seed = DEFAULT_SEED_VALUE;
|
125
|
+
}
|
126
|
+
else
|
127
|
+
{
|
128
|
+
rb_scan_args(argc, argv, "01", &seed);
|
129
|
+
}
|
130
|
+
|
131
|
+
if( !(RB_TYPE_P(seed, T_FIXNUM) || RB_TYPE_P(seed, T_BIGNUM)) )
|
132
|
+
{
|
133
|
+
rb_raise(rb_eTypeError,"Expected Fixnum or Bignum, found %s",
|
134
|
+
rb_obj_classname(seed));
|
135
|
+
}
|
136
|
+
|
137
|
+
rb_integer_pack(seed, (void *) cseeds, 2, sizeof(uint64_t), 0,
|
138
|
+
INTEGER_PACK_MSWORD_FIRST|INTEGER_PACK_NATIVE_BYTE_ORDER);
|
139
|
+
|
140
|
+
rand_data->seed.val = seed;
|
141
|
+
rand_data->seed.state = cseeds[0];
|
142
|
+
rand_data->seed.seq = cseeds[1];
|
143
|
+
pcg32_srandom_r(rand_data->rng, cseeds[0], cseeds[1]);
|
144
|
+
|
145
|
+
/* Add & set private instance variables */
|
146
|
+
rb_iv_set(self, "@seed", seed);
|
147
|
+
rb_iv_set(self, "state", LONG2NUM(rand_data->seed.state));
|
148
|
+
rb_iv_set(self, "sequence", LONG2NUM(rand_data->seed.seq));
|
149
|
+
return self;
|
150
|
+
}
|
151
|
+
|
152
|
+
/*
|
153
|
+
* Get a random string of the given length
|
154
|
+
*
|
155
|
+
* @param max The upperbound on numbers to generate
|
156
|
+
*/
|
157
|
+
VALUE
|
158
|
+
pcg_func_rand_bytes(VALUE self, VALUE size)
|
159
|
+
{
|
160
|
+
VALUE result;
|
161
|
+
pcg_rb_rand_t *rdata = pcg_get_rand_type(self);
|
162
|
+
size_t len = NUM2ULONG(size);
|
163
|
+
char *str = ALLOC_N(char, len);
|
164
|
+
|
165
|
+
for(int i = 0; i < len; ++i)
|
166
|
+
{
|
167
|
+
str[i] = (char) pcg32_boundedrand_r(rdata->rng, CHAR_MAX);
|
168
|
+
}
|
169
|
+
result = rb_str_new(str, len);
|
170
|
+
xfree(str);
|
171
|
+
return result;
|
172
|
+
}
|
173
|
+
|
174
|
+
/*
|
175
|
+
* Return a random number between 0 and 1
|
176
|
+
*
|
177
|
+
* @param max Upper bound for the rng or the range of values that are acceptable
|
178
|
+
*/
|
179
|
+
VALUE
|
180
|
+
pcg_func_rand(int argc, VALUE *argv, VALUE self)
|
181
|
+
{
|
182
|
+
VALUE max, result;
|
183
|
+
long ubound;
|
184
|
+
double num, lim;
|
185
|
+
pcg_rb_rand_t *rdata = pcg_get_rand_type(self);
|
186
|
+
|
187
|
+
if(argc == 0)
|
188
|
+
{
|
189
|
+
return pcg_rb_float64_rand(rdata->rng);
|
190
|
+
}
|
191
|
+
|
192
|
+
rb_scan_args(argc, argv, "01", &max);
|
193
|
+
|
194
|
+
switch(TYPE(max))
|
195
|
+
{
|
196
|
+
case T_FIXNUM:
|
197
|
+
ubound = FIX2LONG(max);
|
198
|
+
return LONG2FIX(pcg32_boundedrand_r(rdata->rng, ubound));
|
199
|
+
case T_FLOAT:
|
200
|
+
num = ldexp((double) pcg32_boundedrand_r(rdata->rng, UINT32_MAX), -32);
|
201
|
+
lim = NUM2DBL(max);
|
202
|
+
return DBL2NUM(num * lim);
|
203
|
+
case T_BIGNUM:
|
204
|
+
num = ldexp((double) pcg32_boundedrand_r(rdata->rng, UINT32_MAX), -32);
|
205
|
+
result = rb_big_mul(max, DBL2NUM(num));
|
206
|
+
return rb_funcall(result, rb_intern("floor"), 0);
|
207
|
+
break;
|
208
|
+
case T_NIL:
|
209
|
+
rb_raise(rb_eArgError, "Invalid argument - nil");
|
210
|
+
break;
|
211
|
+
default:
|
212
|
+
rb_raise(rb_eTypeError, "Argument of type %s not supported (yet)",
|
213
|
+
rb_obj_classname(max));
|
214
|
+
}
|
215
|
+
return Qnil;
|
216
|
+
}
|
217
|
+
|
218
|
+
/*
|
219
|
+
* Return a random number in [0, 1) with double precision rounded to the closest
|
220
|
+
* multiple for 1/(2**64)
|
221
|
+
*/
|
222
|
+
static VALUE
|
223
|
+
pcg_rb_float64_rand(pcg32_random_t *rng)
|
224
|
+
{
|
225
|
+
double d = ldexp((double) pcg32_boundedrand_r(rng, UINT32_MAX), -32);
|
226
|
+
return DBL2NUM(d);
|
227
|
+
}
|
228
|
+
|
229
|
+
/*
|
230
|
+
* Compares two instances of the class, returns true if they had the same
|
231
|
+
* initial state
|
232
|
+
*
|
233
|
+
* @param other [Object] Object to compare this instance to
|
234
|
+
*
|
235
|
+
* @return
|
236
|
+
*/
|
237
|
+
VALUE
|
238
|
+
pcg_func_eql(VALUE self, VALUE other)
|
239
|
+
{
|
240
|
+
VALUE s, o;
|
241
|
+
if( !strcmp(rb_obj_classname(self), rb_obj_classname(other)) )
|
242
|
+
{
|
243
|
+
s = rb_iv_get(self, "@seed");
|
244
|
+
o = rb_iv_get(other, "@seed");
|
245
|
+
return rb_funcall(s, rb_intern("=="), 1, o);
|
246
|
+
}
|
247
|
+
return Qfalse;
|
248
|
+
}
|
@@ -0,0 +1,29 @@
|
|
1
|
+
#ifndef PCG_RNG_H
|
2
|
+
#define PCG_RNG_H 1
|
3
|
+
|
4
|
+
#include <ruby.h>
|
5
|
+
#include <stdint.h>
|
6
|
+
|
7
|
+
struct pcg_rb_seed
|
8
|
+
{
|
9
|
+
VALUE val;
|
10
|
+
uint64_t state;
|
11
|
+
uint64_t seq;
|
12
|
+
};
|
13
|
+
|
14
|
+
typedef struct
|
15
|
+
{
|
16
|
+
struct pcg_rb_seed seed;
|
17
|
+
pcg32_random_t *rng;
|
18
|
+
} pcg_rb_rand_t;
|
19
|
+
|
20
|
+
|
21
|
+
pcg_rb_rand_t *pcg_get_rand_type(VALUE obj);
|
22
|
+
|
23
|
+
VALUE pcg_random_alloc(VALUE klass);
|
24
|
+
VALUE pcg_func_init(int argc, VALUE *argv, VALUE self);
|
25
|
+
VALUE pcg_func_rand(int argc, VALUE *argv, VALUE self);
|
26
|
+
VALUE pcg_func_rand_bytes(VALUE self, VALUE size);
|
27
|
+
VALUE pcg_func_eql(VALUE self, VALUE other);
|
28
|
+
|
29
|
+
#endif /* PCG_RNG_H */
|
data/lib/pcg_random/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pcg_random
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vaibhav Yenamandra
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-04-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -108,6 +108,8 @@ files:
|
|
108
108
|
- ext/pcg_random/extconf.rb
|
109
109
|
- ext/pcg_random/pcg_random.c
|
110
110
|
- ext/pcg_random/pcg_random.h
|
111
|
+
- ext/pcg_random/pcg_rng.c
|
112
|
+
- ext/pcg_random/pcg_rng.h
|
111
113
|
- ext/pcg_random/pcg_seed.c
|
112
114
|
- ext/pcg_random/pcg_seed.h
|
113
115
|
- ext/pcg_random/pcg_spinlock.h
|