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

feat: adds unit support to ceil, floor, and fix functions #3269

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions src/expression/embeddedDocs/function/arithmetic/ceil.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@ export const ceilDocs = {
name: 'ceil',
category: 'Arithmetic',
syntax: [
'ceil(x)'
'ceil(x)',
'ceil(x, n)',
'ceil(unit, valuelessUnit)',
'ceil(unit, n, valuelessUnit)'
],
description:
'Round a value towards plus infinity. If x is complex, both real and imaginary part are rounded towards plus infinity.',
examples: [
'ceil(3.2)',
'ceil(3.8)',
'ceil(-4.2)'
'ceil(-4.2)',
'ceil(3.241cm, cm)',
'ceil(3.241cm, 2, cm)'
],
seealso: ['floor', 'fix', 'round']
}
9 changes: 7 additions & 2 deletions src/expression/embeddedDocs/function/arithmetic/fix.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,20 @@ export const fixDocs = {
name: 'fix',
category: 'Arithmetic',
syntax: [
'fix(x)'
'fix(x)',
'fix(x, n)',
'fix(unit, valuelessUnit)',
'fix(unit, n, valuelessUnit)'
],
description:
'Round a value towards zero. If x is complex, both real and imaginary part are rounded towards zero.',
examples: [
'fix(3.2)',
'fix(3.8)',
'fix(-4.2)',
'fix(-4.8)'
'fix(-4.8)',
'fix(3.241cm, cm)',
'fix(3.241cm, 2, cm)'
],
seealso: ['ceil', 'floor', 'round']
}
9 changes: 7 additions & 2 deletions src/expression/embeddedDocs/function/arithmetic/floor.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@ export const floorDocs = {
name: 'floor',
category: 'Arithmetic',
syntax: [
'floor(x)'
'floor(x)',
'floor(x, n)',
'floor(unit, valuelessUnit)',
'floor(unit, n, valuelessUnit)'
],
description:
'Round a value towards minus infinity.If x is complex, both real and imaginary part are rounded towards minus infinity.',
examples: [
'floor(3.2)',
'floor(3.8)',
'floor(-4.2)'
'floor(-4.2)',
'floor(3.241cm, cm)',
'floor(3.241cm, 2, cm)'
],
seealso: ['ceil', 'fix', 'round']
}
24 changes: 24 additions & 0 deletions src/function/arithmetic/ceil.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ export const createCeil = /* #__PURE__ */ factory(name, dependencies, ({ typed,
* math.ceil(c) // returns Complex 4 - 2i
* math.ceil(c, 1) // returns Complex 3.3 - 2.7i
*
* const unit = math.unit('3.241 cm')
* const cm = math.unit('cm')
* const mm = math.unit('mm')
* math.ceil(unit, 1, cm) // returns Unit 3.3 cm
* math.ceil(unit, 1, mm) // returns Unit 32.5 mm
*
* 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]
*
Expand Down Expand Up @@ -122,6 +128,24 @@ export const createCeil = /* #__PURE__ */ factory(name, dependencies, ({ typed,
return x.ceil(n.toNumber())
},

'Unit, number, Unit': typed.referToSelf(self => function (x, n, unit) {
const valueless = x.toNumeric(unit)
return unit.multiply(self(valueless, n))
}),

'Unit, BigNumber, Unit': typed.referToSelf(self => (x, n, unit) => self(x, n.toNumber(), unit)),

'Unit, Unit': typed.referToSelf(self => (x, unit) => self(x, 0, unit)),

'Array | Matrix, number, Unit': typed.referToSelf(self => (x, n, unit) => {
// deep map collection, skip zeros since ceil(0) = 0
return deepMap(x, (value) => self(value, n, unit), true)
}),

'Array | Matrix, BigNumber, Unit': typed.referToSelf(self => (x, n, unit) => self(x, n.toNumber(), unit)),

'Array | Matrix, Unit': typed.referToSelf(self => (x, unit) => self(x, 0, unit)),

'Array | Matrix': typed.referToSelf(self => (x) => {
// deep map collection, skip zeros since ceil(0) = 0
return deepMap(x, self, true)
Expand Down
24 changes: 24 additions & 0 deletions src/function/arithmetic/fix.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ export const createFix = /* #__PURE__ */ factory(name, dependencies, ({ typed, C
* math.fix(c) // returns Complex 3 - 2i
* math.fix(c, 1) // returns Complex 3.2 -2.7i
*
* const unit = math.unit('3.241 cm')
* const cm = math.unit('cm')
* const mm = math.unit('mm')
* math.fix(unit, 1, cm) // returns Unit 3.2 cm
* math.fix(unit, 1, mm) // returns Unit 32.4 mm
*
* 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]
*
Expand Down Expand Up @@ -103,6 +109,24 @@ export const createFix = /* #__PURE__ */ factory(name, dependencies, ({ typed, C
return x.s < 0 ? ceil(x, n) : floor(x, n)
},

'Unit, number, Unit': typed.referToSelf(self => function (x, n, unit) {
const valueless = x.toNumeric(unit)
return unit.multiply(self(valueless, n))
}),

'Unit, BigNumber, Unit': typed.referToSelf(self => (x, n, unit) => self(x, n.toNumber(), unit)),

'Unit, Unit': typed.referToSelf(self => (x, unit) => self(x, 0, unit)),

'Array | Matrix, number, Unit': typed.referToSelf(self => (x, n, unit) => {
// deep map collection, skip zeros since round(0) = 0
return deepMap(x, (value) => self(value, n, unit), true)
}),

'Array | Matrix, BigNumber, Unit': typed.referToSelf(self => (x, n, unit) => self(x, n.toNumber(), unit)),

'Array | Matrix, Unit': typed.referToSelf(self => (x, unit) => self(x, 0, unit)),

'Array | Matrix': typed.referToSelf(self => (x) => {
// deep map collection, skip zeros since fix(0) = 0
return deepMap(x, self, true)
Expand Down
24 changes: 24 additions & 0 deletions src/function/arithmetic/floor.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ export const createFloor = /* #__PURE__ */ factory(name, dependencies, ({ typed,
* math.floor(c) // returns Complex 3 - 3i
* math.floor(c, 1) // returns Complex 3.2 -2.8i
*
* const unit = math.unit('3.241 cm')
* const cm = math.unit('cm')
* const mm = math.unit('mm')
* math.floor(unit, 1, cm) // returns Unit 3.2 cm
* math.floor(unit, 1, mm) // returns Unit 32.4 mm
*
* 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]
*
Expand Down Expand Up @@ -125,6 +131,24 @@ export const createFloor = /* #__PURE__ */ factory(name, dependencies, ({ typed,
return x.floor(n.toNumber())
},

'Unit, number, Unit': typed.referToSelf(self => function (x, n, unit) {
const valueless = x.toNumeric(unit)
return unit.multiply(self(valueless, n))
}),

'Unit, BigNumber, Unit': typed.referToSelf(self => (x, n, unit) => self(x, n.toNumber(), unit)),

'Unit, Unit': typed.referToSelf(self => (x, unit) => self(x, 0, unit)),

'Array | Matrix, number, Unit': typed.referToSelf(self => (x, n, unit) => {
// deep map collection, skip zeros since floor(0) = 0
return deepMap(x, (value) => self(value, n, unit), true)
}),

'Array | Matrix, BigNumber, Unit': typed.referToSelf(self => (x, n, unit) => self(x, n.toNumber(), unit)),

'Array | Matrix, Unit': typed.referToSelf(self => (x, unit) => self(x, 0, unit)),

'Array | Matrix': typed.referToSelf(self => (x) => {
// deep map collection, skip zeros since floor(0) = 0
return deepMap(x, self, true)
Expand Down
9 changes: 9 additions & 0 deletions test/typescript-tests/testTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,9 @@ Chaining examples
expectTypeOf(math.chain([1]).ceil()).toMatchTypeOf<
MathJsChain<MathCollection>
>()
expectTypeOf(
math.chain(math.unit('5.2cm')).ceil(math.unit('cm'))
).toMatchTypeOf<MathJsChain<Unit>>()

// fix
expectTypeOf(math.chain(1).fix()).toMatchTypeOf<
Expand All @@ -657,6 +660,9 @@ Chaining examples
expectTypeOf(math.chain([1]).fix()).toMatchTypeOf<
MathJsChain<MathCollection>
>()
expectTypeOf(
math.chain(math.unit('5.2cm')).fix(math.unit('cm'))
).toMatchTypeOf<MathJsChain<Unit>>()

// floor
expectTypeOf(math.chain(1).floor()).toMatchTypeOf<
Expand All @@ -665,6 +671,9 @@ Chaining examples
expectTypeOf(math.chain([1]).floor()).toMatchTypeOf<
MathJsChain<MathCollection>
>()
expectTypeOf(
math.chain(math.unit('5.2cm')).floor(math.unit('cm'))
).toMatchTypeOf<MathJsChain<Unit>>()

// round
expectTypeOf(math.chain(1).round()).toMatchTypeOf<
Expand Down
28 changes: 28 additions & 0 deletions test/unit-tests/function/arithmetic/ceil.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,34 @@ describe('ceil', function () {
assert.deepStrictEqual(ceil(bignumber(-799999.9999999999)), bignumber(-800000))
})

it('should ceil units', function () {
assert.deepStrictEqual(ceil(unit('5.01 inch'), unit('inch')), unit('6 inch'))
assert.deepStrictEqual(ceil(unit('3.12345 cm'), 3, unit('cm')), unit('3.124 cm'))
assert.deepStrictEqual(ceil(unit('3.12345 cm'), unit('cm')), unit('4 cm'))
assert.deepStrictEqual(ceil(unit('2 inch'), unit('cm')), unit('6 cm'))
assert.deepStrictEqual(ceil(unit('2 inch'), 1, unit('cm')), unit('5.1 cm'))

// bignumber values
assert.deepStrictEqual(ceil(unit('3.12345 cm'), bignumber(2), unit('cm')), unit('3.13 cm'))
assert.deepStrictEqual(ceil(unit(bignumber('2'), 'inch'), unit('cm')), unit(bignumber('6'), 'cm'))
assert.deepStrictEqual(ceil(unit(bignumber('2'), 'inch'), bignumber(1), unit('cm')), unit(bignumber('5.1'), 'cm'))

// first argument is a collection
assert.deepStrictEqual(ceil([unit('2 inch'), unit('3 inch')], unit('cm')), [unit('6 cm'), unit('8 cm')])
assert.deepStrictEqual(ceil(matrix([unit('2 inch'), unit('3 inch')]), unit('cm')), matrix([unit('6 cm'), unit('8 cm')]))
})

it('should throw an error if used with a unit without valueless unit', function () {
assert.throws(function () { ceil(unit('5cm')) }, TypeError, 'Function ceil(unit) not supported')
assert.throws(function () { ceil(unit('5cm'), 2) }, TypeError, 'Function ceil(unit) not supported')
assert.throws(function () { ceil(unit('5cm'), bignumber(2)) }, TypeError, 'Function ceil(unit) not supported')
})

it('should throw an error if used with a unit with a second unit that is not valueless', function () {
assert.throws(function () { ceil(unit('2 inch'), 1, unit('10 cm')) }, Error)
assert.throws(function () { ceil(unit('2 inch'), unit('10 cm')) }, Error)
})

it('should throw an error for units', function () {
assert.throws(function () { ceil(unit('5cm')) }, TypeError, 'Function ceil(unit) not supported')
})
Expand Down
33 changes: 33 additions & 0 deletions test/unit-tests/function/arithmetic/fix.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,39 @@ describe('fix', function () {
assert.strictEqual(fix(-799999.9999999999, 3), -800000)
})

it('should fix units', function () {
assert.deepStrictEqual(fix(unit('5.99 inch'), unit('inch')), unit('5 inch'))
assert.deepStrictEqual(fix(unit('3.12345 cm'), 3, unit('cm')), unit('3.123 cm'))
assert.deepStrictEqual(fix(unit('3.12345 cm'), unit('cm')), unit('3 cm'))
assert.deepStrictEqual(fix(unit('2 inch'), unit('cm')), unit('5 cm'))
assert.deepStrictEqual(fix(unit('2 inch'), 1, unit('cm')), unit('5 cm'))
assert.deepStrictEqual(fix(unit('-1.9 inch'), unit('cm')), unit('-4 cm'))

// bignumber values
assert.deepStrictEqual(fix(unit('3.12345 cm'), bignumber(2), unit('cm')), unit('3.12 cm'))
assert.deepStrictEqual(fix(unit(bignumber('2'), 'inch'), unit('cm')), unit(bignumber('5'), 'cm'))
assert.deepStrictEqual(fix(unit(bignumber('2'), 'inch'), bignumber(1), unit('cm')), unit(bignumber('5.0'), 'cm'))

// first argument is a collection
assert.deepStrictEqual(fix([unit('2 inch'), unit('3 inch')], unit('cm')), [unit('5 cm'), unit('7 cm')])
assert.deepStrictEqual(fix(matrix([unit('2 inch'), unit('3 inch')]), unit('cm')), matrix([unit('5 cm'), unit('7 cm')]))
})

it('should throw an error if used with a unit without valueless unit', function () {
assert.throws(function () { fix(unit('5cm')) }, TypeError, 'Function fix(unit) not supported')
assert.throws(function () { fix(unit('5cm'), 2) }, TypeError, 'Function fix(unit) not supported')
assert.throws(function () { fix(unit('5cm'), bignumber(2)) }, TypeError, 'Function fix(unit) not supported')
})

it('should throw an error if used with a unit with a second unit that is not valueless', function () {
assert.throws(function () { fix(unit('2 inch'), 1, unit('10 cm')) }, Error)
assert.throws(function () { fix(unit('2 inch'), unit('10 cm')) }, Error)
})

it('should throw an error with a unit', function () {
assert.throws(function () { fix(unit('5cm')) }, TypeError, 'Function fix(unit) not supported')
})

it('should throw an error on unit as parameter', function () {
// unit
assert.throws(function () { fix(unit('5cm')) }, TypeError, 'Function fix(unit) not supported')
Expand Down
36 changes: 32 additions & 4 deletions test/unit-tests/function/arithmetic/floor.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const i = math.i
const sparse = math.sparse

describe('floor', function () {
it('should round booleans correctly', function () {
it('should floor booleans correctly', function () {
assert.strictEqual(floor(true), 1)
assert.strictEqual(floor(false), 0)
})
Expand Down Expand Up @@ -148,6 +148,34 @@ describe('floor', function () {
assert.deepStrictEqual(floor(bignumber(-30000.000000000004)), bignumber(-30000))
})

it('should floor units', function () {
assert.deepStrictEqual(floor(unit('5.99 inch'), unit('inch')), unit('5 inch'))
assert.deepStrictEqual(floor(unit('3.12345 cm'), 3, unit('cm')), unit('3.123 cm'))
assert.deepStrictEqual(floor(unit('3.12345 cm'), unit('cm')), unit('3 cm'))
assert.deepStrictEqual(floor(unit('2 inch'), unit('cm')), unit('5 cm'))
assert.deepStrictEqual(floor(unit('2 inch'), 1, unit('cm')), unit('5 cm'))

// bignumber values
assert.deepStrictEqual(floor(unit('3.12345 cm'), bignumber(2), unit('cm')), unit('3.12 cm'))
assert.deepStrictEqual(floor(unit(bignumber('2'), 'inch'), unit('cm')), unit(bignumber('5'), 'cm'))
assert.deepStrictEqual(floor(unit(bignumber('2'), 'inch'), bignumber(1), unit('cm')), unit(bignumber('5.0'), 'cm'))

// first argument is a collection
assert.deepStrictEqual(floor([unit('2 inch'), unit('3 inch')], unit('cm')), [unit('5 cm'), unit('7 cm')])
assert.deepStrictEqual(floor(matrix([unit('2 inch'), unit('3 inch')]), unit('cm')), matrix([unit('5 cm'), unit('7 cm')]))
})

it('should throw an error if used with a unit without valueless unit', function () {
assert.throws(function () { floor(unit('5cm')) }, TypeError, 'Function floor(unit) not supported')
assert.throws(function () { floor(unit('5cm'), 2) }, TypeError, 'Function floor(unit) not supported')
assert.throws(function () { floor(unit('5cm'), bignumber(2)) }, TypeError, 'Function floor(unit) not supported')
})

it('should throw an error if used with a unit with a second unit that is not valueless', function () {
assert.throws(function () { floor(unit('2 inch'), 1, unit('10 cm')) }, Error)
assert.throws(function () { floor(unit('2 inch'), unit('10 cm')) }, Error)
})

it('should throw an error with a unit', function () {
assert.throws(function () { floor(unit('5cm')) }, TypeError, 'Function floor(unit) not supported')
})
Expand Down Expand Up @@ -226,9 +254,9 @@ describe('floor', function () {
})

it('should throw an error if requested number of decimals is incorrect', function () {
assert.throws(function () { floor(2.5, 1.5) }, Error, 'Number of decimals in function round must be an integer')
assert.throws(function () { floor(2.5, -2) }, Error, ' Number of decimals in function round must be in the range of 0-15')
assert.throws(function () { floor(2.5, Infinity) }, Error, ' Number of decimals in function round must be in the range of 0-15')
assert.throws(function () { floor(2.5, 1.5) }, Error, 'Number of decimals in function floor must be an integer')
assert.throws(function () { floor(2.5, -2) }, Error, ' Number of decimals in function floor must be in the range of 0-15')
assert.throws(function () { floor(2.5, Infinity) }, Error, ' Number of decimals in function floor must be in the range of 0-15')
})

it('should LaTeX floor', function () {
Expand Down
Loading