From: Matt McCutchen Date: Sun, 9 Sep 2007 21:29:06 +0000 (-0400) Subject: Various fixes and enhancements: X-Git-Url: https://mattmccutchen.net/measurements/measurements.git/commitdiff_plain/3a3b5f3c898112a691ed6bfe9e656ccf42207a2b?hp=3f5430dbc58f8f3ffe9b509bdfe00a6b6d334a37 Various fixes and enhancements: - 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. --- diff --git a/README b/README new file mode 100644 index 0000000..5d2e723 --- /dev/null +++ b/README @@ -0,0 +1,12 @@ +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 diff --git a/measurements-demo.ods b/measurements-demo.ods new file mode 100644 index 0000000..165e3c8 Binary files /dev/null and b/measurements-demo.ods differ diff --git a/src/net/mattmccutchen/measurements/Measurement.java b/src/net/mattmccutchen/measurements/Measurement.java index 1ddaa50..0e88986 100644 --- a/src/net/mattmccutchen/measurements/Measurement.java +++ b/src/net/mattmccutchen/measurements/Measurement.java @@ -23,9 +23,11 @@ public class Measurement { 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); @@ -33,11 +35,13 @@ public class Measurement { 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) { @@ -113,7 +117,7 @@ public class Measurement { } 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) { diff --git a/src/net/mattmccutchen/measurements/MeasurementMath.java b/src/net/mattmccutchen/measurements/MeasurementMath.java index 5ea44ab..273365b 100644 --- a/src/net/mattmccutchen/measurements/MeasurementMath.java +++ b/src/net/mattmccutchen/measurements/MeasurementMath.java @@ -71,6 +71,20 @@ public class MeasurementMath { 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; @@ -81,6 +95,22 @@ public class MeasurementMath { 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; diff --git a/src/net/mattmccutchen/measurements/MeasurementsAddIn.java b/src/net/mattmccutchen/measurements/MeasurementsAddIn.java index 5f56dec..0c02f46 100644 --- a/src/net/mattmccutchen/measurements/MeasurementsAddIn.java +++ b/src/net/mattmccutchen/measurements/MeasurementsAddIn.java @@ -42,9 +42,17 @@ public class MeasurementsAddIn extends AddInBase 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.", @@ -100,10 +108,23 @@ public class MeasurementsAddIn extends AddInBase 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)); diff --git a/src/net/mattmccutchen/measurements/Unit.java b/src/net/mattmccutchen/measurements/Unit.java index 25d33ac..4becce2 100644 --- a/src/net/mattmccutchen/measurements/Unit.java +++ b/src/net/mattmccutchen/measurements/Unit.java @@ -3,21 +3,28 @@ package net.mattmccutchen.measurements; 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; @@ -60,6 +67,7 @@ public class Unit { 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); diff --git a/src/net/mattmccutchen/measurements/XMeasurementsAddIn.idl b/src/net/mattmccutchen/measurements/XMeasurementsAddIn.idl index 0a6bc80..fcb6904 100644 --- a/src/net/mattmccutchen/measurements/XMeasurementsAddIn.idl +++ b/src/net/mattmccutchen/measurements/XMeasurementsAddIn.idl @@ -14,7 +14,10 @@ module net { 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); diff --git a/test/net/mattmccutchen/measurements/TestMeasurement.java b/test/net/mattmccutchen/measurements/TestMeasurement.java index 3745dde..4f120a2 100644 --- a/test/net/mattmccutchen/measurements/TestMeasurement.java +++ b/test/net/mattmccutchen/measurements/TestMeasurement.java @@ -23,5 +23,6 @@ public class TestMeasurement { 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 ")); } }