function _compareNatural (x, y) {
    const typeX = typeOf(x)
    const typeY = typeOf(y)
    let c

    // numeric types
    if ((typeX === 'number' || typeX === 'BigNumber' || typeX === 'Fraction') &&
        (typeY === 'number' || typeY === 'BigNumber' || typeY === 'Fraction')) {
      c = compare(x, y)
      if (c.toString() !== '0') {
        // c can be number, BigNumber, or Fraction
        return c > 0 ? 1 : -1 // return a number
      } else {
        return naturalSort(typeX, typeY)
      }
    }

    // matrix types
    const matTypes = ['Array', 'DenseMatrix', 'SparseMatrix']
    if (matTypes.includes(typeX) || matTypes.includes(typeY)) {
      c = compareMatricesAndArrays(_compareNatural, x, y)
      if (c !== 0) {
        return c
      } else {
        return naturalSort(typeX, typeY)
      }
    }

    // in case of different types, order by name of type, i.e. 'BigNumber' < 'Complex'
    if (typeX !== typeY) {
      return naturalSort(typeX, typeY)
    }

    if (typeX === 'Complex') {
      return compareComplexNumbers(x, y)
    }

    if (typeX === 'Unit') {
      if (x.equalBase(y)) {
        return _compareNatural(x.value, y.value)
      }

      // compare by units
      return compareArrays(_compareNatural, x.formatUnits(), y.formatUnits())
    }

    if (typeX === 'boolean') {
      return compareBooleans(x, y)
    }

    if (typeX === 'string') {
      return naturalSort(x, y)
    }

    if (typeX === 'Object') {
      return compareObjects(_compareNatural, x, y)
    }

    if (typeX === 'null') {
      return 0
    }

    if (typeX === 'undefined') {
      return 0
    }

    // this should not occur...
    throw new TypeError('Unsupported type of value "' + typeX + '"')
  }
Compare two values of any type in a deterministic, natural way.

For numeric values, the function works the same as `math.compare`.
For types of values that can't be compared mathematically,
the function compares in a natural way.

For numeric values, x and y are considered equal when the relative
difference between x and y is smaller than the configured relTol and absTol.
The function cannot be used to compare values smaller than
approximately 2.22e-16.

For Complex numbers, first the real parts are compared. If equal,
the imaginary parts are compared.

Strings are compared with a natural sorting algorithm, which
orders strings in a "logic" way following some heuristics.
This differs from the function `compare`, which converts the string
into a numeric value and compares that. The function `compareText`
on the other hand compares text lexically.

Arrays and Matrices are compared value by value until there is an
unequal pair of values encountered. Objects are compared by sorted
keys until the keys or their values are unequal.

Syntax:

   math.compareNatural(x, y)

Examples:

   math.compareNatural(6, 1)              // returns 1
   math.compareNatural(2, 3)              // returns -1
   math.compareNatural(7, 7)              // returns 0

   math.compareNatural('10', '2')         // returns 1
   math.compareText('10', '2')            // returns -1
   math.compare('10', '2')                // returns 1

   math.compareNatural('Answer: 10', 'Answer: 2') // returns 1
   math.compareText('Answer: 10', 'Answer: 2')    // returns -1
   math.compare('Answer: 10', 'Answer: 2')
       // Error: Cannot convert "Answer: 10" to a number

   const a = math.unit('5 cm')
   const b = math.unit('40 mm')
   math.compareNatural(a, b)              // returns 1

   const c = math.complex('2 + 3i')
   const d = math.complex('2 + 4i')
   math.compareNatural(c, d)              // returns -1

   math.compareNatural([1, 2, 4], [1, 2, 3]) // returns 1
   math.compareNatural([1, 2, 3], [1, 2])    // returns 1
   math.compareNatural([1, 5], [1, 2, 3])    // returns 1
   math.compareNatural([1, 2], [1, 2])       // returns 0

   math.compareNatural({a: 2}, {a: 4})       // returns -1

See also:

   compare, compareText

@param  {*} x First value to compare
@param  {*} y Second value to compare
@return {number} Returns the result of the comparison:
                 1 when x > y, -1 when x < y, and 0 when x == y.