1 // Written in the D programming language
2 /++
3 This module defines common math operations on quantities.
4 
5 Copyright: Copyright 2013-2014, Nicolas Sicard
6 Authors: Nicolas Sicard
7 License: $(LINK www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
8 Standards: $(LINK http://www.bipm.org/en/si/si_brochure/)
9 Source: $(LINK https://github.com/biozic/quantities)
10 +/
11 module quantities.math;
12 
13 import quantities.base;
14 import std.math;
15 import std.traits;
16 
17 /// Basic math functions that work with Quantities where N is a builtin floating point type.
18 auto square(Q)(Q quantity)
19     if (isQuantity!Q && isFloatingPoint!(Q.valueType))
20 {
21     return pow!2(quantity);
22 }
23 
24 /// ditto
25 auto cubic(Q)(Q quantity)
26     if (isQuantity!Q && isFloatingPoint!(Q.valueType))
27 {
28     return pow!3(quantity);
29 }
30 
31 /// ditto
32 auto sqrt(Q)(Q quantity)
33     if (isQuantity!Q && isFloatingPoint!(Q.valueType))
34 {
35     return Quantity!(Q.valueType, PowInverse!(2, Q.dimensions)).make(std.math.sqrt(quantity.rawValue));
36 }
37 
38 /// ditto
39 auto cbrt(Q)(Q quantity)
40     if (isQuantity!Q && isFloatingPoint!(Q.valueType))
41 {
42     return Quantity!(Q.valueType, PowInverse!(3, Q.dimensions)).make(std.math.cbrt(quantity.rawValue));
43 }
44 
45 /// ditto
46 auto nthRoot(int n, Q)(Q quantity)
47     if (isQuantity!Q && isFloatingPoint!(Q.valueType))
48 {
49     return Quantity!(Q.valueType, PowInverse!(n, Q.dimensions)).make(std.math.pow(quantity.rawValue, 1.0 / n));
50 }
51 
52 /// ditto
53 Q abs(Q)(Q quantity)
54     if (isQuantity!Q && isFloatingPoint!(Q.valueType))
55 {
56     return Q.make(std.math.fabs(quantity.rawValue));
57 }
58 
59 auto pow(int n, Q)(Q quantity)
60     if (isQuantity!Q && isFloatingPoint!(Q.valueType))
61 {
62     return Quantity!(Q.valueType, Pow!(n, Q.dimensions)).make(quantity.rawValue ^^ n);
63 }
64 
65 ///
66 unittest
67 {
68     enum meter = unit!(double, "L");
69     enum liter = 0.001 * meter * meter * meter;
70 
71     auto surface = 25 * square(meter);
72     auto side = sqrt(surface);
73     assert(side.value(meter).approxEqual(5));
74 
75     auto volume = 27 * liter;
76     side = cbrt(volume);
77     assert(side.value(meter).approxEqual(0.3));
78 
79     auto delta = -10 * meter;
80     assert(abs(delta) == 10 * meter);
81 }
82 
83 
84 /// Utility templates to manipulate quantity types.
85 template Inverse(Q)
86     if (isQuantity!Q)
87 {
88     alias Inverse = typeof(1 / Q.init);
89 }
90 
91 /// ditto
92 template Product(Q1, Q2)
93     if (isQuantity!Q1 && isQuantity!Q2)
94 {
95     alias Product = typeof(Q1.init * Q2.init);
96 }
97 
98 /// ditto
99 template Quotient(Q1, Q2)
100     if (isQuantity!Q1 && isQuantity!Q2)
101 {
102     alias Quotient = typeof(Q1.init / Q2.init);
103 }
104 
105 /// ditto
106 template Square(Q)
107     if (isQuantity!Q)
108 {
109     alias Square = typeof(Q.init * Q.init);
110 }
111 
112 /// ditto
113 template Cubic(Q)
114     if (isQuantity!Q)
115 {
116     alias Cubic = typeof(Q.init * Q.init * Q.init);
117 }
118 
119 ///
120 unittest
121 {
122     import quantities.si;
123 
124     static assert(is(Inverse!Time == Frequency));
125     static assert(is(Product!(Power, Time) == Energy));
126     static assert(is(Quotient!(Length, Time) == Speed));
127     static assert(is(Square!Length == Area));
128     static assert(is(Cubic!Length == Volume));
129     static assert(AreConsistent!(Product!(Inverse!Time, Length), Speed));
130 }