import { Decimal } from '@neutrium/math'; import { typeguards } from "@neutrium/utilities"; import { Quantity } from '../Quantity.js' import { QuantityInitParam } from '../guards.js'; import { isCompatible } from './comparison.js'; import { addTempDegrees, subtractTemperatures, subtractTempDegrees } from './temperature.js'; import { throwIncompatibleUnits } from './errors.js'; import { cleanUnitNames } from './clean-unit-names.js' ; const UNITY = "<1>"; //********************* */ Moved // // Mathematical operations on quantities // export function add(a: Quantity, b_o: QuantityInitParam) : Quantity { const b = new Quantity(b_o); if (!isCompatible(a, b)) { throwIncompatibleUnits(); } if (a.isTemperature() && b.isTemperature()) { throw new Error("Cannot add two temperatures"); } else if (a.isTemperature()) { return addTempDegrees(a, b); } else if (b.isTemperature()) { return addTempDegrees(b, a); } return new Quantity({ scalar: a.scalar.add(b.to(a).scalar), numerator: a.numerator, denominator: a.denominator }); } export function sub(a: Quantity, b_o: QuantityInitParam) : Quantity { const b = new Quantity(b_o); if (!isCompatible(a,b)) { throwIncompatibleUnits(); } if (a.isTemperature() && b.isTemperature()) { return subtractTemperatures(a, b); } else if (a.isTemperature()) { return subtractTempDegrees(a, b); } else if (b.isTemperature()) { throw new Error("Cannot subtract a temperature from a differential degree unit"); } return new Quantity({ scalar: a.scalar.sub(b.to(a).scalar), numerator: a.numerator, denominator: a.denominator }); } export function mul(a: Quantity, b_o: QuantityInitParam) : Quantity { if (typeguards.isNumber(b_o) || b_o instanceof Decimal) { return new Quantity({ scalar: a.scalar.mul(b_o), numerator: a.numerator, denominator: a.denominator }); } const b = new Quantity(b_o); if ((a.isTemperature() || b.isTemperature()) && !(a.isUnitless() || b.isUnitless())) { throw new Error("Cannot multiply by temperatures"); } // Quantities should be multiplied with same units if compatible, with base units else let op1 = a, op2 = b; // so as not to confuse results, multiplication and division between temperature degrees will maintain original unit info in num/den // multiplication and division between deg[CFRK] can never factor each other out, only themselves: "degK*degC/degC^2" == "degK/degC" if (isCompatible(op1, op2) && op1.signature !== 400) { op2 = op2.to(op1); } let numden = cleanUnitNames(op1.numerator.concat(op2.numerator), op1.denominator.concat(op2.denominator)); return new Quantity({ scalar: op1.scalar.mul(op2.scalar), numerator: numden[0], denominator: numden[1] }); } export function div(a: Quantity, b_o: QuantityInitParam) : Quantity { if (typeguards.isNumber(b_o) || b_o instanceof Decimal) { return new Quantity({ "scalar": a.scalar.div(b_o), "numerator": a.numerator, "denominator": a.denominator }); } const b = new Quantity(b_o); if (b.isTemperature()) { throw new Error("Cannot divide with temperatures"); } else if (a.isTemperature() && !b.isUnitless()) { throw new Error("Cannot divide with temperatures"); } // Quantities should be multiplied with same units if compatible, with base units else let op1 = a, op2 = b; // so as not to confuse results, multiplication and division between temperature degrees will maintain original unit info in num/den // multiplication and division between deg[CFRK] can never factor each other out, only themselves: "degK*degC/degC^2" == "degK/degC" if (isCompatible(op1, op2) && op1.signature !== 400) { op2 = op2.to(op1); } let numden = cleanUnitNames(op1.numerator.concat(op2.denominator), op1.denominator.concat(op2.numerator)); return new Quantity({ scalar: op1.scalar.div(op2.scalar), numerator: numden[0], denominator: numden[1] }); } export function pow(a: Quantity, yy: number | string | Decimal) : Quantity { yy = new Decimal(yy); if (!yy.isInt()) { throw Error("Raising quantities to a fractional power not currently supported"); } let num = a.numerator, den = a.denominator; for (let i = 1, len = yy.abs().toNumber(); i < len; i++) { num = num.concat(a.numerator); den = den.concat(a.denominator); } // Invert units for negative powers if (yy.s < 0) { let temp = num; num = den; den = temp; } let numden = cleanUnitNames(num, den); return new Quantity({ scalar: a.scalar.pow(yy), numerator: numden[0], denominator: numden[1] }); } // Returns a Qty that is the inverse of Quantity a, export function inverse(a: Quantity) : Quantity { if (a.isTemperature()) { throw new Error("Cannot divide with temperatures"); } if (a.scalar.eq(0)) { throw new Error("Divide by zero"); } return new Quantity({ scalar: new Decimal(1).div(a.scalar), numerator: a.denominator, denominator: a.numerator }); }