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 }