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 }