diff --git a/src/expression/embeddedDocs/function/arithmetic/ceil.js b/src/expression/embeddedDocs/function/arithmetic/ceil.js index ae6afb8f52..ef29722167 100644 --- a/src/expression/embeddedDocs/function/arithmetic/ceil.js +++ b/src/expression/embeddedDocs/function/arithmetic/ceil.js @@ -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'] } diff --git a/src/expression/embeddedDocs/function/arithmetic/fix.js b/src/expression/embeddedDocs/function/arithmetic/fix.js index eb6302104e..e324fa9c6e 100644 --- a/src/expression/embeddedDocs/function/arithmetic/fix.js +++ b/src/expression/embeddedDocs/function/arithmetic/fix.js @@ -2,7 +2,10 @@ 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.', @@ -10,7 +13,9 @@ export const fixDocs = { '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'] } diff --git a/src/expression/embeddedDocs/function/arithmetic/floor.js b/src/expression/embeddedDocs/function/arithmetic/floor.js index af78e187e7..ce6c55f22e 100644 --- a/src/expression/embeddedDocs/function/arithmetic/floor.js +++ b/src/expression/embeddedDocs/function/arithmetic/floor.js @@ -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'] } diff --git a/src/function/arithmetic/ceil.js b/src/function/arithmetic/ceil.js index 4d4c7a0ea1..48828a94ed 100644 --- a/src/function/arithmetic/ceil.js +++ b/src/function/arithmetic/ceil.js @@ -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] * @@ -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) diff --git a/src/function/arithmetic/fix.js b/src/function/arithmetic/fix.js index f0e8a39aaa..b1c0f60d9d 100644 --- a/src/function/arithmetic/fix.js +++ b/src/function/arithmetic/fix.js @@ -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] * @@ -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) diff --git a/src/function/arithmetic/floor.js b/src/function/arithmetic/floor.js index 4129d5561b..08fa7715a5 100644 --- a/src/function/arithmetic/floor.js +++ b/src/function/arithmetic/floor.js @@ -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] * @@ -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) diff --git a/test/typescript-tests/testTypes.ts b/test/typescript-tests/testTypes.ts index 735ac1148b..95b1730149 100644 --- a/test/typescript-tests/testTypes.ts +++ b/test/typescript-tests/testTypes.ts @@ -649,6 +649,9 @@ Chaining examples expectTypeOf(math.chain([1]).ceil()).toMatchTypeOf< MathJsChain >() + expectTypeOf( + math.chain(math.unit('5.2cm')).ceil(math.unit('cm')) + ).toMatchTypeOf>() // fix expectTypeOf(math.chain(1).fix()).toMatchTypeOf< @@ -657,6 +660,9 @@ Chaining examples expectTypeOf(math.chain([1]).fix()).toMatchTypeOf< MathJsChain >() + expectTypeOf( + math.chain(math.unit('5.2cm')).fix(math.unit('cm')) + ).toMatchTypeOf>() // floor expectTypeOf(math.chain(1).floor()).toMatchTypeOf< @@ -665,6 +671,9 @@ Chaining examples expectTypeOf(math.chain([1]).floor()).toMatchTypeOf< MathJsChain >() + expectTypeOf( + math.chain(math.unit('5.2cm')).floor(math.unit('cm')) + ).toMatchTypeOf>() // round expectTypeOf(math.chain(1).round()).toMatchTypeOf< diff --git a/test/unit-tests/function/arithmetic/ceil.test.js b/test/unit-tests/function/arithmetic/ceil.test.js index e4a40508a2..b9315d29cd 100644 --- a/test/unit-tests/function/arithmetic/ceil.test.js +++ b/test/unit-tests/function/arithmetic/ceil.test.js @@ -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') }) diff --git a/test/unit-tests/function/arithmetic/fix.test.js b/test/unit-tests/function/arithmetic/fix.test.js index 821123cc6b..74cf373a34 100644 --- a/test/unit-tests/function/arithmetic/fix.test.js +++ b/test/unit-tests/function/arithmetic/fix.test.js @@ -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') diff --git a/test/unit-tests/function/arithmetic/floor.test.js b/test/unit-tests/function/arithmetic/floor.test.js index 36ec8763fa..a8acc77f8b 100644 --- a/test/unit-tests/function/arithmetic/floor.test.js +++ b/test/unit-tests/function/arithmetic/floor.test.js @@ -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) }) @@ -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') }) @@ -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 () { diff --git a/types/index.d.ts b/types/index.d.ts index 16f4d16192..feb9d5cbe0 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -4995,6 +4995,25 @@ export interface MathJsChain { this: MathJsChain, n?: number | BigNumber | MathCollection ): MathJsChain + ceil( + this: MathJsChain, + n: U + ): MathJsChain + ceil(this: MathJsChain, unit: Unit): MathJsChain + ceil( + this: MathJsChain, + unit: Unit + ): MathJsChain + ceil( + this: MathJsChain, + n: number | BigNumber, + unit: Unit + ): MathJsChain + ceil( + this: MathJsChain, + n: number | BigNumber, + unit: Unit + ): MathJsChain /** * Round a value towards zero. For matrices, the function is evaluated @@ -5005,6 +5024,25 @@ export interface MathJsChain { this: MathJsChain, n?: number | BigNumber | MathCollection ): MathJsChain + fix( + this: MathJsChain, + n: U + ): MathJsChain + fix(this: MathJsChain, unit: Unit): MathJsChain + fix( + this: MathJsChain, + unit: Unit + ): MathJsChain + fix( + this: MathJsChain, + n: number | BigNumber, + unit: Unit + ): MathJsChain + fix( + this: MathJsChain, + n: number | BigNumber, + unit: Unit + ): MathJsChain /** * Round a value towards minus infinity. For matrices, the function is @@ -5015,6 +5053,25 @@ export interface MathJsChain { this: MathJsChain, n?: number | BigNumber | MathCollection ): MathJsChain + floor( + this: MathJsChain, + n: U + ): MathJsChain + floor(this: MathJsChain, unit: Unit): MathJsChain + floor( + this: MathJsChain, + unit: Unit + ): MathJsChain + floor( + this: MathJsChain, + n: number | BigNumber, + unit: Unit + ): MathJsChain + floor( + this: MathJsChain, + n: number | BigNumber, + unit: Unit + ): MathJsChain /** * Round a value towards the nearest integer. For matrices, the function