Repository: josdejong/mathjs
Pull request #272 (2015-02-04 13:04:45)

Big sine and cosine
Improved the speed of sine, and added cosine. I also adjusted the file, so that relevant functions are bunched together; it helped me keep track of my helper functions. I also checked all of the commented out test cases, and their output values are correct for their input values.


Patch:
diff --git a/.gitignore b/.gitignore
index 77473cc44..35620f14d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,5 @@
 .idea
-.c9
 _site
 coverage
 *swp
 node_modules
-*.log
diff --git a/HISTORY.md b/HISTORY.md
index 56e5615e4..94f689693 100644
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -3,14 +3,13 @@
 
 ## not yet released, version 1.2.1-SNAPSHOT
 
-- Implemented function `trace`. Thanks @pcorey.
 - Faster loading of BigNumber configuration with a high precision by lazy
   loading constants like `pi` and `e`.
 - Fixed constants `NaN` and `Infinity` not being BigNumber objects when
   BigNumbers are configured.
 - Fixed missing parentheses in the `toTex` representation of function
   `permutations`.
-- Some minor fixes in the docs. Thanks @KenanY.
+- Some minor fixes in the docs.
 
 
 ## 2014-12-25, version 1.2.0
diff --git a/lib/expression/node/Node.js b/lib/expression/node/Node.js
index bb63208cf..226004872 100644
--- a/lib/expression/node/Node.js
+++ b/lib/expression/node/Node.js
@@ -262,10 +262,12 @@ function _validateScope (scope) {
 function _transform(math) {
   var transformed = Object.create(math);
 
-  if (math.expression && math.expression.transform) {
-    for (var name in math.expression.transform) {
-      if (math.expression.transform.hasOwnProperty(name)) {
-        transformed[name] = math.expression.transform[name];
+  for (var name in math) {
+    if (math.hasOwnProperty(name)) {
+      var fn = math[name];
+      var transform = fn && fn.transform;
+      if (transform) {
+        transformed[name] = transform;
       }
     }
   }
diff --git a/lib/expression/transform/concat.transform.js b/lib/expression/transform/concat.transform.js
index 4871ef22c..112fa7a3b 100644
--- a/lib/expression/transform/concat.transform.js
+++ b/lib/expression/transform/concat.transform.js
@@ -14,7 +14,7 @@ var argsToArray = require('../../util/array').argsToArray;
  * @param {Object} math
  */
 module.exports = function (math) {
-  var transform = function () {
+  math.concat.transform = function () {
     // copy arguments into an array
     var args = argsToArray(arguments);
 
@@ -35,8 +35,4 @@ module.exports = function (math) {
       throw errorTransform(err);
     }
   };
-
-  math.concat.transform = transform;
-
-  return transform;
 };
diff --git a/lib/expression/transform/filter.transform.js b/lib/expression/transform/filter.transform.js
index 9438dc74b..e1ba91cc6 100644
--- a/lib/expression/transform/filter.transform.js
+++ b/lib/expression/transform/filter.transform.js
@@ -16,7 +16,7 @@ var ArgumentsError = require('../../error/ArgumentsError');
 module.exports = function (math) {
   var _filter = math.filter;
 
-  var transform = function (args, math, scope) {
+  _filter.transform = function (args, math, scope) {
     if (args.length !== 2) {
       throw new ArgumentsError('filter', arguments.length, 2);
     }
@@ -57,8 +57,5 @@ module.exports = function (math) {
     return _filter(x, test);
   };
 
-  transform.rawArgs = true;
-  math.filter.transform = transform;
-
-  return transform;
+  math.filter.transform.rawArgs = true;
 };
diff --git a/lib/expression/transform/forEach.transform.js b/lib/expression/transform/forEach.transform.js
index bb050b9ad..20206ae81 100644
--- a/lib/expression/transform/forEach.transform.js
+++ b/lib/expression/transform/forEach.transform.js
@@ -10,7 +10,7 @@ var Matrix = require('../../type/Matrix');
  * @param {Object} math
  */
 module.exports = function (math) {
-  var transform = function (x, callback) {
+  math.forEach.transform = function (x, callback) {
     if (arguments.length != 2) {
       throw new math.error.ArgumentsError('forEach', arguments.length, 2);
     }
@@ -39,7 +39,4 @@ module.exports = function (math) {
     recurse(array, []);
   }
 
-  math.forEach.transform = transform;
-
-  return transform;
 };
diff --git a/lib/expression/transform/index.transform.js b/lib/expression/transform/index.transform.js
index 8827915b1..0bd575746 100644
--- a/lib/expression/transform/index.transform.js
+++ b/lib/expression/transform/index.transform.js
@@ -15,7 +15,7 @@ var isArray = Array.isArray;
  * @param {Object} math
  */
 module.exports = function (math) {
-  var transform = function () {
+  math.index.transform = function () {
     var args = [];
     for (var i = 0, ii = arguments.length; i < ii; i++) {
       var arg = arguments[i];
@@ -42,8 +42,4 @@ module.exports = function (math) {
     Index.apply(res, args);
     return res;
   };
-
-  math.index.transform = transform;
-
-  return transform;
 };
diff --git a/lib/expression/transform/map.transform.js b/lib/expression/transform/map.transform.js
index ca4b28c44..3ceb0cad0 100644
--- a/lib/expression/transform/map.transform.js
+++ b/lib/expression/transform/map.transform.js
@@ -15,7 +15,7 @@ var isArray = Array.isArray;
  * @param {Object} math
  */
 module.exports = function (math) {
-  var transform = function (x, callback) {
+  math.map.transform = function (x, callback) {
     if (arguments.length != 2) {
       throw new math.error.ArgumentsError('map', arguments.length, 2);
     }
@@ -44,8 +44,4 @@ module.exports = function (math) {
 
     return recurse(arrayIn, []);
   }
-
-  math.map.transform = transform;
-
-  return transform;
 };
diff --git a/lib/expression/transform/max.transform.js b/lib/expression/transform/max.transform.js
index 6fbfadca4..0076167c6 100644
--- a/lib/expression/transform/max.transform.js
+++ b/lib/expression/transform/max.transform.js
@@ -15,7 +15,7 @@ var argsToArray = require('../../util/array').argsToArray;
  * @param {Object} math
  */
 module.exports = function (math) {
-  var transform = function () {
+  math.max.transform = function () {
     var args = argsToArray(arguments);
 
     // change last argument dim from one-based to zero-based
@@ -36,8 +36,4 @@ module.exports = function (math) {
       throw errorTransform(err);
     }
   };
-
-  math.max.transform = transform;
-
-  return transform;
 };
diff --git a/lib/expression/transform/mean.transform.js b/lib/expression/transform/mean.transform.js
index 9badae60b..52eb07218 100644
--- a/lib/expression/transform/mean.transform.js
+++ b/lib/expression/transform/mean.transform.js
@@ -15,7 +15,7 @@ var argsToArray = require('../../util/array').argsToArray;
  * @param {Object} math
  */
 module.exports = function (math) {
-  var transform = function () {
+  math.mean.transform = function () {
     var args = argsToArray(arguments);
 
     // change last argument dim from one-based to zero-based
@@ -36,8 +36,4 @@ module.exports = function (math) {
       throw errorTransform(err);
     }
   };
-
-  math.mean.transform = transform;
-
-  return transform;
 };
diff --git a/lib/expression/transform/min.transform.js b/lib/expression/transform/min.transform.js
index 3875db72c..368248565 100644
--- a/lib/expression/transform/min.transform.js
+++ b/lib/expression/transform/min.transform.js
@@ -15,7 +15,7 @@ var argsToArray = require('../../util/array').argsToArray;
  * @param {Object} math
  */
 module.exports = function (math) {
-  var transform = function () {
+  math.min.transform = function () {
     var args = argsToArray(arguments);
 
     // change last argument dim from one-based to zero-based
@@ -36,8 +36,4 @@ module.exports = function (math) {
       throw errorTransform(err);
     }
   };
-
-  math.min.transform = transform;
-
-  return transform;
 };
diff --git a/lib/expression/transform/range.transform.js b/lib/expression/transform/range.transform.js
index 14234af2f..bb29ddc2f 100644
--- a/lib/expression/transform/range.transform.js
+++ b/lib/expression/transform/range.transform.js
@@ -11,7 +11,7 @@ var argsToArray = require('../../util/array').argsToArray;
  * @param {Object} math
  */
 module.exports = function (math) {
-  var transform = function () {
+  math.range.transform = function () {
     var args = argsToArray(arguments);
 
     var lastIndex = args.length - 1;
@@ -22,8 +22,4 @@ module.exports = function (math) {
 
     return math.range.apply(math, args);
   };
-
-  math.range.transform = transform;
-
-  return transform;
 };
diff --git a/lib/expression/transform/subset.transform.js b/lib/expression/transform/subset.transform.js
index bc8defde1..2b9e59871 100644
--- a/lib/expression/transform/subset.transform.js
+++ b/lib/expression/transform/subset.transform.js
@@ -12,7 +12,7 @@ var argsToArray = require('../../util/array').argsToArray;
  * @param {Object} math
  */
 module.exports = function (math) {
-  var transform = function () {
+  math.subset.transform = function () {
     try {
       return math.subset.apply(math, argsToArray(arguments));
     }
@@ -20,8 +20,4 @@ module.exports = function (math) {
       throw errorTransform(err);
     }
   };
-
-  math.subset.transform = transform;
-
-  return transform;
 };
diff --git a/lib/function/matrix/trace.js b/lib/function/matrix/trace.js
deleted file mode 100644
index f75f8baa7..000000000
--- a/lib/function/matrix/trace.js
+++ /dev/null
@@ -1,97 +0,0 @@
-'use strict';
-
-module.exports = function (math) {
-  var util = require('../../util/index'),
-
-      Matrix = require('../../type/Matrix'),
-
-      object = util.object,
-      string = util.string;
-
-  /**
-   * Calculate the trace of a matrix.
-   *
-   * Syntax:
-   *
-   *    math.trace(x)
-   *
-   * Examples:
-   *
-   *    math.trace([[1, 2], [3, 4]]); // returns 5
-   *
-   *    var A = [
-   *      [1, 2, 3],
-   *      [-1, 2, 3],
-   *      [2, 0, 3]
-   *    ]
-   *    math.trace(A); // returns 6
-   *
-   * @param {Array | Matrix} x  A matrix
-   * @return {Number} The trace of `x`
-   */
-  math.trace = function trace (x) {
-    if (arguments.length != 1) {
-      throw new math.error.ArgumentsError('trace', arguments.length, 1);
-    }
-
-    var size;
-    if (x instanceof Matrix) {
-      size = x.size();
-    }
-    else if (x instanceof Array) {
-      x = new Matrix(x);
-      size = x.size();
-    }
-    else {
-      // a scalar
-      size = [];
-    }
-
-    switch (size.length) {
-      case 0:
-        // scalar
-        return object.clone(x);
-
-      case 1:
-        // vector
-        if (size[0] == 1) {
-          return object.clone(x.valueOf()[0]);
-        }
-        else {
-          throw new RangeError('Matrix must be square ' +
-              '(size: ' + string.format(size) + ')');
-        }
-
-      case 2:
-        // two dimensional array
-        var rows = size[0];
-        var cols = size[1];
-        if (rows == cols) {
-          return _trace(x.clone().valueOf());
-        }
-        else {
-          throw new RangeError('Matrix must be square ' +
-              '(size: ' + string.format(size) + ')');
-        }
-
-      default:
-        // multi dimensional array
-        throw new RangeError('Matrix must be two dimensional ' +
-            '(size: ' + string.format(size) + ')');
-    }
-  };
-
-  /**
-   * Calculate the trace of a matrix
-   * @param {Array[]} matrix  A square, two dimensional matrix
-   * @returns {Number} trace
-   * @private
-   */
-  function _trace (matrix) {
-    var sum = 0;
-    for (var i = 0; i < matrix.length; i++) {
-        sum = math.add(sum, matrix[i][i]);
-    }
-    return sum;
-  }
-};
diff --git a/lib/function/trigonometry/cos.js b/lib/function/trigonometry/cos.js
index 9601c00ef..577c6c3d0 100644
--- a/lib/function/trigonometry/cos.js
+++ b/lib/function/trigonometry/cos.js
@@ -1,6 +1,6 @@
 'use strict';
 
-module.exports = function (math) {
+module.exports = function (math, config) {
   var util = require('../../util/index'),
 
       BigNumber = math.type.BigNumber,
@@ -12,7 +12,9 @@ module.exports = function (math) {
       isBoolean = util['boolean'].isBoolean,
       isComplex = Complex.isComplex,
       isUnit = Unit.isUnit,
-      isCollection = collection.isCollection;
+      isCollection = collection.isCollection,
+
+      bigCos = util.bignumber.cos_sin;
 
   /**
    * Calculate the cosine of a value.
@@ -73,9 +75,7 @@ module.exports = function (math) {
     }
 
     if (x instanceof BigNumber) {
-      // TODO: implement BigNumber support
-      // downgrade to Number
-      return cos(x.toNumber());
+      return bigCos(x, config.precision, 0);
     }
 
     throw new math.error.UnsupportedTypeError('cos', math['typeof'](x));
diff --git a/lib/function/trigonometry/sech.js b/lib/function/trigonometry/sech.js
index da572ec2b..0918233cc 100644
--- a/lib/function/trigonometry/sech.js
+++ b/lib/function/trigonometry/sech.js
@@ -28,7 +28,7 @@ module.exports = function (math) {
    *
    *    // sech(x) = 1/ cosh(x)
    *    math.sech(0.5);       // returns 0.886818883970074
-   *    1 / math.cosh(0.5);   // returns 0.886818883970074
+   *    1 / math.cosh(0.5);   // returns 1.9190347513349437
    *
    * See also:
    *
diff --git a/lib/function/trigonometry/sin.js b/lib/function/trigonometry/sin.js
index 9b289fc32..5c872a39c 100644
--- a/lib/function/trigonometry/sin.js
+++ b/lib/function/trigonometry/sin.js
@@ -1,6 +1,6 @@
 'use strict';
 
-module.exports = function (math) {
+module.exports = function (math, config) {
   var util = require('../../util/index'),
 
       BigNumber = math.type.BigNumber,
@@ -14,7 +14,7 @@ module.exports = function (math) {
       isUnit = Unit.isUnit,
       isCollection = collection.isCollection,
 
-      bigSin = util.bignumber.sin;
+      bigSin = util.bignumber.cos_sin;
 
   /**
    * Calculate the sine of a value.
@@ -74,8 +74,7 @@ module.exports = function (math) {
     }
 
     if (x instanceof BigNumber) {
-      // TODO: implement better BigNumber support
-      return bigSin(x);
+      return bigSin(x, config.precision, 1);
     }
 
     throw new math.error.UnsupportedTypeError('sin', math['typeof'](x));
diff --git a/lib/function/utils/import.js b/lib/function/utils/import.js
index 4c79487f2..ebcf57a6a 100644
--- a/lib/function/utils/import.js
+++ b/lib/function/utils/import.js
@@ -120,20 +120,12 @@ module.exports = function (math) {
           }
           return value.apply(math, args);
         };
-        if (value && value.transform) {
-          math[name].transform = value.transform;
-        }
       }
       else {
         // just create a link to the function or value
         math[name] = value;
       }
 
-      // register the transform function if any
-      if (value && value.transform) {
-        math.expression.transform[name] = value.transform;
-      }
-
       // create a proxy for the chain
       math.chaining.Chain.createProxy(name, value);
     }
diff --git a/lib/math.js b/lib/math.js
index 5e3420331..902ed8435 100644
--- a/lib/math.js
+++ b/lib/math.js
@@ -256,7 +256,6 @@ function create (config) {
   require('./function/matrix/size')(math, _config);
   require('./function/matrix/squeeze')(math, _config);
   require('./function/matrix/subset')(math, _config);
-  require('./function/matrix/trace')(math, _config);
   require('./function/matrix/transpose')(math, _config);
   require('./function/matrix/zeros')(math, _config);
 
@@ -331,18 +330,16 @@ function create (config) {
   require('./constants')(math, _config);
 
   // attach transform functions (for converting one-based indices to zero-based)
-  math.expression.transform = {
-    concat: require('./expression/transform/concat.transform')(math, _config),
-    filter: require('./expression/transform/filter.transform')(math, _config),
-    forEach:require('./expression/transform/forEach.transform')(math, _config),
-    index:  require('./expression/transform/index.transform')(math, _config),
-    map:    require('./expression/transform/map.transform')(math, _config),
-    max:    require('./expression/transform/max.transform')(math, _config),
-    mean:   require('./expression/transform/mean.transform')(math, _config),
-    min:    require('./expression/transform/min.transform')(math, _config),
-    range:  require('./expression/transform/range.transform')(math, _config),
-    subset: require('./expression/transform/subset.transform')(math, _config)
-  };
+  require('./expression/transform/concat.transform')(math, _config);
+  require('./expression/transform/filter.transform')(math, _config);
+  require('./expression/transform/forEach.transform')(math, _config);
+  require('./expression/transform/index.transform')(math, _config);
+  require('./expression/transform/map.transform')(math, _config);
+  require('./expression/transform/max.transform')(math, _config);
+  require('./expression/transform/mean.transform')(math, _config);
+  require('./expression/transform/min.transform')(math, _config);
+  require('./expression/transform/range.transform')(math, _config);
+  require('./expression/transform/subset.transform')(math, _config);
 
   // selector (we initialize after all functions are loaded)
   math.chaining = {};
diff --git a/lib/util/bignumber.js b/lib/util/bignumber.js
index a26a72592..d175b4b60 100644
--- a/lib/util/bignumber.js
+++ b/lib/util/bignumber.js
@@ -15,8 +15,9 @@ exports.isBigNumber = function (value) {
 };
 
 
-/* BigNumber constants. */
-
+/************************************* 
+ *             Constants             *
+ *************************************/
 
 /**
  * Calculate BigNumber e
@@ -77,8 +78,9 @@ exports.tau = memoize(function (precision) {
 });
 
 
-/* BigNumber functions. */
-
+/*************************************
+ *         Bitwise functions         *
+ *************************************/
 
 /*
  * Special Cases:
@@ -145,33 +147,6 @@ exports.and = function(x, y) {
   return bitwise(x, y, function (a, b) { return a & b });
 };
 
-/**
- * Calculate the arc tangent of x
- *
- * arctan(x) = x - x^3/3 + x^5/5 - x^7/7 + x^9/9 - ...
- *           = x - x^2*x^1/3 + x^2*x^3/5 - x^2*x^5/7 + x^2*x^7/9 - ...
- *
- * @param {BigNumber} x
- * @returns {BigNumber} arc tangent of x
- */
-exports.arctan = function (x) {
-  var y = x;
-  var yPrev = NaN;
-  var x2 = x.times(x);
-  var num = x;
-  var add = true;
-
-  for (var k = 3; !y.equals(yPrev); k += 2) {
-    num = num.times(x2);
-
-    yPrev = y;
-    add = !add;
-    y = (add) ? y.plus(num.div(k)) : y.minus(num.div(k));
-  }
-
-  return y;
-};
-
 /*
  * Special Cases:
  *  n << -n = N
@@ -282,70 +257,6 @@ exports.or = function (x, y) {
   return bitwise(x, y, function (a, b) { return a | b });
 };
 
-/**
- * Calculate the sine of x using Taylor Series.
- *
- * sin(x) = x - x^3/3! + x^5/5! - x^7/7! + x^9/9! - ...
- *        = x - x^2*x^1/3! + x^2*x^3/5! - x^2*x^5/7! + x^2*x^7/9! - ...
- *
- * TODO: Replace with Chebyshev approximation.
- *
- * @param {BigNumber} x
- * @returns {BigNumber} sine of x
- */
-exports.sin = function (x) {
-  var BigNumber = x.constructor;
-  var precision = BigNumber.precision;
-  if (x.isNaN() || !x.isFinite()) {
-    return new BigNumber(NaN);
-  }
-
-  // sin(-x) == -sin(x)
-  var isNeg = x.isNegative();
-  if (isNeg) {
-    x.s = -x.s;
-  }
-
-  // Get offset within the period of sin (-pi, pi] w/ gaurd digits
-  var prec_plus_guard_digits = precision + (3*Math.log(precision) | 0) + 1;
-  var pi = exports.pi(prec_plus_guard_digits + 2);
-  var tau = exports.tau(prec_plus_guard_digits);
-
-  // Catch if tau multiple using pi's precision
-  if (x.div(pi.toDP(x.dp(), 1)).toNumber() % 2 == 0) {
-    return new BigNumber(0);
-  }
-
-  var y = x.mod(tau);
-  // Catch if tau multiple with tau's precision
-  if (y.toDP(x.dp(), 1).isZero()) {
-    return new BigNumber(0);
-  }
-  if (y.gt(pi)) {
-    y = y.minus(tau);
-  }
-
-  var yPrev = NaN;
-  var y2 = y.times(y);
-  var num = y;
-  var den = BigNumber.ONE;
-  var add = true;
-  for (var k = 1; !y.equals(yPrev); k += 2) {
-    num = num.times(y2);
-    den = den.times(k+1).times(k+2);
-
-    yPrev = y;
-    add = !add;
-    y = (add) ? y.plus(num.div(den)) : y.minus(num.div(den));
-  }
-
-  if (isNeg) {
-    y.s = -y.s;
-  }
-  y.constructor.config({precision: precision});
-  return y.toDP(precision - 1);
-};
-
 /*
  * Special Cases:
  *   n >> -n =  N
@@ -450,6 +361,314 @@ exports.xor = function (x, y) {
   return bitwise(x, y, function (a, b) { return a ^ b });
 };
 
+/* Applies bitwise function to numbers. */
+function bitwise(x, y, func) {
+  var BigNumber = x.constructor;
+
+  var xBits, yBits;
+  var xSign = +(x.s < 0);
+  var ySign = +(y.s < 0);
+  if (xSign) {
+    xBits = decCoefficientToBinaryString(exports.not(x));
+    for (var i = 0; i < xBits.length; ++i) {
+      xBits[i] ^= 1;
+    }
+  } else {
+    xBits = decCoefficientToBinaryString(x);
+  }
+  if (ySign) {
+    yBits = decCoefficientToBinaryString(exports.not(y));
+    for (var i = 0; i < yBits.length; ++i) {
+      yBits[i] ^= 1;
+    }
+  } else {
+    yBits = decCoefficientToBinaryString(y);
+  }
+
+  var minBits, maxBits, minSign;
+  if (xBits.length <= yBits.length) {
+    minBits = xBits;
+    maxBits = yBits;
+    minSign = xSign;
+  } else {
+    minBits = yBits;
+    maxBits = xBits;
+    minSign = ySign;
+  }
+
+  var shortLen = minBits.length;
+  var longLen = maxBits.length;
+  var expFuncVal = func(xSign, ySign) ^ 1;
+  var outVal = new BigNumber(expFuncVal ^ 1);
+  var twoPower = BigNumber.ONE;
+  var two = new BigNumber(2);
+
+  var prevPrec = BigNumber.precision;
+  BigNumber.config({precision: 1E9});
+
+  while (shortLen > 0) {
+    if (func(minBits[--shortLen], maxBits[--longLen]) == expFuncVal) {
+      outVal = outVal.plus(twoPower);
+    }
+    twoPower = twoPower.times(two);
+  }
+  while (longLen > 0) {
+    if (func(minSign, maxBits[--longLen]) == expFuncVal) {
+      outVal = outVal.plus(twoPower);
+    }
+    twoPower = twoPower.times(two);
+  }
+
+  BigNumber.config({precision: prevPrec});
+
+  if (expFuncVal == 0) {
+    outVal.s = -outVal.s;
+  }
+  return outVal;
+}
+
+/* Extracted from decimal.js, and edited to specialize. */
+function decCoefficientToBinaryString(x) {
+  // Convert to string
+  var a = x.c;
+  var r = a[0] + '';
+
+  for (var i = 1; i < a.length; ++i) {
+    var s = a[i] + '';
+    for (var z = 7 - s.length; z--; ) {
+      s = '0' + s;
+    }
+
+    r += s;
+  }
+
+  var j;
+  for (j = r.length - 1; r.charAt(j) == '0'; --j);
+
+  var xe = x.e;
+  var str = r.slice(0, j + 1 || 1);
+  var strL = str.length;
+  if (xe > 0) {
+    if (++xe > strL) {
+      // Append zeros.
+      for (xe -= strL; xe--; str += '0');
+    } else if (xe < strL) {
+      str = str.slice(0, xe) + '.' + str.slice(xe);
+    }
+  }
+
+  // Convert from base 10 (decimal) to base 2
+  var arr = [0];
+  for (var i = 0; i < str.length; ) {
+    for (var arrL = arr.length; arrL--; arr[arrL] *= 10);
+
+    arr[0] += str.charAt(i++) << 0;  // convert to int
+    for (var j = 0; j < arr.length; ++j) {
+      if (arr[j] > 1) {
+        if (arr[j + 1] == null) {
+          arr[j + 1] = 0;
+        }
+
+        arr[j + 1] += arr[j] >> 1;
+        arr[j] &= 1;
+      }
+    }
+  }
+
+  return arr.reverse();
+}
+
+
+/*************************************
+ *      Trigonometric functions      *
+ *************************************/
+
+/**
+ * Calculate the arc tangent of x
+ *
+ * arctan(x) = x - x^3/3 + x^5/5 - x^7/7 + x^9/9 - ...
+ *           = x - x^2*x^1/3 + x^2*x^3/5 - x^2*x^5/7 + x^2*x^7/9 - ...
+ *
+ * @param {BigNumber} x
+ * @returns {BigNumber} arc tangent of x
+ */
+exports.arctan = function (x) {
+  var y = x;
+  var yPrev = NaN;
+  var x2 = x.times(x);
+  var num = x;
+  var add = true;
+
+  for (var k = 3; !y.equals(yPrev); k += 2) {
+    num = num.times(x2);
+
+    yPrev = y;
+    add = !add;
+    y = (add) ? y.plus(num.div(k)) : y.minus(num.div(k));
+  }
+
+  return y;
+}
+
+/**
+ * Calculate cosine/sine of x using the multiple angle identity:
+ *
+ * cos(4x) = 8[cos(x)^4 - cos(x)^2] + 1
+ *
+ * sin(5x) = 16sin(x)^5 - 20sin(x)^3 + 5sin(x)
+ * http://www.tc.umn.edu/~ringx004/sidebar.html
+ *
+ * @param {BigNumber} x
+ * @param {Number} mode     sine function if 1, cosine function if 0
+ * @returns {BigNumber} sine or cosine of x
+ */
+exports.cos_sin = function (x, precision, mode) {
+  if (x.isNaN() || !x.isFinite()) {
+    var Big = BigNumber.constructor({precision: precision});
+    return new Big(NaN);
+  }
+
+  // sin(-x) == -sin(x), cos(-x) == cos(x)
+  var isNeg = x.isNegative();
+  if (isNeg) {
+    x.s = -x.s;
+  }
+
+  var y = reduceToPeriod(x, precision, mode);  // Make this destructive
+  if (y[1]) {
+    return y[0];
+  }
+
+  y = y[0];
+  var Big = y.constructor;
+  if (mode) {
+    var ret = cos_sin_taylor(y.div(3125), mode);
+    Big.config({precision: Math.min(Big.precision, precision + 15)});
+
+    var five = new Big(5);
+    var sixteen = new Big(16);
+    var twenty = new Big(20);
+    for (var i = 0; i < 5; ++i) {
+      var ret2 = ret.times(ret);
+      var ret3 = ret2.times(ret);
+      var ret5 = ret3.times(ret2);
+      ret = sixteen.times(ret5).minus(
+              twenty.times(ret3)).plus(
+                five.times(ret));
+    }
+
+    if (isNeg) {
+      ret.s = -ret.s;
+    }
+  } else {
+    var div_factor, loops;
+    if (y.abs().lt(Big.ONE)) {
+      div_factor = 64;
+      loops = 3;
+    } else {
+      div_factor = 256;
+      loops = 4;
+    }
+
+    var ret = cos_sin_taylor(y.div(div_factor), mode);
+    Big.config({precision: Math.min(Big.precision, precision + 8)});
+
+    var eight = new Big(8);
+    for (; loops > 0; --loops) {
+      var ret2 = ret.times(ret);
+      var ret4 = ret2.times(ret2);
+      ret = eight.times(ret4.minus(ret2)).plus(Big.ONE);
+    }
+  }
+
+  ret.constructor.config({precision: precision});
+  return ret.toDP(precision - 1);
+};
+
+/**
+ * Calculate the cosine or sine of x using Taylor Series.
+ *
+ * cos(x) = 1 - x^2/2! + x^4/4! - x^6/6! + x^8/8! - ...
+ *        = 1 - 1*x^2/2! + x^2*x^2/4! - x^2*x^4/6! + x^2*x^6/8! - ...
+ *
+ * sin(x) = x - x^3/3! + x^5/5! - x^7/7! + x^9/9! - ...
+ *        = x - x^2*x^1/3! + x^2*x^3/5! - x^2*x^5/7! + x^2*x^7/9! - ...
+ *
+ * @param {BigNumber} x     reduced argument
+ * @param {Number} mode     sine function if 1, cosine function if 0
+ * @returns {BigNumber} sine or cosine of x
+ */
+function cos_sin_taylor(x, mode) {
+  var one = x.constructor.ONE;
+
+  var y = x;
+  var yPrev = NaN;
+  var x2 = x.times(x);
+  var num = (mode) ? y : y = one;
+  var den = one;
+  var add = true;
+
+  for (var k = mode; !y.equals(yPrev); k += 2) {
+    num = num.times(x2);
+    den = den.times(k+1).times(k+2);
+
+    yPrev = y;
+    add = !add;
+    y = (add) ? y.plus(num.div(den)) : y.minus(num.div(den));
+  }
+
+  return y;
+}
+
+/**
+ * Reduce x within a period of pi (0, pi] with guard digits.
+ *
+ * @param {BigNumber} x
+ * @param {Number} precision
+ * @param {Number} mode
+ * @returns {Array} [Reduced x, is tau multiple?]
+ */
+function reduceToPeriod(x, precision, mode) {
+  var Big = x.constructor;
+  var prec_plus_guard_digits = precision + (Math.log(precision) | 0) + 3;
+
+  Big.config({precision: prec_plus_guard_digits});
+  var pi = exports.pi(prec_plus_guard_digits + 2);
+  var tau = exports.tau(prec_plus_guard_digits);
+
+  // Catch if input is tau multiple using pi's precision
+  if (x.div(pi.toDP(x.dp(), 1)).toNumber() % 2 == 0) {
+    Big.config({precision: precision});
+    return [new Big(mode ^ 1), true];
+  }
+
+  var y = x.mod(tau);
+  y.constructor = BigNumber.constructor({precision: prec_plus_guard_digits});
+  Big.config({precision: precision});
+
+  // Catch if tau multiple with tau's precision
+  if (y.toDP(x.dp(), 1).isZero()) {
+    return [new Big(mode ^ 1), true];
+  }
+
+  if (y.gt(pi)) {
+    if (mode) {
+      // sin(x + pi) = -sin(x)
+      y = y.minus(pi);
+      y.s = -y.s;
+    } else {
+      // cos(x) = cos(tau - x)
+      y = tau.minus(y);
+    }
+  }
+
+  return [y, false];
+}
+
+
+/************************************
+ *         Format functions         *
+ ************************************/
 
 /**
  * Convert a number to a formatted string representation.
@@ -634,127 +853,3 @@ exports.toFixed = function(value, precision) {
   // Note: the (precision || 0) is needed as the toFixed of BigNumber has an
   // undefined default precision instead of 0.
 };
-
-
-/* Private functions. */
-
-
-function bitwise(x, y, func) {
-  var BigNumber = x.constructor;
-
-  var xBits, yBits;
-  var xSign = +(x.s < 0);
-  var ySign = +(y.s < 0);
-  if (xSign) {
-    xBits = decToBinary(coefficientToString(exports.not(x)));
-    for (var i = 0; i < xBits.length; ++i) {
-      xBits[i] ^= 1;
-    }
-  } else {
-    xBits = decToBinary(coefficientToString(x));
-  }
-  if (ySign) {
-    yBits = decToBinary(coefficientToString(exports.not(y)));
-    for (var i = 0; i < yBits.length; ++i) {
-      yBits[i] ^= 1;
-    }
-  } else {
-    yBits = decToBinary(coefficientToString(y));
-  }
-
-  var minBits, maxBits, minSign;
-  if (xBits.length <= yBits.length) {
-    minBits = xBits;
-    maxBits = yBits;
-    minSign = xSign;
-  } else {
-    minBits = yBits;
-    maxBits = xBits;
-    minSign = ySign;
-  }
-
-  var shortLen = minBits.length;
-  var longLen = maxBits.length;
-  var expFuncVal = func(xSign, ySign) ^ 1;
-  var outVal = new BigNumber(expFuncVal ^ 1);
-  var twoPower = BigNumber.ONE;
-  var two = new BigNumber(2);
-
-  var prevPrec = BigNumber.precision;
-  BigNumber.config({precision: 1E9});
-
-  while (shortLen > 0) {
-    if (func(minBits[--shortLen], maxBits[--longLen]) == expFuncVal) {
-      outVal = outVal.plus(twoPower);
-    }
-    twoPower = twoPower.times(two);
-  }
-  while (longLen > 0) {
-    if (func(minSign, maxBits[--longLen]) == expFuncVal) {
-      outVal = outVal.plus(twoPower);
-    }
-    twoPower = twoPower.times(two);
-  }
-
-  BigNumber.config({precision: prevPrec});
-
-  if (expFuncVal == 0) {
-    outVal.s = -outVal.s;
-  }
-  return outVal;
-}
-
-
-/* Private functions extracted from decimal.js, and edited to specialize. */
-
-
-function coefficientToString(x) {
-  var a = x.c;
-  var r = a[0] + '';
-
-  for (var i = 1; i < a.length; ++i) {
-    var s = a[i] + '';
-    for (var z = 7 - s.length; z--; ) {
-      s = '0' + s;
-    }
-
-    r += s;
-  }
-
-  var j;
-  for (j = r.length - 1; r.charAt(j) == '0'; --j);
-
-  var xe = x.e;
-  var str = r.slice(0, j + 1 || 1);
-  var strL = str.length;
-  if (xe > 0) {
-    if (++xe > strL) {
-      // Append zeros.
-      for (xe -= strL; xe--; str += '0');
-    } else if (xe < strL) {
-      str = str.slice(0, xe) + '.' + str.slice(xe);
-    }
-  }
-  return str;
-}
-
-function decToBinary(str) {
-  var arr = [0];
-  for (var i = 0; i < str.length; ) {
-    for (var arrL = arr.length; arrL--; arr[arrL] *= 10);
-
-    arr[0] += str.charAt(i++) << 0;  // convert to int
-    for (var j = 0; j < arr.length; ++j) {
-      if (arr[j] > 1) {
-        if (arr[j + 1] == null) {
-          arr[j + 1] = 0;
-        }
-
-        arr[j + 1] += arr[j] >> 1;
-        arr[j] &= 1;
-      }
-    }
-  }
-
-  return arr.reverse();
-}
diff --git a/package.json b/package.json
index d7c96da14..8abeffea0 100644
--- a/package.json
+++ b/package.json
@@ -27,9 +27,7 @@
     "Ryan Seys (https://github.com/ryanseys)",
     "Elijah Insua (https://github.com/tmpvar)",
     "Rogelio J. Baucells (https://github.com/rjbaucells)",
-    "Zach Zibrat (https://github.com/palimpsests)",
-    "Pete Corey (https://github.com/pcorey)",
-    "Kenan Yildirim (https://github.com/KenanY)"
+    "Zach Zibrat (https://github.com/palimpsests)"
   ],
   "homepage": "http://mathjs.org",
   "repository": {


Test patch:
diff --git a/test/expression/parse.test.js b/test/expression/parse.test.js
index f107a25e5..9ef5abaee 100644
--- a/test/expression/parse.test.js
+++ b/test/expression/parse.test.js
@@ -1300,33 +1300,36 @@ describe('parse', function() {
   });
 
   describe('functions', function () {
-    it('should evaluate function "mod"', function () {
-      approx.equal(parseAndEval('mod(8, 3)'), 2);
+    describe('functions', function () {
+      it('should evaluate function "mod"', function () {
+        approx.equal(parseAndEval('mod(8, 3)'), 2);
 
-    });
+      });
 
-    it('should evaluate function "to" ', function () {
-      approx.deepEqual(parseAndEval('to(5.08 cm * 1000, inch)'),
-          math.unit(2000, 'inch').to('inch'));
-    });
+      it('should evaluate function "to" ', function () {
+        approx.deepEqual(parseAndEval('to(5.08 cm * 1000, inch)'),
+            math.unit(2000, 'inch').to('inch'));
+      });
 
-    it('should evaluate function "sort" with a custom sort function', function () {
-      var scope = {};
-      parseAndEval('sortByLength(a, b) = size(a)[1] - size(b)[1]', scope);
-      assert.deepEqual(parseAndEval('sort(["Langdon", "Tom", "Sara"], sortByLength)', scope),
-          math.matrix(["Tom", "Sara", "Langdon"]));
-    });
+      it('should evaluate function "sort" with a custom sort function', function () {
+        var scope = {};
+        parseAndEval('sortByLength(a, b) = size(a)[1] - size(b)[1]', scope);
+        assert.deepEqual(parseAndEval('sort(["Langdon", "Tom", "Sara"], sortByLength)', scope),
+            math.matrix(["Tom", "Sara", "Langdon"]));
+      });
 
-    it('should evaluate function "filter" with a custom test function', function () {
-      var scope = {};
-      parseAndEval('isPositive(x) = x > 0', scope);
-      assert.deepEqual(parseAndEval('filter([6, -2, -1, 4, 3], isPositive)', scope),
-          math.matrix([6, 4, 3]));
-    });
+      it('should evaluate function "filter" with a custom test function', function () {
+        var scope = {};
+        parseAndEval('isPositive(x) = x > 0', scope);
+        assert.deepEqual(parseAndEval('filter([6, -2, -1, 4, 3], isPositive)', scope),
+            math.matrix([6, 4, 3]));
+      });
+
+      it('should evaluate function "filter" with a custom test equation', function () {
+        assert.deepEqual(parseAndEval('filter([6, -2, -1, 4, 3], x > 0)'),
+            math.matrix([6, 4, 3]));
+      });
 
-    it('should evaluate function "filter" with a custom test equation', function () {
-      assert.deepEqual(parseAndEval('filter([6, -2, -1, 4, 3], x > 0)'),
-          math.matrix([6, 4, 3]));
     });
 
   });
diff --git a/test/function/matrix/trace.test.js b/test/function/matrix/trace.test.js
deleted file mode 100644
index 23c28a9ca..000000000
--- a/test/function/matrix/trace.test.js
+++ /dev/null
@@ -1,114 +0,0 @@
-var assert = require('assert'),
-    error = require('../../../lib/error/index'),
-    approx = require('../../../tools/approx'),
-    math = require('../../../index');
-
-describe('trace', function() {
-
-  it('should calculate correctly the trace of a NxN matrix', function() {
-    assert.equal(math.trace([5]), 5);
-    assert.equal(math.trace([[1,2],[3,4]]), 5);
-    assert.equal(math.trace(math.matrix([[1,2],[3,4]])), 5);
-    approx.equal(math.trace([
-      [-2, 2,  3],
-      [-1, 1,  3],
-      [ 2, 0, -1]
-    ]), -2);
-    approx.equal(math.trace([
-      [ 1, 4,  7],
-      [ 3, 0,  5],
-      [-1, 9, 11]
-    ]), 12);
-    approx.equal(math.trace([
-      [1,7,4,3,7], 
-      [0,7,0,3,7], 
-      [0,7,4,3,0], 
-      [1,7,5,9,7], 
-      [2,7,4,3,7]
-    ]), 28);
-    approx.equal(math.trace(math.diag([4,-5,6])), 5);
-  });
-
-  it('should return N for the identity matrix',function() {
-    assert.equal(math.trace(math.eye(7)), 7);
-    assert.equal(math.trace(math.eye(2)), 2);
-    assert.equal(math.trace(math.eye(1)), 1);
-  });
-
-  it('should calculate the trace for a scalar',function() {
-    assert.equal(math.trace(7), 7);
-
-    var c1 = math.complex(2, 3);
-    var c2 = math.trace(c1);
-    assert.deepEqual(c1, c2);
-
-    // c2 should be a clone
-    c1.re = 0;
-    assert.equal(c1.re, 0);
-    assert.equal(c2.re, 2);
-  });
-
-  it('should calculate the trace for a 1x1 matrix',function() {
-    var c1 = math.complex(2, 3);
-    var c2 = math.trace([[c1]]);
-    assert.deepEqual(c1, c2);
-
-    // c2 should be a clone
-    c1.re = 0;
-    assert.equal(c1.re, 0);
-    assert.equal(c2.re, 2);
-  });
-
-  it('should calculate correctly the trace of a matrix with bignumbers', function() {
-    var bignumber = math.bignumber;
-
-    // 1x1
-    assert.deepEqual(math.trace([bignumber(5)]), bignumber(5));
-
-    // 2x2
-    assert.deepEqual(math.trace([
-      [bignumber(1), bignumber(2)],
-      [bignumber(3), bignumber(4)]
-    ]), bignumber(5));
-
-    // 3x3
-    assert.deepEqual(math.trace([
-      [bignumber(-2), bignumber(2), bignumber( 3)],
-      [bignumber(-1), bignumber(1), bignumber( 3)],
-      [bignumber( 2), bignumber(0), bignumber(-1)]
-    ]), bignumber(-2));
-
-    // the following would fail with regular Numbers due to a precision overflow
-    assert.deepEqual(math.trace([
-      [bignumber(1e10+1), bignumber(1e10)],
-      [bignumber(1e10), bignumber(-1e10)]
-    ]), bignumber(1));
-  });
-
-  it('should calculate the trace of a matrix with mixed numbers and bignumbers', function() {
-    var bignumber = math.bignumber;
-    assert.deepEqual(math.trace([
-      [bignumber(2), 1],
-      [bignumber(3), 4]
-    ]), bignumber(6));
-  });
-
-  it('should not change the value of the initial matrix', function() {
-    var m_test = [[1,2,3],[4,5,6],[7,8,9]];
-    math.trace(m_test);
-    assert.deepEqual(m_test, [[1,2,3],[4,5,6],[7,8,9]]);
-  });
-
-  it('should not accept a non-square matrix', function() {
-    assert.throws(function() { math.trace([1,2]); });
-    assert.throws(function() { math.trace([[1,2,3],[1,2,3]]); });
-    assert.throws(function() { math.trace([0,1],[0,1],[0,1]); });
-  });
-
-  it('should not accept arrays with dimensions higher than 2', function() {
-    assert.throws(function() { math.trace([[[1]]]); }, RangeError);
-    assert.throws(function() { math.trace(math.matrix([[[1]]])); }, RangeError);
-  });
-
-
-});
\ No newline at end of file
diff --git a/test/function/trigonometry/cos.test.js b/test/function/trigonometry/cos.test.js
index f4b8c14ff..c530e948b 100644
--- a/test/function/trigonometry/cos.test.js
+++ b/test/function/trigonometry/cos.test.js
@@ -29,12 +29,46 @@ describe('cos', function() {
     approx.equal(cos(pi*6/4), 0);
     approx.equal(cos(pi*7/4), 0.707106781186548);
     approx.equal(cos(pi*8/4), 1);
-    approx.equal(cos(pi/4), math.sqrt(2)/2);
-    assert.ok(cos(complex('1e-50+1e-50i')).im != 0);
+    approx.equal(cos(pi/4), Math.SQRT1_2);
   });
 
-  it('should return the cosine of a bignumber (downgrades to number)', function() {
-    approx.equal(cos(math.bignumber(1)), 0.54030230586814);
+  it('should return the cosine of a bignumber', function() {
+    var bigmath = math.create({number: 'bignumber', precision: 238});
+    assert.deepEqual(bigmath.cos(bigmath.bignumber(0)), bigmath.bignumber(1));
+
+    // 103.64 % tau = 3.109... <- pretty close to the pi boundary
+    var result_val = '-0.99947004918247698171247470962484532559534008595265991588' +
+                        '25959085696348870383952892132851183764863885182646678036' +
+                        '80857263937361947475191126604630777331941809888320749410' +
+                        '59494006339537812110786663367929884637840572887762249921' +
+                        '8425619255481';
+    var cos_val = bigmath.cos(bigmath.bignumber(103.64));
+    assert.equal(cos_val.constructor.precision, 238);
+    assert.deepEqual(cos_val.toString(), result_val);
+
+    cos_val = bigmath.cos(bigmath.bignumber(-103.64));
+    assert.equal(cos_val.constructor.precision, 238);
+    assert.deepEqual(cos_val.toString(), result_val);
+
+    bigmath.config({precision: 15});
+
+    var bigPi = bigmath.pi;
+    result_val = bigmath.SQRT2.div(2).toString();
+
+    assert.deepEqual(bigmath.cos(bigPi.div(4)).toString(), result_val);
+    assert.ok(bigmath.cos(bigPi.div(2)).isZero());
+    assert.deepEqual(bigmath.cos(bigPi).toString(), '-1');
+    assert.ok(bigmath.cos(bigPi.times(3).div(2)).isZero());
+    assert.deepEqual(bigmath.cos(bigPi.times(2)).toString(), '1');
+
+    assert.deepEqual(bigmath.cos(bigmath.tau).toString(), '1');
+    assert.deepEqual(bigmath.cos(bigmath.tau.times(2)).toString(), '1');
+
+    /* If we ever decide to pass in more digits of pi, uncomment these.
+    assert.deepEqual(bigmath.cos(bigPi.times(3).div(4)).toString(), '-'+result_val);
+    assert.deepEqual(bigmath.cos(bigPi.times(5).div(4)).toString(), '-'+result_val);
+    assert.deepEqual(bigmath.cos(bigPi.times(7).div(4)).toString(), result_val);
+    */
   });
 
   it('should return the cosine of a complex number', function() {
@@ -47,6 +81,7 @@ describe('cos', function() {
     approx.deepEqual(cos(complex('i')), complex(1.54308063481524, 0));
     approx.deepEqual(cos(complex('1')), complex(0.540302305868140, 0));
     approx.deepEqual(cos(complex('1+i')), complex(0.833730025131149, -0.988897705762865));
+    assert.ok(cos(complex('1e-50+1e-50i')).im != 0);
   });
 
   it('should return the cosine of an angle', function() {
diff --git a/test/function/trigonometry/csch.test.js b/test/function/trigonometry/csch.test.js
index 616fbcc82..8dbc2555f 100644
--- a/test/function/trigonometry/csch.test.js
+++ b/test/function/trigonometry/csch.test.js
@@ -24,6 +24,7 @@ describe('csch', function() {
     approx.equal(csch(1), 0.85091812823932);
     approx.equal(csch(2), 0.27572056477178);
     approx.equal(csch(3), 0.099821569668823);
+    approx.equal(csch(3), 0.099821569668823);
     approx.equal(csch(1e-22), Number.POSITIVE_INFINITY);
     approx.equal(csch(-1e-22), Number.NEGATIVE_INFINITY);
   });
diff --git a/test/function/trigonometry/sin.test.js b/test/function/trigonometry/sin.test.js
index 5949c1026..7a49bb6cc 100644
--- a/test/function/trigonometry/sin.test.js
+++ b/test/function/trigonometry/sin.test.js
@@ -21,7 +21,7 @@ describe('sin', function() {
   it('should return the sine of a number', function() {
     approx.equal(sin(0), 0);
     approx.equal(sin(pi/8), 0.382683432365090);
-    approx.equal(sin(pi/4), Math.SQRT2/2);
+    approx.equal(sin(pi/4), Math.SQRT1_2);
     approx.equal(sin(pi/2), 1);
     approx.equal(sin(pi*3/4), 0.707106781186548);
     approx.equal(sin(pi), 0);
@@ -33,8 +33,8 @@ describe('sin', function() {
 
   it('should return the sine of a bignumber', function() {
     var bigmath = math.create({number: 'bignumber', precision: 242});
-    assert.deepEqual(bigmath.sin(bigmath.bignumber(0)), bigmath.bignumber(0));
-    
+    assert.ok(bigmath.sin(bigmath.bignumber(0)).isZero());
+
     // 103.64 % tau = 3.109... <- pretty close to the pi boundary
     var result_val = bigmath.sin(bigmath.bignumber(103.64));
     assert.equal(result_val.constructor.precision, 242);
@@ -52,16 +52,17 @@ describe('sin', function() {
 
     var bigPi = bigmath.pi;
     result_val = bigmath.SQRT2.div(2).toString();
+    assert.deepEqual(bigmath.sin(bigPi.div(8)).toString(), '0.38268343236509');
     assert.deepEqual(bigmath.sin(bigPi.div(4)).toString(), result_val);
     assert.deepEqual(bigmath.sin(bigPi.div(2)).toString(), '1');
     assert.deepEqual(bigmath.sin(bigPi.times(3).div(4)).toString(), result_val);
-    assert.equal(bigmath.sin(bigPi).isZero(), true);
+    assert.ok(bigmath.sin(bigPi).isZero());
     assert.deepEqual(bigmath.sin(bigPi.times(5).div(4)).toString(), '-'+result_val);
     assert.deepEqual(bigmath.sin(bigPi.times(3).div(2)).toString(), '-1');
     assert.deepEqual(bigmath.sin(bigPi.times(7).div(4)).toString(), '-'+result_val);
-    assert.equal(bigmath.sin(bigPi.times(2)).isZero(), true);
-    assert.equal(bigmath.sin(bigmath.tau).isZero(), true);
-    assert.equal(bigmath.sin(bigmath.tau.times(2)).isZero(), true);
+    assert.ok(bigmath.sin(bigPi.times(2)).isZero());
+    assert.ok(bigmath.sin(bigmath.tau).isZero());
+    assert.ok(bigmath.sin(bigmath.tau.times(2)).isZero());
   });
 
   it('should return the sine of a complex number', function() {