@@ -10,19 +10,23 @@ module mir.math.numeric;
10
10
import mir.math.common;
11
11
import mir.primitives;
12
12
import mir.primitives: isInputRange;
13
- import std.traits : CommonType, Unqual, isIterable, ForeachType, isPointer, isNumeric ;
13
+ import std.traits : CommonType, Unqual, isIterable, ForeachType, isPointer;
14
14
import mir.internal.utility: isFloatingPoint;
15
15
16
- deprecated ( " Use mir.bignum.fp.Fp!128 instead. " )
16
+ // /
17
17
struct ProdAccumulator (T)
18
18
if (isFloatingPoint! T)
19
19
{
20
20
alias F = Unqual! T;
21
21
22
+ // /
22
23
long exp = 1L ;
24
+ // /
23
25
F x = cast (F) 0.5 ;
26
+ // /
24
27
alias mantissa = x;
25
28
29
+ // /
26
30
@safe pure @nogc nothrow
27
31
this (F value)
28
32
{
@@ -33,13 +37,15 @@ struct ProdAccumulator(T)
33
37
this .exp = lexp;
34
38
}
35
39
40
+ // /
36
41
@safe pure @nogc nothrow
37
42
this (long exp, F x)
38
43
{
39
44
this .exp = exp;
40
45
this .x = x;
41
46
}
42
47
48
+ // /
43
49
@safe pure @nogc nothrow
44
50
void put (U)(U e)
45
51
if (is (U : T))
@@ -60,6 +66,7 @@ struct ProdAccumulator(T)
60
66
}
61
67
}
62
68
69
+ // /
63
70
@safe pure @nogc nothrow
64
71
void put (ProdAccumulator! T value)
65
72
{
@@ -72,6 +79,7 @@ struct ProdAccumulator(T)
72
79
}
73
80
}
74
81
82
+ // /
75
83
void put (Range )(Range r)
76
84
if (isIterable! Range )
77
85
{
@@ -101,6 +109,7 @@ struct ProdAccumulator(T)
101
109
}
102
110
}
103
111
112
+ // /
104
113
@safe pure @nogc nothrow
105
114
T prod () const scope @property
106
115
{
@@ -112,27 +121,74 @@ struct ProdAccumulator(T)
112
121
return ldexp (mantissa, e);
113
122
}
114
123
124
+ // /
115
125
@safe pure @nogc nothrow
116
126
ProdAccumulator! T ldexp (long exp) const
117
127
{
118
128
return typeof (return )(this .exp + exp, mantissa);
119
129
}
120
130
131
+ // ///
121
132
alias opOpAssign (string op : " *" ) = put;
122
133
134
+ // /
123
135
@safe pure @nogc nothrow
124
136
ProdAccumulator! T opUnary (string op : " -" )() const
125
137
{
126
138
return typeof (return )(exp, - mantissa);
127
139
}
128
140
141
+ // /
129
142
@safe pure @nogc nothrow
130
143
ProdAccumulator! T opUnary (string op : " +" )() const
131
144
{
132
145
return typeof (return )(exp, + mantissa);
133
146
}
134
147
}
135
148
149
+ // /
150
+ version (mir_test)
151
+ @safe pure nothrow
152
+ unittest
153
+ {
154
+ import mir.ndslice.slice: sliced;
155
+
156
+ ProdAccumulator! float x;
157
+ x.put([1 , 2 , 3 ].sliced);
158
+ assert (x.prod == 6f );
159
+ x.put(4 );
160
+ assert (x.prod == 24f );
161
+ }
162
+
163
+ version (mir_test)
164
+ @safe pure @nogc nothrow
165
+ unittest
166
+ {
167
+ import mir.ndslice.slice: sliced;
168
+
169
+ static immutable a = [1 , 2 , 3 ];
170
+ ProdAccumulator! float x;
171
+ x.put(a);
172
+ assert (x.prod == 6f );
173
+ x.put(4 );
174
+ assert (x.prod == 24f );
175
+ static assert (is (typeof (x.prod) == float ));
176
+ }
177
+
178
+ version (mir_test)
179
+ @safe pure nothrow
180
+ unittest
181
+ {
182
+ import mir.ndslice.slice: sliced;
183
+
184
+ ProdAccumulator! double x;
185
+ x.put([1.0 , 2.0 , 3.0 ]);
186
+ assert (x.prod == 6.0 );
187
+ x.put(4.0 );
188
+ assert (x.prod == 24.0 );
189
+ static assert (is (typeof (x.prod) == double ));
190
+ }
191
+
136
192
package template prodType(T)
137
193
{
138
194
import mir.math.sum: elementType;
@@ -171,48 +227,30 @@ See_also:
171
227
$(MREF mir, algorithm, iteration, reduce)
172
228
$(MREF mir, algorithm, iteration, fold)
173
229
+/
174
- template prod (uint size)
230
+ F prod (F, Range )(Range r)
231
+ if (isFloatingPoint! F && isIterable! Range )
175
232
{
176
- import mir.bignum.fp: Fp;
177
-
178
- Fp! size prod (Range )(Range r)
179
- if (isIterable! Range )
180
- {
181
- import core.lifetime : move;
182
- import mir.algorithm.iteration: each;
183
- Fp! size prod = 1LU;
184
- each! ((e) {
185
- prod *= Fp! 128 (e);
186
- })(move(r));
187
- return prod;
188
- }
189
- }
233
+ import core.lifetime : move;
190
234
191
- // / ditto
192
- template prod (F)
193
- if (isFloatingPoint! F)
194
- {
195
- F prod (Range )(Range r)
196
- if (isFloatingPoint! F && isIterable! Range )
197
- {
198
- import core.lifetime : move;
199
- return cast (F) .prod! 128 (r);
200
- }
235
+ ProdAccumulator! F prod;
236
+ prod.put(r.move);
237
+ return prod.prod;
201
238
}
202
239
203
-
204
- deprecated (" Use prod!128 instead." )
240
+ /+ +
241
+ Params:
242
+ r = finite iterable range
243
+ exp = value of exponent
244
+ Returns:
245
+ The mantissa, such that the product equals the mantissa times 2^^exp
246
+ +/
205
247
F prod (F, Range )(Range r, ref long exp)
206
248
if (isFloatingPoint! F && isIterable! Range )
207
249
{
208
250
import core.lifetime : move;
209
251
210
- import core.lifetime : move;
211
-
212
- auto p = .prod! 128 (r.move);
213
-
214
252
ProdAccumulator! F prod;
215
- prod.put(cast (F) p );
253
+ prod.put(r.move );
216
254
exp = prod.exp;
217
255
return prod.x;
218
256
}
@@ -228,10 +266,17 @@ prodType!Range prod(Range)(Range r)
228
266
{
229
267
import core.lifetime : move;
230
268
231
- return cast (typeof (return )) .prod! 128 (r.move);
269
+ alias F = typeof (return );
270
+ return .prod! (F, Range )(r.move);
232
271
}
233
272
234
- deprecated (" Use prod!128 instead." )
273
+ /+ +
274
+ Params:
275
+ r = finite iterable range
276
+ exp = value of exponent
277
+ Returns:
278
+ The mantissa, such that the product equals the mantissa times 2^^exp
279
+ +/
235
280
prodType! Range prod (Range )(Range r, ref long exp)
236
281
if (isIterable! Range )
237
282
{
@@ -249,7 +294,10 @@ Returns:
249
294
+/
250
295
prodType! T prod (T)(scope const T[] ar... )
251
296
{
252
- return cast (typeof (return )) .prod! 128 (ar);
297
+ alias F = typeof (return );
298
+ ProdAccumulator! F prod;
299
+ prod.put(ar);
300
+ return prod.prod;
253
301
}
254
302
255
303
// / Product of arbitrary inputs
@@ -273,6 +321,11 @@ unittest
273
321
auto r = [l, l, l, s, s, s, 0.8 * 2.0 ^^ 10 ];
274
322
275
323
assert (r.prod == 0.8 * 2.0 ^^ 10 );
324
+
325
+ // Can get the mantissa and exponent
326
+ long e;
327
+ assert (r.prod(e).approxEqual(0.8 ));
328
+ assert (e == 10 );
276
329
}
277
330
278
331
// / Product of vector
@@ -291,6 +344,10 @@ unittest
291
344
auto r = [l, l, l, s, s, s, u, u, u].sliced;
292
345
293
346
assert (r.prod == reduce! " a * b" (1.0 , [u, u, u]));
347
+
348
+ long e;
349
+ assert (r.prod(e).approxEqual(reduce! " a * b" (1.0 , [c, c, c])));
350
+ assert (e == 30 );
294
351
}
295
352
296
353
// / Product of matrix
@@ -312,6 +369,10 @@ unittest
312
369
].fuse;
313
370
314
371
assert (r.prod == reduce! " a * b" (1.0 , [u, u, u]));
372
+
373
+ long e;
374
+ assert (r.prod(e) == reduce! " a * b" (1.0 , [c, c, c]));
375
+ assert (e == 30 );
315
376
}
316
377
317
378
// / Column prod of matrix
@@ -391,6 +452,10 @@ unittest
391
452
static immutable result2 = [c, c, c];
392
453
393
454
assert (r.sliced.prod.approxEqual(reduce! " a * b" (1.0 , result1)));
455
+
456
+ long e;
457
+ assert (r.sliced.prod(e).approxEqual(reduce! " a * b" (1.0 , result2)));
458
+ assert (e == 30 );
394
459
}
395
460
396
461
version (mir_test)
@@ -410,27 +475,29 @@ unittest
410
475
static immutable result2 = [c, c, c];
411
476
412
477
assert (r.sliced.prod! double .approxEqual(reduce! " a * b" (1.0 , result1)));
478
+
479
+ long e;
480
+ assert (r.sliced.prod! double (e).approxEqual(reduce! " a * b" (1.0 , result2)));
481
+ assert (e == 30 );
413
482
}
414
483
415
484
/+ +
416
485
Compute the sum of binary logarithms of the input range $(D r).
417
486
The error of this method is much smaller than with a naive sum of log2.
418
487
+/
419
488
Unqual! (DeepElementType! Range ) sumOfLog2s (Range )(Range r)
420
- if (isNumeric ! (DeepElementType! Range ))
489
+ if (isFloatingPoint ! (DeepElementType! Range ))
421
490
{
422
- import mir.bignum.fp: fp_log2 ;
423
- import core.lifetime : move ;
424
- return prod ! 128 (move(r)).fp_log2 ! ( typeof ( return ) );
491
+ long exp = 0 ;
492
+ auto x = .prod(r, exp) ;
493
+ return exp + log2(x );
425
494
}
426
495
427
496
// /
428
497
version (mir_test)
429
498
@safe pure
430
499
unittest
431
500
{
432
- import mir.format: text;
433
- import mir.bignum.fp;
434
501
alias isNaN = x => x != x;
435
502
436
503
assert (sumOfLog2s(new double [0 ]) == 0 );
@@ -450,7 +517,7 @@ Compute the sum of binary logarithms of the input range $(D r).
450
517
The error of this method is much smaller than with a naive sum of log.
451
518
+/
452
519
Unqual! (DeepElementType! Range ) sumOfLogs (Range )(Range r)
453
- if (isNumeric ! (DeepElementType! Range ))
520
+ if (isFloatingPoint ! (DeepElementType! Range ))
454
521
{
455
522
import core.lifetime : move;
456
523
import mir.math.constant: LN2 ;
0 commit comments