回答編集履歴

5

別解3を追加

2017/02/04 13:06

投稿

raccy
raccy

スコア21735

test CHANGED
@@ -209,3 +209,29 @@
209
209
  ```
210
210
 
211
211
 
212
+
213
+ ---
214
+
215
+ 【別解3】
216
+
217
+ -1は奇数乗か偶数乗かだけで切り替わることに気付いた。
218
+
219
+
220
+
221
+ ```JavaScript
222
+
223
+ let val = (x => ((-1)**x * ((x - x % 2) / 2 + 1)))(Math.floor(6 * Math.random()));
224
+
225
+ ```
226
+
227
+
228
+
229
+ IE等の古いブラウザ用に書き直すと
230
+
231
+
232
+
233
+ ```JavaScript
234
+
235
+ var val = function (x) {return Math.pow(-1, x) * ((x - x % 2) / 2 + 1);}(Math.floor(6 * Math.random()));
236
+
237
+ ```

4

説明がちょっとおかしかったのを修正

2017/02/04 13:06

投稿

raccy
raccy

スコア21735

test CHANGED
@@ -190,7 +190,7 @@
190
190
 
191
191
  ```
192
192
 
193
- これに最初の2nを掛けて床関数をとって2足すをMath.random()にしたものを与えるようる。
193
+ これに最初の2nを掛けて床関数で整数化したものを与えると[0,1)を均等配分できる。
194
194
 
195
195
  ```JavaScript
196
196
 

3

別解2が整数の最大値を超える場合がるため、修正。

2017/02/04 12:52

投稿

raccy
raccy

スコア21735

test CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  1. 乱数生成は1度のみ行う。
4
4
 
5
- 2. 任意の整数`n`に対して、`-n`, `-n+1`, ... `-2`, `-1`, `1`, `2`, ... `n-1`, `n`の計n*2個の整数の内一つを返す。ランダム性は1.で生成した乱数を用いること。ただし、`n`は`1`以上`2**52-1`以下とする。(`2**52`以上の場合は`2*n`が`Number.MAX_SEFE_INTEGER`を越えるため)
5
+ 2. 任意の整数`n`に対して、`-n`, `-n+1`, ... `-2`, `-1`, `1`, `2`, ... `n-1`, `n`の計n*2個の整数の内一つを返す。ランダム性は1.で生成した乱数を用いること。ただし、`n`は`1`以上`2**52-1`以下とする。(`2**52`以上の場合は`2*n`が`Number.MAX_SAFE_INTEGER`を越えるため)
6
6
 
7
7
 
8
8
 
@@ -118,15 +118,19 @@
118
118
 
119
119
  【別解2】
120
120
 
121
+ ※ 途中の演算で`Math.MAX_SAFE_INTEGER`を越える場合があるため修正。
122
+
123
+
124
+
121
125
  Math.floorを一回だけにする方法を考える。他にも演算はなるべく1回とする。
122
126
 
123
127
 
124
128
 
125
- 2n倍したものにfloorをとり、2を足せば2, 3, ... 2n, 2n+1になる。
129
+ 2n倍したものにfloorをとると0, 1, ... 2n-2, 2n-1になる。
126
130
 
127
131
  これを2を除数とした商と剰余を考えると、下記になる。
128
132
 
129
- 商: 1, 1, 2, 2, ... 2n-1, 2n-1, 2n, 2n
133
+ 商: 0, 0, 1, 1, ... 2n-2, 2n-2, 2n-1, 2n-1
130
134
 
131
135
  剰余: 0, 1, 0, 1, ... 0, 1, 0, 1
132
136
 
@@ -134,7 +138,7 @@
134
138
 
135
139
  剰余: 0, 1, 0, 1, ... 0, 1, 0, 1 => 1, -1, 1, -1 ... 1, -1, 1, -1
136
140
 
137
- が得られるため、後は商と掛ければ、
141
+ が得られるため、後は商に1足した物と掛ければ、
138
142
 
139
143
  1, -1, 2, -2, ... 2n-1, -2n+1, 2n, -2n
140
144
 
@@ -148,7 +152,7 @@
148
152
 
149
153
  // q 商、r 剰余
150
154
 
151
- const g = r => q => (-1)**r * q;
155
+ const g = r => q => (-1)**r * (q + 1);
152
156
 
153
157
  ```
