Skip to content

Commit 08504a1

Browse files
committed
fix Issue #115
1 parent 4a85d1f commit 08504a1

File tree

4 files changed

+52
-13
lines changed

4 files changed

+52
-13
lines changed

source/mir/math/numeric.d

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Sponsors: This work has been sponsored by $(SUBREF http://symmetryinvestments.co
1212
module mir.math.numeric;
1313

1414
import mir.math.common;
15+
import mir.primitives;
1516

1617
import std.traits;
1718

@@ -33,7 +34,7 @@ struct Prod(T)
3334
exp += lexp;
3435
if (x.fabs < 0.5f)
3536
{
36-
x *= 2;
37+
x += x;
3738
exp--;
3839
}
3940
}
@@ -54,27 +55,27 @@ struct Prod(T)
5455
/++
5556
Compute the product of the input range $(D r) using separate exponent accumulation.
5657
+/
57-
Unqual!(ForeachType!Range) prod(Range)(Range r, ref long exp)
58-
if (isFloatingPoint!(ForeachType!Range))
58+
Unqual!(DeepElementType!Range) prod(Range)(Range r, ref long exp)
59+
if (isFloatingPoint!(DeepElementType!Range))
5960
{
61+
import mir.ndslice.algorithm: each;
6062
Prod!(typeof(return)) prod;
61-
foreach (e; r)
62-
prod.put(e);
63+
r.each!(e => prod.put(e));
6364
exp = prod.exp;
6465
return prod.x;
6566
}
6667

6768
/// ditto
68-
Unqual!(ForeachType!Range) prod(Range)(Range r)
69-
if (isFloatingPoint!(ForeachType!Range))
69+
Unqual!(DeepElementType!Range) prod(Range)(Range r)
70+
if (isFloatingPoint!(DeepElementType!Range))
7071
{
7172

7273
long exp;
7374
auto x = .prod(r, exp);
7475
return Prod!(typeof(return))(exp, x).value;
7576
}
7677

77-
///
78+
/// Arrays and Ranges
7879
version(mir_test)
7980
unittest
8081
{
@@ -87,12 +88,33 @@ unittest
8788
assert(r.prod == 0.8 * 2.0 ^^ 10);
8889
}
8990

91+
/// Ndslices
92+
version(mir_test)
93+
unittest
94+
{
95+
import mir.math.numeric: prod;
96+
import mir.ndslice.slice: sliced;
97+
import mir.ndslice.algorithm: reduce;
98+
99+
enum l = 2.0 ^^ (double.max_exp - 1);
100+
enum s = 2.0 ^^ -(double.max_exp - 1);
101+
auto c = 0.8;
102+
auto u = c * 2.0 ^^ 10;
103+
auto r = [l, l, l,
104+
s, s, s,
105+
u, u, u].sliced(3, 3);
106+
long e;
107+
assert(r.prod(e) == reduce!"a * b"(1.0, [c, c, c]));
108+
assert(e == 30);
109+
assert(r.prod == u * u * u);
110+
}
111+
90112
/++
91113
Compute the sum of binary logarithms of the input range $(D r).
92114
The error of this method is much smaller than with a naive sum of log2.
93115
+/
94-
Unqual!(ForeachType!Range) sumOfLog2s(Range)(Range r)
95-
if (isFloatingPoint!(ForeachType!Range))
116+
Unqual!(DeepElementType!Range) sumOfLog2s(Range)(Range r)
117+
if (isFloatingPoint!(DeepElementType!Range))
96118
{
97119
long exp = 0;
98120
auto x = .prod(r, exp);

source/mir/ndslice/algorithm.d

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,19 @@ unittest
408408
assert(resT == 3);
409409
}
410410

411+
/// Dlang Range API support.
412+
version(mir_test)
413+
unittest
414+
{
415+
import mir.ndslice.algorithm: each;
416+
import std.range: phobos_iota = iota;
417+
418+
int s;
419+
// 0 1 2 3
420+
4.phobos_iota.each!(i => s += i);
421+
assert(s == 6);
422+
}
423+
411424
@safe pure nothrow @nogc
412425
version(mir_test) unittest
413426
{

source/mir/ndslice/slice.d

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ $(T2 slicedNdField, Creates a slice on top of an ndField.)
2222
$(T2 kindOf, Extracts $(LREF SliceKind).)
2323
$(T2 packsOf, Extracts dimension packs from a $(LREF Slice). Alias for $(LREF isSlice).)
2424
$(T2 isSlice, Extracts dimension packs from a type. Extracts `null` if the template argument is not a `Slice`.)
25-
$(T2 DeepElementType, Extracts the element type of a $(LREF Slice).)
2625
$(T2 Structure, A tuple of lengths and strides.)
2726
)
2827

source/mir/primitives.d

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,11 +147,15 @@ size_t elementsCount(Range)(Range range) @property
147147

148148
/++
149149
Returns the element type of a struct with `.DeepElemType` inner alias or a type of common array.
150+
Returns `ForeachType` if struct does not have `.DeepElemType` member.
150151
+/
151152
template DeepElementType(S)
152153
if (is(S == struct) || is(S == class) || is(S == interface))
153154
{
154-
alias DeepElementType = S.DeepElemType;
155+
static if (__traits(hasMember, S, "DeepElemType"))
156+
alias DeepElementType = S.DeepElemType;
157+
else
158+
alias DeepElementType = ForeachType!S;
155159
}
156160

157161
/// ditto
@@ -161,7 +165,8 @@ alias DeepElementType(S : T[], T) = T;
161165
version(mir_test) unittest
162166
{
163167
import mir.ndslice.slice;
164-
import mir.ndslice.topology : iota;
168+
import std.range: std_iota = iota;
169+
static assert(is(DeepElementType!(typeof(std_iota(5))) == int));
165170
static assert(is(DeepElementType!(Slice!(Universal, [4], const(int)[])) == const(int)));
166171
static assert(is(DeepElementType!(Slice!(Universal, [4], immutable(int)*)) == immutable(int)));
167172
}

0 commit comments

Comments
 (0)