function approxEqual (a, b, epsilon) {
  if (epsilon === undefined) {
    epsilon = EPSILON
  }

  if (isNumber(a) && isNumber(b)) {
    if (a === b) {
      // great, we're done :)
    } else if (isNaN(a)) {
      assert.strictEqual(a.toString(), b.toString())
    } else if (a === 0) {
      assert.ok(Math.abs(b) < epsilon, (a + ' ~= ' + b))
    } else if (b === 0) {
      assert.ok(Math.abs(a) < epsilon, (a + ' ~= ' + b))
    } else {
      const diff = Math.abs(a - b)
      const max = Math.max(a, b)
      const maxDiff = Math.abs(max * epsilon)
      assert.ok(diff <= maxDiff, (a + ' ~= ' + b + ' (epsilon: ' + epsilon + ')'))
    }
  } else if (a && a.isBigNumber) {
    return approxEqual(a.toNumber(), b, epsilon)
  } else if (b && b.isBigNumber) {
    return approxEqual(a, b.toNumber(), epsilon)
  } else if ((a && a.isComplex) || (b && b.isComplex)) {
    if (a && a.isComplex && b && b.isComplex) {
      approxEqual(a.re, b.re, epsilon)
      approxEqual(a.im, b.im, epsilon)
    } else if (a && a.isComplex) {
      approxEqual(a.re, b, epsilon)
      approxEqual(a.im, 0, epsilon)
    } else if (b && b.isComplex) {
      approxEqual(a, b.re, epsilon)
      approxEqual(0, b.im, epsilon)
    }
  } else {
    assert.strictEqual(a, b)
  }
}
Test whether two values are approximately equal. Tests whether the difference
between the two numbers is smaller than a fraction of their max value.
@param {Number | BigNumber | Complex | Fraction} a
@param {Number | BigNumber | Complex | Fraction} b
@param {Number} [epsilon]