Repository: josdejong/mathjs
Pull request #738 (2016-11-06 14:05:29)

Retain original units
Units no longer search for the best prefix if the current prefix results in a value approximately between 0.1 and 1000.

Added some tests and adjusted others. Some tests were simplified as a result of the units not changing prefixes.


Patch:
diff --git a/lib/type/unit/Unit.js b/lib/type/unit/Unit.js
index 2aab8d8f3..8c850516a 100644
--- a/lib/type/unit/Unit.js
+++ b/lib/type/unit/Unit.js
@@ -1145,9 +1145,9 @@ function factory (type, config, load, typed, math) {
       return bestPrefix;
     }
     var power = this.units[0].power;
-    var bestDiff = Math.abs(
-        Math.log(absValue / Math.pow(bestPrefix.value * absUnitValue, power)) / Math.LN10 - 1.2);
-
+    var bestDiff = Math.log(absValue / Math.pow(bestPrefix.value * absUnitValue, power)) / Math.LN10 - 1.2;
+    if(bestDiff > -2.200001 && bestDiff < 1.800001) return bestPrefix;    // Allow the original prefix
+    bestDiff = Math.abs(bestDiff);
     var prefixes = this.units[0].unit.prefixes;
     for (var p in prefixes) {
       if (prefixes.hasOwnProperty(p)) {


Test patch:
diff --git a/test/function/arithmetic/divide.test.js b/test/function/arithmetic/divide.test.js
index 3e181278c..51f4dfb50 100644
--- a/test/function/arithmetic/divide.test.js
+++ b/test/function/arithmetic/divide.test.js
@@ -116,11 +116,11 @@ describe('divide', function() {
   });
 
   it('should divide units by a number', function() {
-    assert.equal(divide(math.unit('5 m'), 10).toString(), '500 mm');
+    assert.equal(divide(math.unit('5 m'), 10).toString(), '0.5 m');
   });
 
   it('should divide valueless units by a number', function() {
-    assert.equal(divide(math.unit('m'), 2).toString(), '500 mm');
+    assert.equal(divide(math.unit('m'), 2).toString(), '0.5 m');
   });
 
   it('should divide a number by a unit', function() {
@@ -158,7 +158,7 @@ describe('divide', function() {
   });
 
   it('should divide units by a big number', function() {
-    assert.equal(divide(math.unit('5 m'), bignumber(10)).toString(), '500 mm');
+    assert.equal(divide(math.unit('5 m'), bignumber(10)).toString(), '0.5 m');
   });
 
   it('should divide each elements in a matrix by a number', function() {
diff --git a/test/function/arithmetic/dotDivide.test.js b/test/function/arithmetic/dotDivide.test.js
index 74b907cd2..38eaa37a7 100644
--- a/test/function/arithmetic/dotDivide.test.js
+++ b/test/function/arithmetic/dotDivide.test.js
@@ -49,7 +49,7 @@ describe('dotDivide', function() {
   });
 
   it('should divide a unit by a number', function() {
-    assert.equal(dotDivide(math.unit('5 m'), 10).toString(), '500 mm');
+    assert.equal(dotDivide(math.unit('5 m'), 10).toString(), '0.5 m');
   });
 
   it('should divide a number by a unit', function() {
diff --git a/test/type/string.test.js b/test/type/string.test.js
index 1b9b79310..3c5c1b0f2 100644
--- a/test/type/string.test.js
+++ b/test/type/string.test.js
@@ -49,7 +49,7 @@ describe('string', function() {
   });
 
   it('should convert a unit to string', function() {
-    assert.equal(string(math.unit('5cm')), '50 mm');
+    assert.equal(string(math.unit('5cm')), '5 cm');
   });
 
   it('should throw an error if called with wrong number of arguments', function() {
diff --git a/test/type/unit/Unit.test.js b/test/type/unit/Unit.test.js
index cc9613cda..192282c8a 100644
--- a/test/type/unit/Unit.test.js
+++ b/test/type/unit/Unit.test.js
@@ -449,19 +449,34 @@ describe('Unit', function() {
     });
 
     it('should render with the best prefix', function() {
+      assert.equal(new Unit(0.000001 ,'m').format(8), '1 um');
+      assert.equal(new Unit(0.00001 ,'m').format(8), '10 um');
+      assert.equal(new Unit(0.0001 ,'m').format(8), '100 um');
+      assert.equal(new Unit(0.0005 ,'m').format(8), '500 um');
+      assert.equal(new Unit(0.0006 ,'m').toString(), '0.6 mm');
       assert.equal(new Unit(0.001 ,'m').toString(), '1 mm');
       assert.equal(new Unit(0.01 ,'m').toString(), '10 mm');
-      assert.equal(new Unit(0.1 ,'m').toString(), '100 mm');
-      assert.equal(new Unit(0.5 ,'m').toString(), '500 mm');
+      assert.equal(new Unit(100000 ,'m').toString(), '100 km');
+      assert.equal(new Unit(300000 ,'m').toString(), '300 km');
+      assert.equal(new Unit(500000 ,'m').toString(), '500 km');
+      assert.equal(new Unit(600000 ,'m').toString(), '0.6 Mm');
+      assert.equal(new Unit(1000000 ,'m').toString(), '1 Mm');
+      assert.equal(new Unit(2000 ,'ohm').toString(), '2 kohm');
+    });
+
+    it('should keep the original prefix when in range', function() {
+      assert.equal(new Unit(0.0999 ,'m').toString(), '99.9 mm');
+      assert.equal(new Unit(0.1 ,'m').toString(), '0.1 m');
+      assert.equal(new Unit(0.5 ,'m').toString(), '0.5 m');
       assert.equal(new Unit(0.6 ,'m').toString(), '0.6 m');
       assert.equal(new Unit(1 ,'m').toString(), '1 m');
       assert.equal(new Unit(10 ,'m').toString(), '10 m');
       assert.equal(new Unit(100 ,'m').toString(), '100 m');
       assert.equal(new Unit(300 ,'m').toString(), '300 m');
       assert.equal(new Unit(500 ,'m').toString(), '500 m');
-      assert.equal(new Unit(600 ,'m').toString(), '0.6 km');
-      assert.equal(new Unit(1000 ,'m').toString(), '1 km');
-      assert.equal(new Unit(1000 ,'ohm').toString(), '1 kohm');
+      assert.equal(new Unit(600 ,'m').toString(), '600 m');
+      assert.equal(new Unit(1000 ,'m').toString(), '1000 m');
+      assert.equal(new Unit(1001 ,'m').toString(), '1.001 km');
     });
 
     it('should render best prefix for a single unit raised to integral power', function() {
diff --git a/test/type/unit/function/unit.test.js b/test/type/unit/function/unit.test.js
index 2afd6c2cb..e1a4c3580 100644
--- a/test/type/unit/function/unit.test.js
+++ b/test/type/unit/function/unit.test.js
@@ -11,7 +11,7 @@ describe('unit', function() {
   });
 
   it('should parse a valid string to a unit', function() {
-    assert.deepEqual(unit('5 cm').toString(), '50 mm');
+    assert.deepEqual(unit('5 cm').toString(), '5 cm');
     assert.deepEqual(unit('5000 cm').toString(), '50 m');
     assert.deepEqual(unit('10 kg').toString(), '10 kg');
   });
@@ -19,7 +19,7 @@ describe('unit', function() {
   it('should clone a unit', function() {
     var a = math.unit('5cm');
     var b = math.unit(a);
-    assert.deepEqual(b.toString(), '50 mm');
+    assert.deepEqual(b.toString(), '5 cm');
   });
 
   it('should create units from all elements in an array', function() {
@@ -43,20 +43,20 @@ describe('unit', function() {
   });
 
   it('should take a number as the quantity and a string as the unit', function() {
-    assert.deepEqual(unit(5, 'cm').toString(), '50 mm');
+    assert.deepEqual(unit(5, 'cm').toString(), '5 cm');
     assert.deepEqual(unit(10, 'kg').toString(), '10 kg');
   });
 
   it('should take a bignumber as the quantity and a string as the unit', function() {
-    assert.deepEqual(unit(math.bignumber(5).plus(1e-24), 'cm').toString(), '50.00000000000000000000001 mm');
+    assert.deepEqual(unit(math.bignumber(5).plus(1e-24), 'cm').toString(), '5.000000000000000000000001 cm');
   });
 
   it('should take a fraction as the quantity and a string as the unit', function() {
-    assert.deepEqual(unit(math.fraction(1,3), 'cm').toString(), '10/3 mm');
+    assert.deepEqual(unit(math.fraction(1,3), 'cm').toString(), '1/3 cm');
   });
 
   it('should convert a string to number with 2 strings', function() {
-    assert.deepEqual(unit('5', 'cm').toString(), '50 mm');
+    assert.deepEqual(unit('5', 'cm').toString(), '5 cm');
   });
 
   it('should throw an error if called with an invalid argument', function() {