Glen Whitney 82074e85e0
fix: Type declarations for rounding functions (#2539)
This is a sequel to #2531. Uniformizes the signatures of ceil, fix, floor,
  and round, and updates the TypeScript declarations to match. Adds the
  optional "number of places" argument to the chain versions of ceil, fix,
  and floor. Adds TypeScript tests for all rounding functions.

  Also corrects the TypeScript declaration for `bignumber()` and introduces
  a couple more common abbreviations for TypeScript types.

  Fixes the number-only implementations of floor, ceil, fix, and nthRoot
  to match the full implementation behavior on numbers, and tests this for
  floor.

  Includes some minor documentation updates and additional unit tests for
  the rounding functions.

  Reverts inclusion in AUTHORS of incorrect email for one contributor,
  that occurred in #2531.

  Resolves #2526.
  Resolves #2529.
2022-04-25 12:07:02 +02:00

189 lines
8.9 KiB
JavaScript

// test round
import assert from 'assert'
import approx from '../../../../tools/approx.js'
import math from '../../../../src/defaultInstance.js'
const bignumber = math.bignumber
const complex = math.complex
const fraction = math.fraction
const matrix = math.matrix
const sparse = math.sparse
const round = math.round
describe('round', function () {
it('should round a number to te given number of decimals', function () {
approx.equal(round(math.pi), 3)
approx.equal(round(math.pi * 1000), 3142)
approx.equal(round(math.pi, 3), 3.142)
approx.equal(round(math.pi, 6), 3.141593)
approx.equal(round(1234.5678, 2), 1234.57)
approx.equal(round(2.135, 2), 2.14)
assert.strictEqual(round(2.7), 3)
assert.strictEqual(round(2.5), 3)
assert.strictEqual(round(2.5, 0), 3)
assert.strictEqual(round(-2.5), -3)
assert.strictEqual(round(-2.7), -3)
assert.strictEqual(round(-2.5, 0), -3)
})
it('should round booleans (yeah, not really useful but it should be supported)', function () {
approx.equal(round(true), 1)
approx.equal(round(false), 0)
approx.equal(round(true, 2), 1)
approx.equal(round(false, 2), 0)
})
it('should throw an error on invalid type of value', function () {
assert.throws(function () { round(new Date()) }, /TypeError: Unexpected type of argument/)
})
it('should throw an error on invalid type of n', function () {
assert.throws(function () { round(math.pi, new Date()) }, /TypeError: Unexpected type of argument/)
})
it('should throw an error on invalid value of n', function () {
assert.throws(function () { round(math.pi, -2) }, /Number of decimals in function round must be .* 0 .* 15/)
assert.throws(function () { round(math.pi, 20) }, /Number of decimals in function round must be .* 0 .* 15/)
assert.throws(function () { round(math.pi, 2.5) }, /Number of decimals in function round must be an integer/)
assert.throws(function () { round(1, 1.2) }, /Error: Number of decimals in function round must be an integer/)
assert.throws(function () { round(1, bignumber(1.2)) }, /Error: Number of decimals in function round must be an integer/)
assert.throws(function () { round(complex(1, 1), 1.2) }, /Error: Number of decimals in function round must be an integer/)
assert.throws(function () { round(complex(1, 1), bignumber(1.2)) }, /Error: Number of decimals in function round must be an integer/)
assert.throws(function () { round(bignumber(1.2), bignumber(1.2)) }, /Error: Number of decimals in function round must be an integer/)
assert.throws(function () { round(round(fraction('1/2'), 1.2)) }, /Error: Number of decimals in function round must be an integer/)
})
it('should throw an error if used with wrong number of arguments', function () {
assert.throws(function () { round() }, /TypeError: Too few arguments/)
assert.throws(function () { round(1, 2, 3) }, /TypeError: Too many arguments/)
})
it('should throw an in case of wrong type of arguments', function () {
assert.throws(function () { round(null) }, /TypeError: Unexpected type of argument/)
})
it('should round bignumbers', function () {
assert.deepStrictEqual(round(bignumber(2.7)), bignumber(3))
assert.deepStrictEqual(round(bignumber(2.5)), bignumber(3))
assert.deepStrictEqual(round(bignumber(-2.5)), bignumber(-3))
assert.deepStrictEqual(round(bignumber(2.5), 0), bignumber(3))
assert.deepStrictEqual(round(bignumber(-2.5), 0), bignumber(-3))
assert.deepStrictEqual(round(bignumber(2.1)), bignumber(2))
assert.deepStrictEqual(round(bignumber(2.123456), bignumber(3)), bignumber(2.123))
assert.deepStrictEqual(round(bignumber(2.123456), 3), bignumber(2.123))
assert.deepStrictEqual(round(2.1234567, bignumber(3)), bignumber(2.123))
assert.deepStrictEqual(round(true, bignumber(3)), bignumber(1))
assert.deepStrictEqual(round(bignumber(1.23), true), bignumber(1.2))
})
it('should round fractions', function () {
const a = fraction('2/3')
assert(round(a) instanceof math.Fraction)
assert.strictEqual(a.toString(), '0.(6)')
assert.strictEqual(round(fraction('2/3')).toString(), '1')
assert.strictEqual(round(fraction('1/3')).toString(), '0')
assert.strictEqual(round(fraction('1/2')).toString(), '1')
assert.strictEqual(round(fraction('1/2'), 1).toString(), '0.5')
assert.deepStrictEqual(round(fraction(2, 3), bignumber(2)), fraction(67, 100))
})
it('should gracefully handle round-off errors', function () {
assert.strictEqual(round(3.0000000000000004), 3)
assert.strictEqual(round(7.999999999999999), 8)
assert.strictEqual(round(-3.0000000000000004), -3)
assert.strictEqual(round(-7.999999999999999), -8)
assert.strictEqual(round(30000.000000000004), 30000)
assert.strictEqual(round(799999.9999999999), 800000)
assert.strictEqual(round(-30000.000000000004), -30000)
assert.strictEqual(round(-799999.9999999999), -800000)
assert.strictEqual(round(3.0000000000000004, 2), 3)
assert.strictEqual(round(7.999999999999999, 2), 8)
assert.strictEqual(round(-3.0000000000000004, 2), -3)
assert.strictEqual(round(-7.999999999999999, 2), -8)
assert.strictEqual(round(30000.000000000004, 2), 30000)
assert.strictEqual(round(799999.9999999999, 2), 800000)
assert.strictEqual(round(-30000.000000000004, 2), -30000)
assert.strictEqual(round(-799999.9999999999, 2), -800000)
})
it('should round real and imag part of a complex number', function () {
assert.deepStrictEqual(round(complex(2.2, math.pi)), complex(2, 3))
})
it('should round a complex number with a bignumber as number of decimals', function () {
assert.deepStrictEqual(round(complex(2.157, math.pi), bignumber(2)), complex(2.16, 3.14))
})
it('should throw an error if used with a unit', function () {
assert.throws(function () { round(math.unit('5cm')) }, TypeError, 'Function round(unit) not supported')
assert.throws(function () { round(math.unit('5cm'), 2) }, TypeError, 'Function round(unit) not supported')
assert.throws(function () { round(math.unit('5cm'), bignumber(2)) }, TypeError, 'Function round(unit) not supported')
})
it('should convert to a number when used with a string', function () {
assert.strictEqual(round('3.6'), 4)
assert.strictEqual(round('3.12345', '3'), 3.123)
assert.throws(function () { round('hello world') }, /Cannot convert "hello world" to a number/)
})
it('should round each element in a matrix, array, range', function () {
assert.deepStrictEqual(round(math.range(0, 2.1, 1 / 3), 2), math.matrix([0, 0.33, 0.67, 1, 1.33, 1.67, 2]))
assert.deepStrictEqual(round(math.range(0, 2.1, 1 / 3)), math.matrix([0, 0, 1, 1, 1, 2, 2]))
assert.deepStrictEqual(round([1.7, 2.3]), [2, 2])
assert.deepStrictEqual(round(math.matrix([1.7, 2.3])).valueOf(), [2, 2])
})
describe('Array', function () {
it('should round array', function () {
assert.deepStrictEqual(round([1.7, 2.3]), [2, 2])
})
it('should round array and scalar', function () {
assert.deepStrictEqual(round([1.7777, 2.3456], 3), [1.778, 2.346])
assert.deepStrictEqual(round(3.12385, [2, 3]), [3.12, 3.124])
assert.deepStrictEqual(round(fraction(44, 7), [2, 3]),
[fraction(629, 100), fraction(6286, 1000)])
})
})
describe('DenseMatrix', function () {
it('should round dense matrix', function () {
assert.deepStrictEqual(round(matrix([[1.7, 2.3], [8.987, -3.565]])), matrix([[2, 2], [9, -4]]))
})
it('should round dense matrix and scalar', function () {
assert.deepStrictEqual(round(matrix([[1.7777, 2.3456], [-90.8272, 0]]), 3), matrix([[1.778, 2.346], [-90.827, 0]]))
assert.deepStrictEqual(round(3.12385, matrix([[2, 3], [0, 2]])), matrix([[3.12, 3.124], [3, 3.12]]))
assert.deepStrictEqual(round(0.0, matrix([2, 3])), matrix([0, 0]))
assert.deepStrictEqual(round(complex(2.7182, 6.2831), matrix([2, 3])),
matrix([complex(2.72, 6.28), complex(2.718, 6.283)]))
})
})
describe('SparseMatrix', function () {
it('should round sparse matrix', function () {
assert.deepStrictEqual(round(sparse([[1.7, 0], [8.987, -3.565]])), sparse([[2, 0], [9, -4]]))
})
it('should round sparse matrix and scalar', function () {
assert.deepStrictEqual(round(sparse([[1.7777, 2.3456], [-90.8272, 0]]), 3), sparse([[1.778, 2.346], [-90.827, 0]]))
assert.deepStrictEqual(round(3.12385, sparse([[2, 3], [0, 2]])), matrix([[3.12, 3.124], [3, 3.12]]))
assert.deepStrictEqual(round(0.0, sparse([2, 3])), sparse([0, 0]))
assert.deepStrictEqual(round(bignumber(6.28318), sparse([0, 4])),
matrix([[bignumber(6)], [bignumber(6.2832)]]))
})
})
it('should LaTeX round', function () {
const expr1 = math.parse('round(1.1)')
const expr2 = math.parse('round(1.1,2)')
assert.strictEqual(expr1.toTex(), '\\left\\lfloor1.1\\right\\rceil')
assert.strictEqual(expr2.toTex(), '\\mathrm{round}\\left(1.1,2\\right)')
})
})