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 15 /++ 16 Mixin template that introduces math functions operating on a quantity of value type N in the 17 current scope. Each function imports module_ internally. This module should 18 contain the math primitives that can operate on the variables of type N, such 19 as sqrt, cbrt, pow and fabs. 20 +/ 21 mixin template MathFunctions(N, string module_ = "std.math") 22 { 23 auto square(U)(U unit) 24 if (isQuantity!U && is(U.valueType == N)) 25 { 26 return pow!2(unit); 27 } 28 29 /// ditto 30 auto cubic(U)(U unit) 31 if (isQuantity!U && is(U.valueType == N)) 32 { 33 return pow!3(unit); 34 } 35 36 /// ditto 37 auto pow(int n, U)(U unit) 38 if (isQuantity!U && is(U.valueType == N)) 39 { 40 mixin("import " ~ module_ ~ ";"); 41 static assert(__traits(compiles, unit.rawValue ^^ n), 42 U.valueType.stringof ~ " doesn't overload operator ^^"); 43 return Quantity!(U.valueType, Pow!(n, U.dimensions)).make(unit.rawValue ^^ n); 44 } 45 46 /// ditto 47 auto sqrt(Q)(Q quantity) 48 if (isQuantity!Q && is(Q.valueType == N)) 49 { 50 mixin("import " ~ module_ ~ ";"); 51 static assert(__traits(compiles, sqrt(quantity.rawValue)), 52 "No overload of sqrt for an argument of type " ~ Q.valueType.stringof); 53 return Quantity!(Q.valueType, PowInverse!(2, Q.dimensions)).make(sqrt(quantity.rawValue)); 54 } 55 56 /// ditto 57 auto cbrt(Q)(Q quantity) 58 if (isQuantity!Q && is(Q.valueType == N)) 59 { 60 mixin("import " ~ module_ ~ ";"); 61 static assert(__traits(compiles, cbrt(quantity.rawValue)), 62 "No overload of cbrt for an argument of type " ~ Q.valueType.stringof); 63 return Quantity!(Q.valueType, PowInverse!(3, Q.dimensions)).make(cbrt(quantity.rawValue)); 64 } 65 66 /// ditto 67 auto nthRoot(int n, Q)(Q quantity) 68 if (isQuantity!Q && is(Q.valueType == N)) 69 { 70 mixin("import " ~ module_ ~ ";"); 71 static assert(__traits(compiles, pow(quantity.rawValue, 1.0 / n)), 72 "No overload of pow for an argument of type " ~ Q.valueType.stringof); 73 return Quantity!(Q.valueType, PowInverse!(n, Q.dimensions)).make(pow(quantity.rawValue, 1.0 / n)); 74 } 75 76 /// ditto 77 Q abs(Q)(Q quantity) 78 if (isQuantity!Q && is(Q.valueType == N)) 79 { 80 mixin("import " ~ module_ ~ ";"); 81 static assert(__traits(compiles, fabs(quantity.rawValue)), 82 "No overload of fabs for an argument of type " ~ Q.valueType.stringof); 83 return Q.make(fabs(quantity.rawValue)); 84 } 85 } 86 87 /// 88 unittest 89 { 90 enum meter = unit!("L"); 91 enum liter = 0.001 * meter * meter * meter; 92 93 mixin MathFunctions!(real, "std.math"); 94 95 auto surface = 25 * square(meter); 96 auto side = sqrt(surface); 97 assert(side.value(meter).approxEqual(5)); 98 99 auto volume = 27 * liter; 100 side = cbrt(volume); 101 assert(side.value(meter).approxEqual(0.3)); 102 103 auto delta = -10 * meter; 104 assert(abs(delta) == 10 * meter); 105 } 106 107 108 /// Utility templates to manipulate quantity types. 109 template Inverse(Q) 110 if (isQuantity!Q) 111 { 112 alias Inverse = typeof(1 / Q.init); 113 } 114 115 /// ditto 116 template Product(Q1, Q2) 117 if (isQuantity!Q1 && isQuantity!Q2) 118 { 119 alias Product = typeof(Q1.init * Q2.init); 120 } 121 122 /// ditto 123 template Quotient(Q1, Q2) 124 if (isQuantity!Q1 && isQuantity!Q2) 125 { 126 alias Quotient = typeof(Q1.init / Q2.init); 127 } 128 129 /// ditto 130 template Square(Q) 131 if (isQuantity!Q) 132 { 133 alias Square = typeof(Q.init * Q.init); 134 } 135 136 /// ditto 137 template Cubic(Q, N = real) 138 if (isQuantity!Q) 139 { 140 alias Cubic = typeof(Q.init * Q.init * Q.init); 141 } 142 143 /// 144 unittest 145 { 146 import quantities.si; 147 148 static assert(is(Inverse!Time == Frequency)); 149 static assert(is(Product!(Power, Time) == Energy)); 150 static assert(is(Quotient!(Length, Time) == Speed)); 151 static assert(is(Square!Length == Area)); 152 static assert(is(Cubic!Length == Volume)); 153 static assert(AreConsistent!(Product!(Inverse!Time, Length), Speed)); 154 }