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.internal.dimensions;
13 import quantities.base;
14 import quantities.qvariant;
15 
16 import std.math;
17 import std.traits;
18 
19 /// Basic math functions that work with Quantity and QVariant.
20 auto square(Q)(Q quantity)
21     if (isQuantity!Q)
22 {
23     return Quantity!(Q.valueType, Q.dimensions.pow(2)).make(quantity.rawValue ^^ 2);
24 }
25 
26 /// ditto
27 auto square(Q)(Q quantity)
28     if (isQVariant!Q)
29 {
30     return Q.make(quantity.rawValue ^^ 2, quantity.dimensions.pow(2));
31 }
32 
33 /// ditto
34 auto sqrt(Q)(Q quantity)
35     if (isQuantity!Q)
36 {
37     return Quantity!(Q.valueType, Q.dimensions.powinverse(2)).make(std.math.sqrt(quantity.rawValue));
38 }
39 
40 /// ditto
41 auto sqrt(Q)(Q quantity)
42     if (isQVariant!Q)
43 {
44     return Q.make(std.math.sqrt(quantity.rawValue), quantity.dimensions.powinverse(2));
45 }
46 
47 pure nothrow @nogc @safe unittest
48 {
49     auto meter = unit!(double, "L");
50     auto surface = 25 * square(meter);
51     auto side = sqrt(surface);
52     assert(side.value(meter).approxEqual(5));
53 }
54 
55 pure @safe unittest
56 {
57     auto meter = unit!(double, "L").qVariant;
58     auto surface = 25 * square(meter);
59     auto side = sqrt(surface);
60     assert(side.value(meter).approxEqual(5));
61 }
62 
63 /// ditto
64 auto cubic(Q)(Q quantity)
65     if (isQuantity!Q)
66 {
67     return Quantity!(Q.valueType, Q.dimensions.pow(3)).make(quantity.rawValue ^^ 3);
68 }
69 
70 /// ditto
71 auto cubic(Q)(Q quantity)
72     if (isQVariant!Q)
73 {
74     return Q.make(quantity.rawValue ^^ 3, quantity.dimensions.pow(3));
75 }
76 
77 /// ditto
78 auto cbrt(Q)(Q quantity)
79     if (isQuantity!Q)
80 {
81     return Quantity!(Q.valueType, Q.dimensions.powinverse(3)).make(std.math.cbrt(quantity.rawValue));
82 }
83 
84 /// ditto
85 auto cbrt(Q)(Q quantity)
86     if (isQVariant!Q)
87 {
88     return Q.make(std.math.cbrt(quantity.rawValue), quantity.dimensions.powinverse(3));
89 }
90 
91 @safe /+pure+/ /+nothrow+/ @nogc unittest
92 {
93     auto meter = unit!(double, "L");
94     auto vol = 27 * cubic(meter);
95     auto side = cbrt(vol);
96     assert(side.value(meter).approxEqual(3));
97 }
98 
99 @safe /+pure+/ unittest
100 {
101     auto meter = unit!(double, "L").qVariant;
102     auto vol = 27 * cubic(meter);
103     auto side = cbrt(vol);
104     assert(side.value(meter).approxEqual(3));
105 }
106 
107 /// ditto
108 auto pow(int n, Q)(Q quantity)
109     if (isQuantity!Q)
110 {
111     return Quantity!(Q.valueType, Q.dimensions.pow(n)).make(std.math.pow(quantity.rawValue, n));
112 }
113 
114 /// ditto
115 auto pow(int n, Q)(Q quantity)
116     if (isQVariant!Q)
117 {
118     return Q.make(std.math.pow(quantity.rawValue, n), quantity.dimensions.pow(n));
119 }
120 
121 /// ditto
122 auto nthRoot(int n, Q)(Q quantity)
123     if (isQuantity!Q)
124 {
125     return Quantity!(Q.valueType, Q.dimensions.powinverse(n)).make(std.math.pow(quantity.rawValue, 1.0 / n));
126 }
127 
128 /// ditto
129 auto nthRoot(int n, Q)(Q quantity)
130     if (isQVariant!Q)
131 {
132     return Q.make(std.math.pow(quantity.rawValue, 1.0 / n), quantity.dimensions.powinverse(n));
133 }
134 
135 pure nothrow @nogc @safe unittest
136 {
137     auto meter = unit!(double, "L");
138     auto x = 16 * pow!4(meter);
139     auto side = nthRoot!4(x);
140     assert(side.value(meter).approxEqual(2));
141 }
142 
143 pure @safe unittest
144 {
145     auto meter = unit!(double, "L").qVariant;
146     auto x = 16 * pow!4(meter);
147     auto side = nthRoot!4(x);
148     assert(side.value(meter).approxEqual(2));
149 }
150 
151 /// ditto
152 Q abs(Q)(Q quantity)
153     if (isQuantity!Q)
154 {
155     return Q.make(std.math.fabs(quantity.rawValue));
156 }
157 
158 /// ditto
159 Q abs(Q)(Q quantity)
160     if (isQVariant!Q)
161 {
162     return Q.make(std.math.fabs(quantity.rawValue), quantity.dimensions);
163 }
164 
165 pure nothrow @nogc @safe unittest
166 {
167     auto meter = unit!(double, "L");
168     auto mlength = -12 * meter;
169     auto length = abs(mlength);
170     assert(length.value(meter).approxEqual(12));
171 }
172 
173 pure @safe unittest
174 {
175     auto meter = unit!(double, "L").qVariant;
176     auto mlength = -12 * meter;
177     auto length = abs(mlength);
178     assert(length.value(meter).approxEqual(12));
179 }
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 ///
218 pure nothrow @nogc @safe unittest
219 {
220     import quantities.si;
221 
222     static assert(is(Inverse!Time == Frequency));
223     static assert(is(Product!(Power, Time) == Energy));
224     static assert(is(Quotient!(Length, Time) == Speed));
225     static assert(is(Square!Length == Area));
226     static assert(is(Cubic!Length == Volume));
227     static assert(AreConsistent!(Product!(Inverse!Time, Length), Speed));
228 }