Repository: josdejong/mathjs
Pull request #438 (2015-08-25 03:32:54)

Unit prefix powers
This ended up being quite a few changes, so I'll submit the PR without merging it yet.

- Best prefix is applied for units like `3e9 m^2` and `5e-8 s^-1` and so on
- Physical constants are all `fixPrefix == true` now (via the undocumented `_fix` function)
- Minor bug fixes 



Patch:
diff --git a/lib/function/arithmetic/divideScalar.js b/lib/function/arithmetic/divideScalar.js
index cdb14b2df..09c3af89b 100644
--- a/lib/function/arithmetic/divideScalar.js
+++ b/lib/function/arithmetic/divideScalar.js
@@ -36,8 +36,9 @@ function factory(type, config, load, typed) {
     },
 
     'number, Unit': function (x, y) {
-      var xUnit = new type.Unit(x);
-      return xUnit.divide(y);
+      var res = y.pow(-1);
+      res.value = ((res.value === null) ? res._normalize(1) : res.value) * x;
+      return res;
     },
 
     'Unit, Unit': function (x, y) {
diff --git a/lib/type/unit/Unit.js b/lib/type/unit/Unit.js
index 85493ccac..8e1f38696 100644
--- a/lib/type/unit/Unit.js
+++ b/lib/type/unit/Unit.js
@@ -653,6 +653,7 @@ function factory (type, config, load, typed) {
     return res;
   };
 
+
   /**
    * Create a clone of this unit with a representation
    * @param {string | Unit} valuelessUnit   A unit without value. Can have prefix, like "cm"
@@ -769,56 +770,54 @@ function factory (type, config, load, typed) {
         break;
       }
     }
+
     if(matchingBase === 'NONE')
     {
       this.units = [];
-      this.isUnitListSimplified = true;
-      return;
-    }
-
-    var matchingUnit;
-    if(matchingBase) {
-      // Does the unit system have a matching unit?
-      if(currentUnitSystem.hasOwnProperty(matchingBase)) {
-        matchingUnit = currentUnitSystem[matchingBase]
-      }
-    }
-
-
-    var value;
-    var str;
-    if(matchingUnit) {
-      this.units = [{
-        unit: matchingUnit.unit,
-        prefix: matchingUnit.prefix,
-        power: 1.0,
-      }];
-      this.isUnitListSimplified = true;
-      return;
     }
     else {
-      // Multiple units or units with powers are formatted like this:
-      // 5 (kg m^2) / (s^3 mol)
-      // Build an representation from the base units of the current unit system
-      for(var i=0; i<BASE_DIMENSIONS.length; i++) {
-        var baseDim = BASE_DIMENSIONS[i];
-        if(Math.abs(this.dimensions[i]) > 1e-12) {
-          proposedUnitList.push({
-            unit: currentUnitSystem[baseDim].unit,
-            prefix: currentUnitSystem[baseDim].prefix,
-            power: this.dimensions[i]
-          });
+      var matchingUnit;
+      if(matchingBase) {
+        // Does the unit system have a matching unit?
+        if(currentUnitSystem.hasOwnProperty(matchingBase)) {
+          matchingUnit = currentUnitSystem[matchingBase]
         }
       }
 
-      // Is the proposed unit list "simpler" than the existing one?
-      if(proposedUnitList.length < this.units.length) {
-        // Replace this unit list with the proposed list
-        this.units = proposedUnitList;
+      var value;
+      var str;
+      if(matchingUnit) {
+        this.units = [{
+          unit: matchingUnit.unit,
+          prefix: matchingUnit.prefix,
+          power: 1.0,
+        }];
+      }
+      else {
+        // Multiple units or units with powers are formatted like this:
+        // 5 (kg m^2) / (s^3 mol)
+        // Build an representation from the base units of the current unit system
+        for(var i=0; i<BASE_DIMENSIONS.length; i++) {
+          var baseDim = BASE_DIMENSIONS[i];
+          if(Math.abs(this.dimensions[i]) > 1e-12) {
+            proposedUnitList.push({
+              unit: currentUnitSystem[baseDim].unit,
+              prefix: currentUnitSystem[baseDim].prefix,
+              power: this.dimensions[i]
+            });
+          }
+        }
+
+        // Is the proposed unit list "simpler" than the existing one?
+        if(proposedUnitList.length < this.units.length) {
+          // Replace this unit list with the proposed list
+          this.units = proposedUnitList;
+        }
       }
-      this.isUnitListSimplified = true;
-      return;
     }
+
+    this.isUnitListSimplified = true;
+    return;
   }
 
   /**
@@ -895,9 +894,32 @@ function factory (type, config, load, typed) {
    */
   Unit.prototype.format = function (options) {
 
-// Simplfy the unit list, if necessary
+    // Simplfy the unit list, if necessary
     this.simplifyUnitListLazy();
 
+    // Now apply the best prefix
+    // Units must have only one unit and not have the fixPrefix flag set
+    if (this.units.length === 1 && !this.fixPrefix) {
+      // Units must have integer powers, otherwise the prefix will change the
+      // outputted value by not-an-integer-power-of-ten
+      if (Math.abs(this.units[0].power - Math.round(this.units[0].power)) < 1e-14) {
+        // Apply the prefix
+        var bestPrefix = this._bestPrefix();
+        this.units[0].prefix = bestPrefix;
+      }
+    }
+
+    var value = this._denormalize(this.value);
+    var str = (this.value !== null) ? (format(value, options)) : '';
+    var unitStr = this.formatUnits();
+    if(unitStr.length > 0 && str.length > 0) {
+      str += " ";
+    }
+    str += unitStr;
+
+    return str;
+
+/*
     var value,
         str;
     if (this._isDerived()) {
@@ -928,6 +950,7 @@ function factory (type, config, load, typed) {
 
 
     return str;
+    */
   };
 
   /**
@@ -936,26 +959,35 @@ function factory (type, config, load, typed) {
    * @private
    */
   Unit.prototype._bestPrefix = function () {
-    if(this._isDerived()) {
-      throw new Error("Can only compute the best prefix for non-derived units, like kg, s, N, and so forth!");
+    if (this.units.length !== 1) {
+      throw new Error("Can only compute the best prefix for single units with integer powers, like kg, s^2, N^-1, and so forth!");
+    }
+    if (Math.abs(this.units[0].power - Math.round(this.units[0].power)) >= 1e-14) {
+      throw new Error("Can only compute the best prefix for single units with integer powers, like kg, s^2, N^-1, and so forth!");
     }
 
     // find the best prefix value (resulting in the value of which
     // the absolute value of the log10 is closest to zero,
     // though with a little offset of 1.2 for nicer values: you get a
     // sequence 1mm 100mm 500mm 0.6m 1m 10m 100m 500m 0.6km 1km ...
-    var absValue = Math.abs(this.value / this.units[0].unit.value);
-    var bestPrefix = PREFIX_NONE;
+
+    var absValue = Math.abs(this.value); // / this.units[0].unit.value);
+    var bestPrefix = this.units[0].prefix;
+    if (absValue === 0) {
+      return bestPrefix;
+    }
+    var power = this.units[0].power;
     var bestDiff = Math.abs(
-        Math.log(absValue / bestPrefix.value) / Math.LN10 - 1.2);
+        Math.log(absValue / Math.pow(bestPrefix.value * this.units[0].unit.value, power)) / Math.LN10 - 1.2);
 
     var prefixes = this.units[0].unit.prefixes;
     for (var p in prefixes) {
       if (prefixes.hasOwnProperty(p)) {
         var prefix = prefixes[p];
         if (prefix.scientific) {
+
           var diff = Math.abs(
-              Math.log(absValue / prefix.value) / Math.LN10 - 1.2);
+              Math.log(absValue / Math.pow(prefix.value * this.units[0].unit.value, power)) / Math.LN10 - 1.2);
 
           if (diff < bestDiff
               || (diff === bestDiff && prefix.name.length < bestPrefix.name.length)) {
@@ -1048,7 +1080,7 @@ function factory (type, config, load, typed) {
       'f': {name: 'f', value: 1e-30, scientific: true},
       'a': {name: 'a', value: 1e-36, scientific: true},
       'z': {name: 'z', value: 1e-42, scientific: true},
-      'y': {name: 'y', value: 1e-42, scientific: true}
+      'y': {name: 'y', value: 1e-48, scientific: true}
     },
     CUBIC: {
       '': {name: '', value: 1, scientific: true},
diff --git a/lib/type/unit/physicalConstants.js b/lib/type/unit/physicalConstants.js
index bf664e0f9..e4ea4a456 100644
--- a/lib/type/unit/physicalConstants.js
+++ b/lib/type/unit/physicalConstants.js
@@ -1,72 +1,81 @@
 var lazy = require('../../utils/object').lazy;
 
+
 function factory (type, config, load, typed, math) {
+
+  // helper function to create a unit with a fixed prefix
+  function fixedUnit(str) {
+    var unit = type.Unit.parse(str);
+    unit.fixPrefix = true;
+    return unit;
+  }
+
   // Source: http://www.wikiwand.com/en/Physical_constant
 
   // Universal constants
-  lazy(math, 'speedOfLight',         function () {return type.Unit.parse('299792458 m s^-1')});
-  lazy(math, 'gravitationConstant',  function () {return type.Unit.parse('6.6738480e-11 m^3 kg^-1 s^-2')});
-  lazy(math, 'planckConstant',       function () {return type.Unit.parse('6.626069311e-34 J s')});
-  lazy(math, 'reducedPlanckConstant',function () {return type.Unit.parse('1.05457172647e-34 J s')});
+  lazy(math, 'speedOfLight',         function () {return fixedUnit('299792458 m s^-1')});
+  lazy(math, 'gravitationConstant',  function () {return fixedUnit('6.6738480e-11 m^3 kg^-1 s^-2')});
+  lazy(math, 'planckConstant',       function () {return fixedUnit('6.626069311e-34 J s')});
+  lazy(math, 'reducedPlanckConstant',function () {return fixedUnit('1.05457172647e-34 J s')});
 
   // Electromagnetic constants
-  lazy(math, 'magneticConstant',          function () {return type.Unit.parse('1.2566370614e-6 N A^-2')});
-  lazy(math, 'electricConstant',          function () {return type.Unit.parse('8.854187817e-12 F m^-1')});
-  lazy(math, 'vacuumImpedance',           function () {return type.Unit.parse('376.730313461 ohm')});
-  lazy(math, 'coulomb',                   function () {return type.Unit.parse('8.9875517873681764e9 N m^2 C^-2')});
-  lazy(math, 'elementaryCharge',          function () {return type.Unit.parse('1.60217656535e-19 C')});
-  lazy(math, 'bohrMagneton',              function () {return type.Unit.parse('9.2740096820e-24 J T^-1')});
-  lazy(math, 'conductanceQuantum',        function () {return type.Unit.parse('7.748091734625e-5 S')});
-  lazy(math, 'inverseConductanceQuantum', function () {return type.Unit.parse('12906.403721742 ohm')});
-  lazy(math, 'magneticFluxQuantum',       function () {return type.Unit.parse('2.06783375846e-15 Wb')});
-  lazy(math, 'nuclearMagneton',           function () {return type.Unit.parse('5.0507835311e-27 J T^-1')});
-  lazy(math, 'klitzing',                  function () {return type.Unit.parse('25812.807443484 ohm')});
-  //lazy(math, 'josephson',                 function () {return type.Unit.parse('4.8359787011e-14 Hz V^-1')});  // TODO: support for Hz needed
+  lazy(math, 'magneticConstant',          function () {return fixedUnit('1.2566370614e-6 N A^-2')});
+  lazy(math, 'electricConstant',          function () {return fixedUnit('8.854187817e-12 F m^-1')});
+  lazy(math, 'vacuumImpedance',           function () {return fixedUnit('376.730313461 ohm')});
+  lazy(math, 'coulomb',                   function () {return fixedUnit('8.9875517873681764e9 N m^2 C^-2')});
+  lazy(math, 'elementaryCharge',          function () {return fixedUnit('1.60217656535e-19 C')});
+  lazy(math, 'bohrMagneton',              function () {return fixedUnit('9.2740096820e-24 J T^-1')});
+  lazy(math, 'conductanceQuantum',        function () {return fixedUnit('7.748091734625e-5 S')});
+  lazy(math, 'inverseConductanceQuantum', function () {return fixedUnit('12906.403721742 ohm')});
+  lazy(math, 'magneticFluxQuantum',       function () {return fixedUnit('2.06783375846e-15 Wb')});
+  lazy(math, 'nuclearMagneton',           function () {return fixedUnit('5.0507835311e-27 J T^-1')});
+  lazy(math, 'klitzing',                  function () {return fixedUnit('25812.807443484 ohm')});
+  //lazy(math, 'josephson',                 function () {return fixedUnit('4.8359787011e-14 Hz V^-1')});  // TODO: support for Hz needed
 
   // Atomic and nuclear constants
-  lazy(math, 'bohrRadius',              function () {return type.Unit.parse('5.291772109217e-11 m')});
-  lazy(math, 'classicalElectronRadius', function () {return type.Unit.parse('2.817940326727e-15 m')});
-  lazy(math, 'electronMass',            function () {return type.Unit.parse('9.1093829140e-31 kg')});
-  lazy(math, 'fermiCoupling',           function () {return type.Unit.parse('1.1663645e-5 GeV^-2')});
+  lazy(math, 'bohrRadius',              function () {return fixedUnit('5.291772109217e-11 m')});
+  lazy(math, 'classicalElectronRadius', function () {return fixedUnit('2.817940326727e-15 m')});
+  lazy(math, 'electronMass',            function () {return fixedUnit('9.1093829140e-31 kg')});
+  lazy(math, 'fermiCoupling',           function () {return fixedUnit('1.1663645e-5 GeV^-2')});
   lazy(math, 'fineStructure',           function () {return 7.297352569824e-3});
-  lazy(math, 'hartreeEnergy',           function () {return type.Unit.parse('4.3597443419e-18 J')});
-  lazy(math, 'protonMass',              function () {return type.Unit.parse('1.67262177774e-27 kg')});
-  lazy(math, 'deuteronMass',            function () {return type.Unit.parse('3.3435830926e-27 kg')});
-  lazy(math, 'neutronMass',             function () {return type.Unit.parse('1.6749271613e-27 kg')});
-  lazy(math, 'quantumOfCirculation',    function () {return type.Unit.parse('3.636947552024e-4 m^2 s^-1')});
-  lazy(math, 'rydberg',                 function () {return type.Unit.parse('10973731.56853955 m^-1')});
-  lazy(math, 'thomsonCrossSection',     function () {return type.Unit.parse('6.65245873413e-29 m^2')});
+  lazy(math, 'hartreeEnergy',           function () {return fixedUnit('4.3597443419e-18 J')});
+  lazy(math, 'protonMass',              function () {return fixedUnit('1.67262177774e-27 kg')});
+  lazy(math, 'deuteronMass',            function () {return fixedUnit('3.3435830926e-27 kg')});
+  lazy(math, 'neutronMass',             function () {return fixedUnit('1.6749271613e-27 kg')});
+  lazy(math, 'quantumOfCirculation',    function () {return fixedUnit('3.636947552024e-4 m^2 s^-1')});
+  lazy(math, 'rydberg',                 function () {return fixedUnit('10973731.56853955 m^-1')});
+  lazy(math, 'thomsonCrossSection',     function () {return fixedUnit('6.65245873413e-29 m^2')});
   lazy(math, 'weakMixingAngle',         function () {return 0.222321});
   lazy(math, 'efimovFactor',            function () {return 22.7});
 
   // Physico-chemical constants
-  lazy(math, 'atomicMass',          function () {return type.Unit.parse('1.66053892173e-27 kg')});
-  lazy(math, 'avogadro',            function () {return type.Unit.parse('6.0221412927e23 mol^-1')});
-  lazy(math, 'boltzmann',           function () {return type.Unit.parse('1.380648813e-23 J K^-1')});
-  lazy(math, 'faraday',             function () {return type.Unit.parse('96485.336521 C mol^-1')});
-  lazy(math, 'firstRadiation',      function () {return type.Unit.parse('3.7417715317e-16 W m^2')});
-  // lazy(math, 'spectralRadiance',   function () {return type.Unit.parse('1.19104286953e-16 W m^2 sr^-1')}); // TODO spectralRadiance
-  lazy(math, 'loschmidt',           function () {return type.Unit.parse('2.686780524e25 m^-3')});
-  lazy(math, 'gasConstant',         function () {return type.Unit.parse('8.314462175 J K^-1 mol^-1')});
-  lazy(math, 'molarPlanckConstant', function () {return type.Unit.parse('3.990312717628e-10 J s mol^-1')});
-  lazy(math, 'molarVolume',         function () {return type.Unit.parse('2.241396820e-10 m^3 mol^-1')});
+  lazy(math, 'atomicMass',          function () {return fixedUnit('1.66053892173e-27 kg')});
+  lazy(math, 'avogadro',            function () {return fixedUnit('6.0221412927e23 mol^-1')});
+  lazy(math, 'boltzmann',           function () {return fixedUnit('1.380648813e-23 J K^-1')});
+  lazy(math, 'faraday',             function () {return fixedUnit('96485.336521 C mol^-1')});
+  lazy(math, 'firstRadiation',      function () {return fixedUnit('3.7417715317e-16 W m^2')});
+  // lazy(math, 'spectralRadiance',   function () {return fixedUnit('1.19104286953e-16 W m^2 sr^-1')}); // TODO spectralRadiance
+  lazy(math, 'loschmidt',           function () {return fixedUnit('2.686780524e25 m^-3')});
+  lazy(math, 'gasConstant',         function () {return fixedUnit('8.314462175 J K^-1 mol^-1')});
+  lazy(math, 'molarPlanckConstant', function () {return fixedUnit('3.990312717628e-10 J s mol^-1')});
+  lazy(math, 'molarVolume',         function () {return fixedUnit('2.241396820e-10 m^3 mol^-1')});
   lazy(math, 'sackurTetrode',       function () {return -1.164870823});
-  lazy(math, 'secondRadiation',     function () {return type.Unit.parse('1.438777013e-2 m K')});
-  lazy(math, 'stefanBoltzmann',     function () {return type.Unit.parse('5.67037321e-8 W m^-2 K^-4')});
-  lazy(math, 'wienDisplacement',    function () {return type.Unit.parse('2.897772126e-3 m K')});
+  lazy(math, 'secondRadiation',     function () {return fixedUnit('1.438777013e-2 m K')});
+  lazy(math, 'stefanBoltzmann',     function () {return fixedUnit('5.67037321e-8 W m^-2 K^-4')});
+  lazy(math, 'wienDisplacement',    function () {return fixedUnit('2.897772126e-3 m K')});
 
   // Adopted values
-  lazy(math, 'molarMass',         function () {return type.Unit.parse('1e-3 kg mol^-1')});
-  lazy(math, 'molarMassC12',      function () {return type.Unit.parse('1.2e-2 kg mol^-1')});
-  lazy(math, 'gravity',           function () {return type.Unit.parse('9.80665 m s^-2')});
+  lazy(math, 'molarMass',         function () {return fixedUnit('1e-3 kg mol^-1')});
+  lazy(math, 'molarMassC12',      function () {return fixedUnit('1.2e-2 kg mol^-1')});
+  lazy(math, 'gravity',           function () {return fixedUnit('9.80665 m s^-2')});
   // atm is defined in Unit.js
 
   // Natural units
-  lazy(math, 'planckLength',      function () {return type.Unit.parse('1.61619997e-35 m')});
-  lazy(math, 'planckMass',        function () {return type.Unit.parse('2.1765113e-8 kg')});
-  lazy(math, 'planckTime',        function () {return type.Unit.parse('5.3910632e-44 s')});
-  lazy(math, 'planckCharge',      function () {return type.Unit.parse('1.87554595641e-18 C')});
-  lazy(math, 'planckTemperature', function () {return type.Unit.parse('1.41683385e+32 K')});
+  lazy(math, 'planckLength',      function () {return fixedUnit('1.61619997e-35 m')});
+  lazy(math, 'planckMass',        function () {return fixedUnit('2.1765113e-8 kg')});
+  lazy(math, 'planckTime',        function () {return fixedUnit('5.3910632e-44 s')});
+  lazy(math, 'planckCharge',      function () {return fixedUnit('1.87554595641e-18 C')});
+  lazy(math, 'planckTemperature', function () {return fixedUnit('1.41683385e+32 K')});
 
 }
 


Test patch:
diff --git a/test/function/arithmetic/divide.test.js b/test/function/arithmetic/divide.test.js
index f8f2828a2..885c38eae 100644
--- a/test/function/arithmetic/divide.test.js
+++ b/test/function/arithmetic/divide.test.js
@@ -125,6 +125,9 @@ describe('divide', function() {
 
   it('should divide a number by a unit', function() {
     assert.equal(divide(20, math.unit('4 N s')).toString(), '5 N^-1 s^-1');
+    assert.equal(divide(4, math.unit('W')).toString(), '4 W^-1');
+    assert.equal(divide(2.5, math.unit('1.25 mm')).toString(), '2 mm^-1');
+    assert.equal(divide(10, math.unit('4 mg/s')).toString(), '2.5 s / mg');
   });
 
   it('should divide two units', function() {
diff --git a/test/function/arithmetic/dotMultiply.test.js b/test/function/arithmetic/dotMultiply.test.js
index adaa853dc..35bfe2ec4 100644
--- a/test/function/arithmetic/dotMultiply.test.js
+++ b/test/function/arithmetic/dotMultiply.test.js
@@ -57,7 +57,7 @@ describe('dotMultiply', function() {
     assert.equal(dotMultiply(2, unit('5 mm')).toString(), '10 mm');
     assert.equal(dotMultiply(2, unit('5 mm')).toString(), '10 mm');
     assert.equal(dotMultiply(unit('5 mm'), 2).toString(), '10 mm');
-    assert.equal(dotMultiply(unit('5 mm'), 0).toString(), '0 m');
+    assert.equal(dotMultiply(unit('5 mm'), 0).toString(), '0 mm');
   });
 
   it('should throw an error with strings', function() {
diff --git a/test/function/arithmetic/multiply.test.js b/test/function/arithmetic/multiply.test.js
index 3a98d27d1..da78e92d8 100644
--- a/test/function/arithmetic/multiply.test.js
+++ b/test/function/arithmetic/multiply.test.js
@@ -141,7 +141,7 @@ describe('multiply', function() {
       assert.equal(multiply(2, unit('5 mm')).toString(), '10 mm');
       assert.equal(multiply(10, unit('celsius')).toString(), '10 celsius');
       assert.equal(multiply(unit('5 mm'), 2).toString(), '10 mm');
-      assert.equal(multiply(unit('5 mm'), 0).toString(), '0 m');
+      assert.equal(multiply(unit('5 mm'), 0).toString(), '0 mm');
       assert.equal(multiply(unit('celsius'), 10).toString(), '10 celsius');
     });
 
diff --git a/test/type/unit/Unit.test.js b/test/type/unit/Unit.test.js
index c0ca1e67a..251eb0a75 100644
--- a/test/type/unit/Unit.test.js
+++ b/test/type/unit/Unit.test.js
@@ -367,6 +367,23 @@ describe('unit', function() {
       assert.equal(new Unit(1000 ,'ohm').toString(), '1 kohm');
     });
 
+    it('should render best prefix for a single unit raised to integral power', function() {
+      assert.equal(new Unit(3.2e7, 'm^2').toString(), "32 km^2");
+      assert.equal(new Unit(3.2e-7, 'm^2').toString(), "0.32 mm^2");
+      assert.equal(new Unit(15000, 'm^-1').toString(), "15 mm^-1");
+      assert.equal(new Unit(3e-9, 'm^-2').toString(), "3000 Mm^-2");
+      assert.equal(new Unit(3e-9, 'm^-1.5').toString(), "3e-9 m^-1.5");
+      assert.equal(new Unit(2, 'kg^0').toString(), "2");
+    });
+
+    it('should not render best prefix if "fixPrefix" is set', function() {
+			var u = new Unit(5e-3, 'm');
+			u.fixPrefix = true;
+      assert.equal(u.toString(), "0.005 m");
+			u.fixPrefix = false;
+      assert.equal(u.toString(), "5 mm");
+    });
+
   });
 
   describe('simplifyUnitListLazy', function() {
diff --git a/test/type/unit/physicalConstants.test.js b/test/type/unit/physicalConstants.test.js
index 3438c9be1..dbfb04003 100644
--- a/test/type/unit/physicalConstants.test.js
+++ b/test/type/unit/physicalConstants.test.js
@@ -18,25 +18,25 @@ describe('physical constants', function() {
     assert.equal(math.electricConstant.toString(),          '8.854187817e-12 F / m');
     assert.equal(math.vacuumImpedance.toString(),           '376.730313461 ohm');
     assert.equal(math.coulomb.toString(),                   '8.987551787368176e+9 (N m^2) / C^2');
-    assert.equal(math.elementaryCharge.toString(),          '160.217656535 zC');
+    assert.equal(math.elementaryCharge.toString(),          '1.60217656535e-19 C');
     assert.equal(math.bohrMagneton.toString(),              '9.274009682e-24 J / T');
-    assert.equal(math.conductanceQuantum.toString(),        '77.48091734625 uS');
-    assert.equal(math.inverseConductanceQuantum.toString(), '12.906403721741999 kohm'); // round-off error
-    assert.equal(math.magneticFluxQuantum.toString(),       '2.06783375846 fWb');
+    assert.equal(math.conductanceQuantum.toString(),        '7.748091734625e-5 S');
+    assert.equal(math.inverseConductanceQuantum.toString(), '12906.403721742 ohm'); 
+    assert.equal(math.magneticFluxQuantum.toString(),       '2.06783375846e-15 Wb');
     assert.equal(math.nuclearMagneton.toString(),           '5.0507835311e-27 J / T');
-    assert.equal(math.klitzing.toString(),                  '25.812807443483997 kohm'); // round-off error
+    assert.equal(math.klitzing.toString(),                  '25812.807443484 ohm');
     //assert.equal(math.josephson.toString(),                 '4.8359787011e-14 Hz V^-1');  // TODO: support for Hz needed
 
     // Atomic and nuclear constants
-    assert.equal(math.bohrRadius.toString(),              '52.917721092170005 pm'); // round-off error
-    assert.equal(math.classicalElectronRadius.toString(), '2.817940326727 fm');
-    assert.equal(math.electronMass.toString(),            '9.109382913999999e-4 yg');
+    assert.equal(math.bohrRadius.toString(),              '5.291772109217e-11 m');
+    assert.equal(math.classicalElectronRadius.toString(), '2.817940326727e-15 m');
+    assert.equal(math.electronMass.toString(),            '9.109382913999998e-31 kg');
     assert.equal(math.fermiCoupling.toString(),           '1.1663645e-5 GeV^-2');
     approx.equal(math.fineStructure.toString(),           7.297352569824e-3);
-    assert.equal(math.hartreeEnergy.toString(),           '4.3597443419 aJ');
-    assert.equal(math.protonMass.toString(),              '1.6726217777400003 yg'); // round-off error
-    assert.equal(math.deuteronMass.toString(),            '3.3435830926000008 yg'); // round-off error
-    assert.equal(math.neutronMass.toString(),             '1.6749271613 yg');
+    assert.equal(math.hartreeEnergy.toString(),           '4.3597443419e-18 J');
+    assert.equal(math.protonMass.toString(),              '1.67262177774e-27 kg');
+    assert.equal(math.deuteronMass.toString(),            '3.3435830926000005e-27 kg');  // round-off error
+    assert.equal(math.neutronMass.toString(),             '1.6749271613e-27 kg');
     assert.equal(math.quantumOfCirculation.toString(),    '3.636947552024e-4 m^2 / s');
     assert.equal(math.rydberg.toString(),                 '1.097373156853955e+7 m^-1');
     assert.equal(math.thomsonCrossSection.toString(),     '6.65245873413e-29 m^2');
@@ -44,7 +44,7 @@ describe('physical constants', function() {
     approx.equal(math.efimovFactor.toString(),            22.7);
 
     // Physico-chemical constants
-    assert.equal(math.atomicMass.toString(),          '1.6605389217299997 yg'); // round-off error
+    assert.equal(math.atomicMass.toString(),          '1.6605389217299995e-27 kg');  // round-off error
     assert.equal(math.avogadro.toString(),            '6.0221412927e+23 mol^-1');
     assert.equal(math.boltzmann.toString(),           '1.380648813e-23 J / K');
     assert.equal(math.faraday.toString(),             '96485.336521 C / mol');
@@ -65,10 +65,10 @@ describe('physical constants', function() {
     assert.equal(math.gravity.toString(),           '9.80665 m / s^2');
 
     // Natural units
-    assert.equal(math.planckLength.toString(),      '1.6161999700000003e-11 ym'); // round-off error
-    assert.equal(math.planckMass.toString(),        '21.765113 ug');
-    assert.equal(math.planckTime.toString(),        '5.3910632000000007e-20 ys'); // round-off error
-    assert.equal(math.planckCharge.toString(),      '1.8755459564099999 aC');
+    assert.equal(math.planckLength.toString(),      '1.61619997e-35 m');
+    assert.equal(math.planckMass.toString(),        '2.1765113e-8 kg');
+    assert.equal(math.planckTime.toString(),        '5.3910632e-44 s');
+    assert.equal(math.planckCharge.toString(),      '1.87554595641e-18 C');
     assert.equal(math.planckTemperature.toString(), '1.41683385e+32 K');
 
   });