- Pure numbers are now exact by default.
- Fix mishandling of sig-figs for negative numbers.
- Add MROOTINT, MEXP, and MLN functions.
- Add a sixth basic unit (mol) and some more derived units.
- Add a minimal README.
- Add a demo spreadsheet.
--- /dev/null
+This is Measurements, an OpenOffice.org Calc add-in that provides
+functions for tracking units of measure and significant figures.
+
+See: http://mattmccutchen.net/measurements/
+
+Legal
+-----
+I, Matt McCutchen, the sole author of the original Measurements add-in, waive my
+copyright to it, placing it in the public domain. The add-in comes with
+absolutely no warranty.
+
+-- Matt McCutchen <matt@mattmccutchen.net>
int space = str.indexOf(' ');
String numPart;
String unitPart;
+ boolean forceExact = false;
if (space == -1) {
numPart = str;
unitPart = "";
+ forceExact = true;
} else {
numPart = str.substring(0, space);
unitPart = str.substring(space + 1);
double num;
double unc;
if (numPart.charAt(numPart.length() - 1) == exactIndicator) {
+ forceExact = true;
numPart = numPart.substring(0, numPart.length() - 1);
+ }
+ num = Double.parseDouble(numPart);
+ if (forceExact)
unc = 0;
- num = Double.parseDouble(numPart);
- } else {
- num = Double.parseDouble(numPart);
+ else {
// Determine sig figs
int echar = numPart.indexOf('e');
if (echar == -1) {
}
private static double expOf(double d) {
- return (d == 0) ? 0 : Math.floor(Math.log10(d));
+ return (d == 0) ? 0 : Math.floor(Math.log10(Math.abs(d)));
}
private static int sigFigsOf(double num, double unc) {
up);
}
+ public static Measurement rootint(Measurement a, int b) {
+ if (a == null)
+ return null;
+ int[] up = new int[Unit.basicUnits.length];
+ for (int i = 0; i < Unit.basicUnits.length; i++) {
+ if (Math.abs(a.unitPowers[i]) % b != 0)
+ return null;
+ up[i] = a.unitPowers[i] / b;
+ }
+ return new Measurement(Math.pow(a.number, 1.0/b),
+ a.uncertainty / b * Math.pow(a.number, (1.0/b)-1),
+ up);
+ }
+
public static Measurement pow(Measurement a, Measurement b) {
if (a == null || !isPureNumber(a) || b == null || !isPureNumber(b))
return null;
Measurement.pureNumberUnitPowers);
}
+ public static Measurement exp(Measurement m) {
+ if (m == null || !isPureNumber(m))
+ return null;
+ return new Measurement(Math.exp(m.number),
+ m.uncertainty * Math.exp(m.number),
+ Measurement.pureNumberUnitPowers);
+ }
+
+ public static Measurement ln(Measurement m) {
+ if (m == null || !isPureNumber(m))
+ return null;
+ return new Measurement(Math.log(m.number),
+ m.uncertainty / m.number,
+ Measurement.pureNumberUnitPowers);
+ }
+
public static double cmp(Measurement a, Measurement b) {
if (a == null || b == null || !unitsSame(a, b))
return Double.NaN;
new FunctionInfo("mpowint", "mpowint", "Raises a measurement to an integer power.",
Arrays.asList(new ArgumentInfo("base", "Base"),
new ArgumentInfo("exp", "Exponent"))),
+ new FunctionInfo("mrootint", "mrootint", "Takes an integer square root of a measurement. Does not allow fractional powers of units in the result.",
+ Arrays.asList(new ArgumentInfo("base", "Base"),
+ new ArgumentInfo("exp", "Exponent"))),
new FunctionInfo("mpow", "mpow", "Raises one measurement to the power of another. Both must be pure numbers.",
Arrays.asList(new ArgumentInfo("base", "Base"),
new ArgumentInfo("exp", "Exponent"))),
+ new FunctionInfo("mexp", "mexp", "Raises e (2.718...) to the power of a measurement.",
+ Arrays.asList(new ArgumentInfo("m", "Measurement"))),
+ new FunctionInfo("mln", "mln", "Takes the natural logarithm of a measurement. " +
+ "The measurement must be a pure number, so you may have to rewrite a difference of logarithms as a logarithm of a quotient.",
+ Arrays.asList(new ArgumentInfo("m", "Measurement"))),
new FunctionInfo("mcmp", "mcmp",
"Returns the difference between two measurements, expressed in units of the sum of their uncertainties. " +
"You can compare measurements very flexibly by checking the result against a tolerance.",
return Measurement.format(MeasurementMath.powint(
Measurement.parseCode(a), b), true);
}
+ public String mrootint(String a, String bstr) {
+ int b = Integer.parseInt(bstr);
+ return Measurement.format(MeasurementMath.rootint(
+ Measurement.parseCode(a), b), true);
+ }
public String mpow(String a, String b) {
return Measurement.format(MeasurementMath.pow(
Measurement.parseCode(a), Measurement.parseCode(b)), true);
}
+ public String mexp(String m) {
+ return Measurement.format(MeasurementMath.exp(
+ Measurement.parseCode(m)), true);
+ }
+ public String mln(String m) {
+ return Measurement.format(MeasurementMath.ln(
+ Measurement.parseCode(m)), true);
+ }
public double mcmp(String a, String b) {
return MeasurementMath.cmp(
Measurement.parseCode(a), Measurement.parseCode(b));
import java.util.*;
public class Unit {
- public static final Unit SECOND = new Unit("s" , 1.0, 1, 0, 0, 0, 0);
- public static final Unit METER = new Unit("m" , 1.0, 0, 1, 0, 0, 0);
- public static final Unit GRAM = new Unit("g" , 1.0, 0, 0, 1, 0, 0);
- public static final Unit COULOMB = new Unit("coul", 1.0, 0, 0, 0, 1, 0);
- public static final Unit KELVIN = new Unit("K" , 1.0, 0, 0, 0, 0, 1);
+ public static final Unit SECOND = new Unit("s" , 1.0, 1, 0, 0, 0, 0, 0);
+ public static final Unit METER = new Unit("m" , 1.0, 0, 1, 0, 0, 0, 0);
+ public static final Unit GRAM = new Unit("g" , 1.0, 0, 0, 1, 0, 0, 0);
+ public static final Unit COULOMB = new Unit("coul", 1.0, 0, 0, 0, 1, 0, 0);
+ public static final Unit KELVIN = new Unit("K" , 1.0, 0, 0, 0, 0, 1, 0);
+ public static final Unit MOLE = new Unit("mol" , 1.0, 0, 0, 0, 0, 0, 1);
public static final Unit[] basicUnits = new Unit[] {
- SECOND, METER, GRAM, COULOMB, KELVIN,
+ SECOND, METER, GRAM, COULOMB, KELVIN, MOLE,
}; // Don't mutate
- public static final Unit LITER = new Unit("L", 1e-3, 0, 3, 0, 0, 0);
- public static final Unit PERCENT = new Unit("%", 1e-2, 0, 0, 0, 0, 0);
+ public static final Unit PERCENT = new Unit("%", 1e-2, 0, 0, 0, 0, 0, 0);
+ public static final Unit NEWTON = new Unit("N", 1e+3,-2, 1, 1, 0, 0, 0);
+ public static final Unit JOULE = new Unit("J", 1e+3,-2, 2, 1, 0, 0, 0);
+ public static final Unit WATT = new Unit("W", 1e+3,-3, 2, 1, 0, 0, 0);
+ public static final Unit VOLT = new Unit("V", 1e+3,-2, 2, 1,-1, 0, 0);
+ public static final Unit AMP = new Unit("A", 1.0 ,-1, 0, 0, 1, 0, 0);
+ public static final Unit LITER = new Unit("L", 1e-3, 0, 3, 0, 0, 0, 0);
public static final Unit[] allUnits = new Unit[] {
- PERCENT, SECOND, METER, GRAM, COULOMB, KELVIN, LITER,
+ SECOND, METER, GRAM, COULOMB, KELVIN, MOLE,
+ PERCENT, NEWTON, JOULE, WATT, VOLT, AMP, LITER,
}; // Don't mutate
public final String symbol;
prefixes.put('E', 1e+18);
prefixes.put('Z', 1e+21);
prefixes.put('Y', 1e+24);
+ prefixes.put('c', 1e-02);
prefixes.put('m', 1e-03);
prefixes.put('u', 1e-06); // micro -> u: oh well
prefixes.put('n', 1e-09);
string mmul([in] string a, [in] string b);
string mdiv([in] string a, [in] string b);
string mpowint([in] string a, [in] string b);
+ string mrootint([in] string a, [in] string b);
string mpow([in] string a, [in] string b);
+ string mexp([in] string a);
+ string mln([in] string a);
double mcmp([in] string a, [in] string b);
string mcleanstr([in] string m);
System.out.println(ma.mmul("50.00 mL", "1.000 mg mL^-1"));
System.out.println(ma.mstras("50.00 mL", "L"));
System.out.println(ma.mstras("50.00 mL", "YL"));
+ System.out.println(ma.mln(".365 "));
}
}