Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

floor and cell with precision #1967

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
66 changes: 63 additions & 3 deletions src/function/arithmetic/ceil.js
@@ -1,13 +1,19 @@
import { Decimal } from 'decimal.js'
import { factory } from '../../utils/factory'
import { deepMap } from '../../utils/collection'
import { nearlyEqual } from '../../utils/number'
import { nearlyEqual as bigNearlyEqual } from '../../utils/bignumber/nearlyEqual'
import { ceilNumber } from '../../plain/number'
import { createAlgorithm11 } from '../../type/matrix/utils/algorithm11'
import { createAlgorithm14 } from '../../type/matrix/utils/algorithm14'

const name = 'ceil'
const dependencies = ['typed', 'config', 'round']
const dependencies = ['typed', 'config', 'round', 'matrix', 'equalScalar']

export const createCeil = /* #__PURE__ */ factory(name, dependencies, ({ typed, config, round, matrix, equalScalar }) => {
const algorithm11 = createAlgorithm11({ typed, equalScalar })
const algorithm14 = createAlgorithm14({ typed })

export const createCeil = /* #__PURE__ */ factory(name, dependencies, ({ typed, config, round }) => {
/**
* Round a value towards plus infinity
* If `x` is complex, both real and imaginary part are rounded towards plus infinity.
Expand All @@ -16,6 +22,7 @@ export const createCeil = /* #__PURE__ */ factory(name, dependencies, ({ typed,
* Syntax:
*
* math.ceil(x)
* math.ceil(x, n)
*
* Examples:
*
Expand All @@ -24,16 +31,24 @@ export const createCeil = /* #__PURE__ */ factory(name, dependencies, ({ typed,
* math.ceil(-4.2) // returns number -4
* math.ceil(-4.7) // returns number -4
*
* const c = math.complex(3.2, -2.7)
* math.ceil(3.212, 2) // returns number 3.22
* math.ceil(3.288, 2) // returns number 3.29
* math.ceil(-4.212, 2) // returns number -4.21
* math.ceil(-4.782, 2) // returns number -4.78
*
* const c = math.complex(3.24, -2.71)
* math.ceil(c) // returns Complex 4 - 2i
* math.ceil(c, 1) // returns Complex 3.3 - 2.7i
*
* math.ceil([3.2, 3.8, -4.7]) // returns Array [4, 4, -4]
* math.ceil([3.21, 3.82, -4.71], 1) // returns Array [3.3, 3.9, -4.7]
*
* See also:
*
* floor, fix, round
*
* @param {number | BigNumber | Fraction | Complex | Array | Matrix} x Number to be rounded
* @param {number | BigNumber | Array} [n=0] Number of decimals
* @return {number | BigNumber | Fraction | Complex | Array | Matrix} Rounded value
*/
return typed('ceil', {
Expand All @@ -45,10 +60,25 @@ export const createCeil = /* #__PURE__ */ factory(name, dependencies, ({ typed,
}
},

'number, number': function (x, n) {
if (nearlyEqual(x, round(x, n), config.epsilon)) {
return round(x, n)
} else {
let [number, exponent] = `${x}e`.split('e')
const result = Math.ceil(Number(`${number}e${Number(exponent) + n}`));
[number, exponent] = `${result}e`.split('e')
return Number(`${number}e${Number(exponent) - n}`)
}
},

Complex: function (x) {
return x.ceil()
},

'Complex, number': function (x, n) {
return x.ceil(n)
},

BigNumber: function (x) {
if (bigNearlyEqual(x, round(x), config.epsilon)) {
return round(x)
Expand All @@ -57,13 +87,43 @@ export const createCeil = /* #__PURE__ */ factory(name, dependencies, ({ typed,
}
},

'BigNumber, BigNumber': function (x, n) {
if (bigNearlyEqual(x, round(x, n), config.epsilon)) {
return round(x, n)
} else {
return x.toDecimalPlaces(n.toNumber(), Decimal.ROUND_CEIL)
}
},

Fraction: function (x) {
return x.ceil()
},

'Fraction, number': function (x, n) {
return x.ceil(n)
},

'Array | Matrix': function (x) {
// deep map collection, skip zeros since ceil(0) = 0
return deepMap(x, this, true)
},

'Array | Matrix, number': function (x, n) {
// deep map collection, skip zeros since ceil(0) = 0
return deepMap(x, i => this(i, n), true)
},

'SparseMatrix, number | BigNumber': function (x, y) {
return algorithm11(x, y, this, false)
},

'DenseMatrix, number | BigNumber': function (x, y) {
return algorithm14(x, y, this, false)
},

'number | Complex | BigNumber, Array': function (x, y) {
// use matrix implementation
return algorithm14(matrix(y), x, this, true).valueOf()
}
})
})
51 changes: 45 additions & 6 deletions src/function/arithmetic/fix.js
@@ -1,10 +1,12 @@
import { factory } from '../../utils/factory'
import { deepMap } from '../../utils/collection'
import { createAlgorithm14 } from '../../type/matrix/utils/algorithm14'

const name = 'fix'
const dependencies = ['typed', 'Complex', 'ceil', 'floor']
const dependencies = ['typed', 'Complex', 'matrix', 'ceil', 'floor']

export const createFix = /* #__PURE__ */ factory(name, dependencies, ({ typed, Complex, ceil, floor }) => {
export const createFix = /* #__PURE__ */ factory(name, dependencies, ({ typed, Complex, matrix, ceil, floor }) => {
const algorithm14 = createAlgorithm14({ typed })
/**
* Round a value towards zero.
* For matrices, the function is evaluated element wise.
Expand All @@ -20,41 +22,78 @@ export const createFix = /* #__PURE__ */ factory(name, dependencies, ({ typed, C
* math.fix(-4.2) // returns number -4
* math.fix(-4.7) // returns number -4
*
* const c = math.complex(3.2, -2.7)
* math.fix(3.12, 1) // returns number 3.1
* math.fix(3.18, 1) // returns number 3.1
* math.fix(-4.12, 1) // returns number -4.1
* math.fix(-4.17, 1) // returns number -4.1
*
* const c = math.complex(3.22, -2.78)
* math.fix(c) // returns Complex 3 - 2i
* math.fix(c, 1) // returns Complex 3.2 - 2.7i
*
* math.fix([3.2, 3.8, -4.7]) // returns Array [3, 3, -4]
* math.fix([3.2, 3.8, -4.7]) // returns Array [3, 3, -4]
* math.fix([3.2, 3.8, -4.7], 1) // returns Array [3.2, 3.8, -4.7]
*
* See also:
*
* ceil, floor, round
*
* @param {number | BigNumber | Fraction | Complex | Array | Matrix} x Number to be rounded
* @return {number | BigNumber | Fraction | Complex | Array | Matrix} Rounded value
* @param {number | BigNumber | Fraction | Complex | Array | Matrix} x Number to be rounded
* @param {number | BigNumber | Array} [n=0] Number of decimals
* @return {number | BigNumber | Fraction | Complex | Array | Matrix} Rounded value
*/
return typed('fix', {
number: function (x) {
return (x > 0) ? floor(x) : ceil(x)
},

'number, number | BigNumber': function (x, n) {
return (x > 0) ? floor(x, n) : ceil(x, n)
},

Complex: function (x) {
return new Complex(
(x.re > 0) ? Math.floor(x.re) : Math.ceil(x.re),
(x.im > 0) ? Math.floor(x.im) : Math.ceil(x.im)
)
},

'Complex, number | BigNumber': function (x, n) {
return new Complex(
(x.re > 0) ? floor(x.re, n) : ceil(x.re, n),
(x.im > 0) ? floor(x.im, n) : ceil(x.im, n)
)
},

BigNumber: function (x) {
return x.isNegative() ? ceil(x) : floor(x)
},

'BigNumber, number | BigNumber': function (x, n) {
return x.isNegative() ? ceil(x, n) : floor(x, n)
},

Fraction: function (x) {
return x.s < 0 ? x.ceil() : x.floor()
},

'Fraction, number | BigNumber': function (x, n) {
return x.s < 0 ? x.ceil(n) : x.floor(n)
},

'Array | Matrix': function (x) {
// deep map collection, skip zeros since fix(0) = 0
return deepMap(x, this, true)
},

'Array | Matrix, number | BigNumber': function (x, n) {
// deep map collection, skip zeros since fix(0) = 0
return deepMap(x, i => this(i, n), true)
},

'number | Complex | BigNumber, Array': function (x, y) {
// use matrix implementation
return algorithm14(matrix(y), x, this, true).valueOf()
}
})
})
70 changes: 65 additions & 5 deletions src/function/arithmetic/floor.js
@@ -1,19 +1,26 @@
import { Decimal } from 'decimal.js'
import { factory } from '../../utils/factory'
import { deepMap } from '../../utils/collection'
import { nearlyEqual } from '../../utils/number'
import { nearlyEqual as bigNearlyEqual } from '../../utils/bignumber/nearlyEqual'
import { createAlgorithm11 } from '../../type/matrix/utils/algorithm11'
import { createAlgorithm14 } from '../../type/matrix/utils/algorithm14'

const name = 'floor'
const dependencies = ['typed', 'config', 'round']
const dependencies = ['typed', 'config', 'round', 'matrix', 'equalScalar']

export const createFloor = /* #__PURE__ */ factory(name, dependencies, ({ typed, config, round, matrix, equalScalar }) => {
const algorithm11 = createAlgorithm11({ typed, equalScalar })
const algorithm14 = createAlgorithm14({ typed })

export const createFloor = /* #__PURE__ */ factory(name, dependencies, ({ typed, config, round }) => {
/**
* Round a value towards minus infinity.
* For matrices, the function is evaluated element wise.
*
* Syntax:
*
* math.floor(x)
* math.floor(x, n)
*
* Examples:
*
Expand All @@ -22,16 +29,24 @@ export const createFloor = /* #__PURE__ */ factory(name, dependencies, ({ typed,
* math.floor(-4.2) // returns number -5
* math.floor(-4.7) // returns number -5
*
* const c = math.complex(3.2, -2.7)
* math.floor(c) // returns Complex 3 - 3i
* math.floor(3.212, 2) // returns number 3.21
* math.floor(3.288, 2) // returns number 3.28
* math.floor(-4.212, 2) // returns number -4.22
* math.floor(-4.782, 2) // returns number -4.79
*
* const c = math.complex(3.24, -2.71)
* math.floor(c) // returns Complex 3 - 3i
* math.floor(c, 1) // returns Complex 3.2 - 2.8i
*
* math.floor([3.2, 3.8, -4.7]) // returns Array [3, 3, -5]
* math.floor([3.2, 3.8, -4.7]) // returns Array [3, 3, -5]
* math.floor([3.21, 3.82, -4.71], 1) // returns Array [3.2, 3.8, -4.8]
*
* See also:
*
* ceil, fix, round
*
* @param {number | BigNumber | Fraction | Complex | Array | Matrix} x Number to be rounded
* @param {number | BigNumber | Array} [n=0] Number of decimals
* @return {number | BigNumber | Fraction | Complex | Array | Matrix} Rounded value
*/
return typed('floor', {
Expand All @@ -43,10 +58,25 @@ export const createFloor = /* #__PURE__ */ factory(name, dependencies, ({ typed,
}
},

'number, number': function (x, n) {
if (nearlyEqual(x, round(x, n), config.epsilon)) {
return round(x, n)
} else {
let [number, exponent] = `${x}e`.split('e')
const result = Math.floor(Number(`${number}e${Number(exponent) + n}`));
[number, exponent] = `${result}e`.split('e')
return Number(`${number}e${Number(exponent) - n}`)
}
},

Complex: function (x) {
return x.floor()
},

'Complex, number': function (x, n) {
return x.floor(n)
},

BigNumber: function (x) {
if (bigNearlyEqual(x, round(x), config.epsilon)) {
return round(x)
Expand All @@ -55,13 +85,43 @@ export const createFloor = /* #__PURE__ */ factory(name, dependencies, ({ typed,
}
},

'BigNumber, BigNumber': function (x, n) {
if (bigNearlyEqual(x, round(x, n), config.epsilon)) {
return round(x, n)
} else {
return x.toDecimalPlaces(n.toNumber(), Decimal.ROUND_FLOOR)
}
},

Fraction: function (x) {
return x.floor()
},

'Fraction, number': function (x, n) {
return x.floor(n)
},

'Array | Matrix': function (x) {
// deep map collection, skip zeros since floor(0) = 0
return deepMap(x, this, true)
},

'Array | Matrix, number': function (x, n) {
// deep map collection, skip zeros since ceil(0) = 0
return deepMap(x, i => this(i, n), true)
},

'SparseMatrix, number | BigNumber': function (x, y) {
return algorithm11(x, y, this, false)
},

'DenseMatrix, number | BigNumber': function (x, y) {
return algorithm14(x, y, this, false)
},

'number | Complex | BigNumber, Array': function (x, y) {
// use matrix implementation
return algorithm14(matrix(y), x, this, true).valueOf()
}
})
})
8 changes: 6 additions & 2 deletions src/function/arithmetic/round.js
Expand Up @@ -34,10 +34,14 @@ export const createRound = /* #__PURE__ */ factory(name, dependencies, ({ typed,
*
* Examples:
*
* math.round(3.2) // returns number 3
* math.round(3.8) // returns number 4
* math.round(3.22) // returns number 3
* math.round(3.82) // returns number 4
* math.round(-4.2) // returns number -4
* math.round(-4.7) // returns number -5
* math.round(3.22, 1) // returns number 3.2
* math.round(3.88, 1) // returns number 3.8
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think math.round(3.88, 1) returns 3.9 instead of 3.8, right?

* math.round(-4.21, 1) // returns number -4.2
* math.round(-4.71, 1) // returns number -4.7
* math.round(math.pi, 3) // returns number 3.142
* math.round(123.45678, 2) // returns number 123.46
*
Expand Down