pcg_random 0.1.4 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e26f09fa3ea5290710f41975fcf1a22e4265e794
4
- data.tar.gz: 792f5b3ffddb3c984d58aa93c8146443e7837682
3
+ metadata.gz: e613759fc11837de964926f2067b38d770100cd6
4
+ data.tar.gz: c72b3c2996301edeeb5084c5d785342219c99b59
5
5
  SHA512:
6
- metadata.gz: 8bf992989aa751a8cd99dc153f78469dc3da4c16b6e2ec3e8dc8a8589aaa1407d0f78b42b9b1a33123ef6b0b83b3b700853afbac5bb23ccc9151e799cd8d7b92
7
- data.tar.gz: 8addc87f54888e50b8bdeb08f6959da746054f5d8014c498842121596b6b0c64c314d1b5cd841fd650a97924cc6a69778cd2f36633428b1a352fd0f801ac73b4
6
+ metadata.gz: 9dd5e22f22437be3e1cf6fa105f984d12cda521462e284a14d373d1f7c3b45b029a07e84a099f2fdbc833e54fe0748dd69f05f972119fa015a6f7c8da5e1754c
7
+ data.tar.gz: ac91b8a84e7cdb204905fe05453d63fd7aa23900b3416a5dd60606938156e4a84e05dd9dcee033d18b34ce341096c713865dbff672227545dbefc687991b01e0
data/README.md CHANGED
@@ -1,41 +1,113 @@
1
- # PcgRandom
1
+ # PCGRandom
2
+ [![Gem Version](https://badge.fury.io/rb/pcg_random.svg)](https://badge.fury.io/rb/pcg_random)
2
3
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/pcg_random`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+ ```
5
+ _____ _____ _____ _____ _
6
+ | _ | | __| __ |___ ___ _| |___ _____
7
+ | __| --| | | -| .'| | . | . | |
8
+ |__| |_____|_____|__|__|__,|_|_|___|___|_|_|_|
9
+
10
+ ```
4
11
 
5
- TODO: Delete this and the text above, and describe your gem
12
+ Ruby wrappers for the PCGRandom family of random number generators.
6
13
 
7
14
  ## Installation
8
15
 
9
- Add this line to your application's Gemfile:
16
+ ### Prerequisites
10
17
 
11
- ```ruby
12
- gem 'pcg_random'
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
- And then execute:
22
+ ### Installing the gem:
16
23
 
17
- $ bundle
24
+ * Rubygems:
18
25
 
19
- Or install it yourself as:
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
- $ gem install pcg_random
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
- ## Usage
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
- TODO: Write usage instructions here
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
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
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
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
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
- ## Contributing
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
- ## License
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
- The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
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
- task :build => :compile
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]
@@ -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-25 18:27:27 +0000
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.120000 1.060000 1.180000 ( 1.173928)
11
- PCGRandom.new_seed 0.070000 1.020000 1.090000 ( 1.096108)
12
- --------------------------------------------- total: 2.270000sec
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.100000 1.090000 1.190000 ( 1.188864)
16
- PCGRandom.new_seed 0.110000 1.090000 1.200000 ( 1.197528)
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
  ```
@@ -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-25 18:27:35 +0000
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.040000 0.980000 1.020000 ( 1.031410)
11
- PCGRandom.raw_seed(16) 0.050000 0.970000 1.020000 ( 1.021024)
12
- ------------------------------------------------- total: 2.040000sec
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.090000 0.990000 1.080000 ( 1.076778)
16
- PCGRandom.raw_seed(16) 0.060000 1.000000 1.060000 ( 1.067268)
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
  ```
@@ -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
- /* Public instance methods */
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
- // rb_define_private_method(rb_cPCGRandom, "marshal_dump", pcg_func_dump, 0);
190
- // rb_define_private_method(rb_cPCGRandom, "marshal_load", pcg_func_load, 1);
191
- rb_define_private_method(rb_cPCGRandom, "state", pcg_func_get_state, 0);
192
- rb_define_private_method(rb_cPCGRandom, "sequence", pcg_func_get_seq, 0);
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
  }
@@ -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 */
@@ -1,3 +1,3 @@
1
1
  class PCGRandom
2
- VERSION = "0.1.4"
2
+ VERSION = "0.1.6"
3
3
  end
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
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-03-30 00:00:00.000000000 Z
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