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 }