1 /++
2 This module defines common math operations on quantities.
3 
4 Copyright: Copyright 2013-2015, Nicolas Sicard
5 Authors: Nicolas Sicard
6 License: $(LINK www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7 Standards: $(LINK http://www.bipm.org/en/si/si_brochure/)
8 Source: $(LINK https://github.com/biozic/quantities)
9 +/
10 module quantities.math;
11 
12 import quantities.base;
13 import quantities.qvariant;
14 
15 import std.math;
16 import std.traits;
17 
18 alias dimpow = quantities.base.pow;
19 
20 /// Basic math functions that work with Quantity and QVariant.
21 auto square(Q)(Q quantity)
22     if (isQuantity!Q)
23 {
24     return Quantity!(Q.valueType, dimpow(Q.dimensions, 2)).make(quantity.rawValue ^^ 2);
25 }
26 
27 /// ditto
28 auto square(Q)(Q quantity)
29     if (isQVariant!Q)
30 {
31     return Q.make(quantity.rawValue ^^ 2, dimpow(quantity.dimensions, 2));
32 }
33 
34 /// ditto
35 auto sqrt(Q)(Q quantity)
36     if (isQuantity!Q)
37 {
38     return Quantity!(Q.valueType, powinverse(Q.dimensions, 2)).make(std.math.sqrt(quantity.rawValue));
39 }
40 
41 /// ditto
42 auto sqrt(Q)(Q quantity)
43     if (isQVariant!Q)
44 {
45     return Q.make(std.math.sqrt(quantity.rawValue), powinverse(quantity.dimensions, 2));
46 }
47 
48 pure nothrow @nogc @safe unittest
49 {
50     auto meter = unit!(double, "L");
51     auto surface = 25 * square(meter);
52     auto side = sqrt(surface);
53     assert(side.value(meter).approxEqual(5));
54 }
55 
56 pure @safe unittest
57 {
58     auto meter = unit!(double, "L").qVariant;
59     auto surface = 25 * square(meter);
60     auto side = sqrt(surface);
61     assert(side.value(meter).approxEqual(5));
62 }
63 
64 /// ditto
65 auto cubic(Q)(Q quantity)
66     if (isQuantity!Q)
67 {
68     return Quantity!(Q.valueType, dimpow(Q.dimensions, 3)).make(quantity.rawValue ^^ 3);
69 }
70 
71 /// ditto
72 auto cubic(Q)(Q quantity)
73     if (isQVariant!Q)
74 {
75     return Q.make(quantity.rawValue ^^ 3, dimpow(quantity.dimensions, 3));
76 }
77 
78 /// ditto
79 auto cbrt(Q)(Q quantity)
80     if (isQuantity!Q)
81 {
82     return Quantity!(Q.valueType, powinverse(Q.dimensions, 3)).make(std.math.cbrt(quantity.rawValue));
83 }
84 
85 /// ditto
86 auto cbrt(Q)(Q quantity)
87     if (isQVariant!Q)
88 {
89     return Q.make(std.math.cbrt(quantity.rawValue), powinverse(quantity.dimensions, 3));
90 }
91 
92 @safe /+pure+/ /+nothrow+/ @nogc unittest
93 {
94     auto meter = unit!(double, "L");
95     auto vol = 27 * cubic(meter);
96     auto side = cbrt(vol);
97     assert(side.value(meter).approxEqual(3));
98 }
99 
100 @safe /+pure+/ unittest
101 {
102     auto meter = unit!(double, "L").qVariant;
103     auto vol = 27 * cubic(meter);
104     auto side = cbrt(vol);
105     assert(side.value(meter).approxEqual(3));
106 }
107 
108 /// ditto
109 auto pow(int n, Q)(Q quantity)
110     if (isQuantity!Q)
111 {
112     return Quantity!(Q.valueType, dimpow(Q.dimensions, n)).make(std.math.pow(quantity.rawValue, n));
113 }
114 
115 // ditto
116 auto pow(int n, Q)(Q quantity)
117     if (isQVariant!Q)
118 {
119     return Q.make(std.math.pow(quantity.rawValue, n), dimpow(quantity.dimensions, n));
120 }
121 
122 /// ditto
123 auto nthRoot(int n, Q)(Q quantity)
124     if (isQuantity!Q)
125 {
126     return Quantity!(Q.valueType, powinverse(Q.dimensions, n)).make(std.math.pow(quantity.rawValue, 1.0 / n));
127 }
128 
129 /// ditto
130 auto nthRoot(int n, Q)(Q quantity)
131     if (isQVariant!Q)
132 {
133     return Q.make(std.math.pow(quantity.rawValue, 1.0 / n), powinverse(quantity.dimensions, n));
134 }
135 
136 pure nothrow @nogc @safe unittest
137 {
138     auto meter = unit!(double, "L");
139     auto x = 16 * pow!4(meter);
140     auto side = nthRoot!4(x);
141     assert(side.value(meter).approxEqual(2));
142 }
143 
144 pure @safe unittest
145 {
146     auto meter = unit!(double, "L").qVariant;
147     auto x = 16 * pow!4(meter);
148     auto side = nthRoot!4(x);
149     assert(side.value(meter).approxEqual(2));
150 }
151 
152 /// ditto
153 Q abs(Q)(Q quantity)
154     if (isQuantity!Q)
155 {
156     return Q.make(std.math.fabs(quantity.rawValue));
157 }
158 
159 // ditto
160 Q abs(Q)(Q quantity)
161     if (isQVariant!Q)
162 {
163     return Q.make(std.math.fabs(quantity.rawValue), quantity.dimensions);
164 }
165 
166 pure nothrow @nogc @safe unittest
167 {
168     auto meter = unit!(double, "L");
169     auto mlength = -12 * meter;
170     auto length = abs(mlength);
171     assert(length.value(meter).approxEqual(12));
172 }
173 
174 pure @safe unittest
175 {
176     auto meter = unit!(double, "L").qVariant;
177     auto mlength = -12 * meter;
178     auto length = abs(mlength);
179     assert(length.value(meter).approxEqual(12));
180 }
181 
182 /// Utility templates to manipulate Quantity types.
183 template Inverse(Q)
184     if (isQuantity!Q)
185 {
186     alias Inverse = typeof(1 / Q.init);
187 }
188 
189 /// ditto
190 template Product(Q1, Q2)
191     if (isQuantity!Q1 && isQuantity!Q2)
192 {
193     alias Product = typeof(Q1.init * Q2.init);
194 }
195 
196 /// ditto
197 template Quotient(Q1, Q2)
198     if (isQuantity!Q1 && isQuantity!Q2)
199 {
200     alias Quotient = typeof(Q1.init / Q2.init);
201 }
202 
203 /// ditto
204 template Square(Q)
205     if (isQuantity!Q)
206 {
207     alias Square = typeof(Q.init * Q.init);
208 }
209 
210 /// ditto
211 template Cubic(Q)
212     if (isQuantity!Q)
213 {
214     alias Cubic = typeof(Q.init * Q.init * Q.init);
215 }
216 
217 pure nothrow @nogc @safe unittest
218 {
219     import quantities.si;
220 
221     static assert(is(Inverse!Time == Frequency));
222     static assert(is(Product!(Power, Time) == Energy));
223     static assert(is(Quotient!(Length, Time) == Speed));
224     static assert(is(Square!Length == Area));
225     static assert(is(Cubic!Length == Volume));
226     static assert(AreConsistent!(Product!(Inverse!Time, Length), Speed));
227 }