154
158
 
@@ -174,15 +178,15 @@
174
178
 
175
179
  // 関数を展開する。
176
180
 
177
- const f = x => (r_ => (r => q => (-1)**r * q)(r)((d => m => r => (d - r) / m)(x)(2)(r_)))(x % 2);
181
+ const f = x => (r_ => (r => q => (-1)**r * (q + 1))(r)((d => m => r => (d - r) / m)(x)(2)(r_)))(x % 2);
178
182
 
179
183
  // rはr_と同じ、xとdは同じであり、mは2固定で冗長のためまとめる。
180
184
 
181
- const f = x => (r => (q => (-1)**r * q)((m => (x - r) / 2)()))(x % 2);
185
+ const f = x => (r => (q => (-1)**r * (q + 1))((m => (x - r) / 2)()))(x % 2);
182
186
 
183
187
  // 固定の所は評価をしてしまって。qもなくす。
184
188
 
185
- const f = x => (r => (x - r) / 2 * (-1)**r)(x % 2);
189
+ const f = x => (r => ((-1)**r * ((x - r) / 2 + 1)))(x % 2);
186
190
 
187
191
  ```
188
192
 
@@ -190,7 +194,7 @@
190
194
 
191
195
  ```JavaScript
192
196
 
193
- const f_ = n => y => (x => (r => (x - r) / 2 * (-1)**r)(x % 2))(Math.floor(2 * n * y) + 2);
197
+ const f_ = n => y => (x => (r => ((-1)**r * ((x - r) / 2 + 1)))(x % 2))(Math.floor(2 * n * y));
194
198
 
195
199
  ```
196
200
 
@@ -200,8 +204,8 @@
200
204
 
201
205
  ```JavaScript
202
206
 
203
- let val = (n => y => (x => (r => (x - r) / 2 * (-1)**r)(x % 2))(Math.floor(2 * n * y) + 2))(3)(Math.random());
207
+ let val = (n => y => (x => (r => ((-1)**r * ((x - r) / 2 + 1)))(x % 2))(Math.floor(2 * n * y)))(3)(Math.random());
204
-
208
+
205
- ```
209
+ ```
206
-
207
-
210
+
211
+

2

別解2を追加

2017/02/04 04:37

投稿

raccy
raccy

スコア21735

test CHANGED
@@ -111,3 +111,97 @@
111
111
  ```
112
112
 
113
113
  となる。
114
+
115
+
116
+
117
+ ---
118
+
119
+ 【別解2】
120
+
121
+ Math.floorを一回だけにする方法を考える。他にも演算はなるべく1回とする。
122
+
123
+
124
+
125
+ 2n倍したものにfloorをとり、2を足せば2, 3, ... 2n, 2n+1になる。
126
+
127
+ これを2を除数とした商と剰余を考えると、下記になる。
128
+
129
+ 商: 1, 1, 2, 2, ... 2n-1, 2n-1, 2n, 2n
130
+
131
+ 剰余: 0, 1, 0, 1, ... 0, 1, 0, 1
132
+
133
+ つまり、剰余部分は-1を底にしてその値を冪指数にした冪を求めれば
134
+
135
+ 剰余: 0, 1, 0, 1, ... 0, 1, 0, 1 => 1, -1, 1, -1 ... 1, -1, 1, -1
136
+
137
+ が得られるため、後は商と掛ければ、
138
+
139
+ 1, -1, 2, -2, ... 2n-1, -2n+1, 2n, -2n
140
+
141
+ が得られる。
142
+
143
+
144
+
145
+ JavaScriptにすると次のような関数になる。
146
+
147
+ ```JavaScript
148
+
149
+ // q 商、r 剰余
150
+
151
+ const g = r => q => (-1)**r * q;
152
+
153
+ ```
154
+
155
+ JavaScriptには商を直接求める演算子や関数がないため剰余から求める関数を考える。
156
+
157
+ ```JavaScript
158
+
159
+ // d 被除数、m 除数
160
+
161
+ const h = d => m => r => (d - r) / m;
162
+
163
+ ```
164
+
165
+ 除数は2で固定であるため、これを用いると次のようになり、展開しながら変形していく。
166
+
167
+ ```JavaScript
168
+
169
+ const f = x => g(x % 2)(h(x)(2)(x % 2));
170
+
171
+ // `x % 2`は冗長のためさらに書き替える。
172
+
173
+ const f = x => (r => g(r)(h(x)(2)(r)))(x % 2);
174
+
175
+ // 関数を展開する。
176
+
177
+ const f = x => (r_ => (r => q => (-1)**r * q)(r)((d => m => r => (d - r) / m)(x)(2)(r_)))(x % 2);
178
+
179
+ // rはr_と同じ、xとdは同じであり、mは2固定で冗長のためまとめる。
180
+
181
+ const f = x => (r => (q => (-1)**r * q)((m => (x - r) / 2)()))(x % 2);
182
+
183
+ // 固定の所は評価をしてしまって。qもなくす。
184
+
185
+ const f = x => (r => (x - r) / 2 * (-1)**r)(x % 2);
186
+
187
+ ```
188
+
189
+ これに最初の2nを掛けて床関数をとって2足すをMath.random()にしたものを与えるようにする。
190
+
191
+ ```JavaScript
192
+
193
+ const f_ = n => y => (x => (r => (x - r) / 2 * (-1)**r)(x % 2))(Math.floor(2 * n * y) + 2);
194
+
195
+ ```
196
+
197
+
198
+
199
+ n=3のときのため、最終的に次のようになる。
200
+
201
+ ```JavaScript
202
+
203
+ let val = (n => y => (x => (r => (x - r) / 2 * (-1)**r)(x % 2))(Math.floor(2 * n * y) + 2))(3)(Math.random());
204
+
205
+ ```
206
+
207
+

1

別解を追加

2017/02/04 00:01

投稿

raccy
raccy

スコア21735

test CHANGED
@@ -56,4 +56,58 @@
56
56
 
57
57
 
58
58
 
59
- 数学っぽく考えたつもりですが、`Math.random()`がまったく数学っぽくない時点でなんとも言えないです。
59
+ 数学っぽく考えたつもりですが、`Math.random()`に副作用あるのでまったく数学っぽくない時点でなんとも言えないです。
60
+
61
+
62
+
63
+ ---
64
+
65
+
66
+
67
+ 【別解】
68
+
69
+ [0,1) => -n, -n+1, ... -2, -1, 1, 2, ... n-1, n
70
+
71
+ となる写像関数を直接考える。
72
+
73
+
74
+
75
+ 1. 2倍すれば[0,2)となるため、[0,1), [1,2)に分離でき、floorをとれば0, 1になる。
76
+
77
+ 2. -1を底、1.の値を冪指数とする冪を求めると、1, -1になる。
78
+
79
+ 3. 2n倍すれば[0,2n)となるため、[0,1), [1,2), ... [n-1, n), [n, n+1), ... [2n-2,2n-1), [2n-1,2n)に分離でき、floorをとれば0, 1, ... n-1, n, ... 2n-2, 2n-1となる。
80
+
81
+ このうちの前半は1.の0(2.の1)に、後半は1.の1(2.の-1)に相当する。
82
+
83
+ 4. さらにnでの余りを求めると0, 1, ... n-1, 0, ... n-2, n-1と前半と後半が同じである。
84
+
85
+ 5. さらに1足せば1, 2, ... n, 1, ... n-1, nとなる。
86
+
87
+ 6. 2.と5.を組み合わせれば、目的の写像が得られる。
88
+
89
+ f(n)(x) = (-1)^[2x]*([2nx]%n+1)
90
+
91
+ ※ fはカリー化されている。^ ... 冪乗。[z] ... ガウス記号、床関数。% ... 剰余。
92
+
93
+
94
+
95
+ これをJavaScriptで表すと下記になる。
96
+
97
+ ```JavaScript
98
+
99
+ const f = n => x => (-1)**Math.floor(2 * x) * (Math.floor(2 * n * x) % n + 1)
100
+
101
+ ```
102
+
103
+
104
+
105
+ 写像関数が得られたので、n=3の時にxが[0,1)分布の乱数を与えることで答えは
106
+
107
+ ```JavaScript
108
+
109
+ let v = (n => x => (-1)**Math.floor(2 * x) * (Math.floor(2 * n * x) % n + 1))(3)(Math.random());
110
+
111
+ ```
112
+
113
+ となる。