From 88bde30526142e0b49e793ee2f7e6779617573be Mon Sep 17 00:00:00 2001 From: Dushusir <1414556676@qq.com> Date: Thu, 4 Jul 2024 18:58:52 +0800 Subject: [PATCH] feat(formula): add asin function (#2620) * feat(formula): add asin function * feat(formula): add asinh function * feat(formula): add tan,tanh functions * test(formula): acot test * fix(formula): function atan2 calculation * fix(sheet): strip every number cell * fix(sheet): remove unused module * fix(sheet): skip numfmt pattern in number cell interceptor --- .../engine/value-object/primitive-object.ts | 5 + .../math/abs/__tests__/index.spec.ts | 50 +++++-- .../src/functions/math/abs/index.ts | 4 +- .../math/acos/__tests__/index.spec.ts | 49 +++++-- .../src/functions/math/acos/index.ts | 4 +- .../math/acosh/__tests__/index.spec.ts | 47 ++++-- .../src/functions/math/acosh/index.ts | 4 +- .../math/acot/__tests__/index.spec.ts | 49 +++++-- .../math/asin/__tests__/index.spec.ts | 87 +++++++++++ .../src/functions/math/asin/index.ts | 36 +++++ .../math/asinh/__tests__/index.spec.ts | 87 +++++++++++ .../src/functions/math/asinh/index.ts | 36 +++++ .../math/atan/__tests__/index.spec.ts | 87 +++++++++++ .../src/functions/math/atan/index.ts | 36 +++++ .../math/atan2/__tests__/index.spec.ts | 136 ++++++++++++++++++ .../src/functions/math/atan2/index.ts | 45 ++++++ .../math/atanh/__tests__/index.spec.ts | 87 +++++++++++ .../src/functions/math/atanh/index.ts | 36 +++++ .../math/cos/__tests__/index.spec.ts | 87 +++++++++++ .../src/functions/math/cos/index.ts | 36 +++++ .../src/functions/math/function-map.ts | 20 ++- .../math/tan/__tests__/index.spec.ts | 87 +++++++++++ .../src/functions/math/tan/index.ts | 36 +++++ .../math/tanh/__tests__/index.spec.ts | 87 +++++++++++ .../src/functions/math/tanh/index.ts | 36 +++++ .../controllers/formula-render.controller.ts | 11 +- .../src/locale/function-list/math/en-US.ts | 41 +++--- .../src/locale/function-list/math/ja-JP.ts | 41 +++--- .../src/locale/function-list/math/zh-CN.ts | 41 +++--- .../src/services/function-list/math.ts | 103 ++++--------- .../src/controllers/number-cell.controller.ts | 60 ++++++++ packages/sheets/src/sheets-plugin.ts | 2 + 32 files changed, 1361 insertions(+), 212 deletions(-) create mode 100644 packages/engine-formula/src/functions/math/asin/__tests__/index.spec.ts create mode 100644 packages/engine-formula/src/functions/math/asin/index.ts create mode 100644 packages/engine-formula/src/functions/math/asinh/__tests__/index.spec.ts create mode 100644 packages/engine-formula/src/functions/math/asinh/index.ts create mode 100644 packages/engine-formula/src/functions/math/atan/__tests__/index.spec.ts create mode 100644 packages/engine-formula/src/functions/math/atan/index.ts create mode 100644 packages/engine-formula/src/functions/math/atan2/__tests__/index.spec.ts create mode 100644 packages/engine-formula/src/functions/math/atan2/index.ts create mode 100644 packages/engine-formula/src/functions/math/atanh/__tests__/index.spec.ts create mode 100644 packages/engine-formula/src/functions/math/atanh/index.ts create mode 100644 packages/engine-formula/src/functions/math/cos/__tests__/index.spec.ts create mode 100644 packages/engine-formula/src/functions/math/cos/index.ts create mode 100644 packages/engine-formula/src/functions/math/tan/__tests__/index.spec.ts create mode 100644 packages/engine-formula/src/functions/math/tan/index.ts create mode 100644 packages/engine-formula/src/functions/math/tanh/__tests__/index.spec.ts create mode 100644 packages/engine-formula/src/functions/math/tanh/index.ts create mode 100644 packages/sheets/src/controllers/number-cell.controller.ts diff --git a/packages/engine-formula/src/engine/value-object/primitive-object.ts b/packages/engine-formula/src/engine/value-object/primitive-object.ts index 5251e659b0..1cf19429c3 100644 --- a/packages/engine-formula/src/engine/value-object/primitive-object.ts +++ b/packages/engine-formula/src/engine/value-object/primitive-object.ts @@ -1022,6 +1022,11 @@ export class NumberValueObject extends BaseValueObject { return ErrorValueObject.create(ErrorType.NUM); } + // ATAN2(y, x) calculates the angle of the point (x, y) relative to the positive x-axis. When x and y are both 0, the point is actually the origin itself, and there is no concept of the angle "starting from" the origin to the origin. + if (currentValue === 0 && value === 0) { + return ErrorValueObject.create(ErrorType.DIV_BY_ZERO); + } + const result = Math.atan2(currentValue, value); if (!Number.isFinite(result)) { diff --git a/packages/engine-formula/src/functions/math/abs/__tests__/index.spec.ts b/packages/engine-formula/src/functions/math/abs/__tests__/index.spec.ts index 5c5226f6fd..b99fbc2cdb 100644 --- a/packages/engine-formula/src/functions/math/abs/__tests__/index.spec.ts +++ b/packages/engine-formula/src/functions/math/abs/__tests__/index.spec.ts @@ -18,42 +18,64 @@ import { describe, expect, it } from 'vitest'; import { FUNCTION_NAMES_MATH } from '../../function-names'; import { Abs } from '../index'; -import { NumberValueObject, StringValueObject } from '../../../../engine/value-object/primitive-object'; +import { BooleanValueObject, NullValueObject, NumberValueObject, StringValueObject } from '../../../../engine/value-object/primitive-object'; import { ArrayValueObject, transformToValue, transformToValueObject } from '../../../../engine/value-object/array-value-object'; +import { ErrorType } from '../../../../basics/error-type'; +import { ErrorValueObject } from '../../../../engine/value-object/base-value-object'; describe('Test abs function', () => { const testFunction = new Abs(FUNCTION_NAMES_MATH.ABS); describe('Abs', () => { - it('Value is normal', () => { - const value = NumberValueObject.create(1); + it('Value is normal number', () => { + const value = NumberValueObject.create(-1); const result = testFunction.calculate(value); expect(result.getValue()).toBe(1); }); - it('Value is string number', () => { - const value = new StringValueObject('1'); + + it('Value is number string', () => { + const value = StringValueObject.create('-0.5'); const result = testFunction.calculate(value); - expect(result.getValue()).toBe(1); + expect(result.getValue()).toBe(0.5); + }); + + it('Value is normal string', () => { + const value = StringValueObject.create('test'); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(ErrorType.VALUE); + }); + + it('Value is boolean', () => { + const value = BooleanValueObject.create(false); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(0); + }); + it('Value is blank cell', () => { + const value = NullValueObject.create(); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(0); + }); + it('Value is error', () => { + const value = ErrorValueObject.create(ErrorType.NAME); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(ErrorType.NAME); }); it('Value is array', () => { const valueArray = ArrayValueObject.create({ calculateValueList: transformToValueObject([ - [1, 2], - [2, 3], - [3, 4], + [1, ' ', 1.23, true, false, null], + [0, '100', '2.34', 'test', -3, ErrorType.NAME], ]), - rowCount: 3, - columnCount: 2, + rowCount: 2, + columnCount: 6, unitId: '', sheetId: '', row: 0, column: 0, }); const result = testFunction.calculate(valueArray); - expect(transformToValue(result.getArrayValue())).toStrictEqual([[1, 2], - [2, 3], - [3, 4]]); + expect(transformToValue(result.getArrayValue())).toStrictEqual([[1, ErrorType.VALUE, 1.23, 1, 0, 0], [0, 100, 2.34, ErrorType.VALUE, 3, ErrorType.NAME]]); }); }); }); diff --git a/packages/engine-formula/src/functions/math/abs/index.ts b/packages/engine-formula/src/functions/math/abs/index.ts index 9740097dfe..1b1ec90407 100644 --- a/packages/engine-formula/src/functions/math/abs/index.ts +++ b/packages/engine-formula/src/functions/math/abs/index.ts @@ -14,9 +14,7 @@ * limitations under the License. */ -import { ErrorType } from '../../../basics/error-type'; import type { BaseValueObject } from '../../../engine/value-object/base-value-object'; -import { ErrorValueObject } from '../../../engine/value-object/base-value-object'; import { BaseFunction } from '../../base-function'; export class Abs extends BaseFunction { @@ -30,7 +28,7 @@ export class Abs extends BaseFunction { } if (variant.isError()) { - return ErrorValueObject.create(ErrorType.VALUE); + return variant; } return variant.abs(); diff --git a/packages/engine-formula/src/functions/math/acos/__tests__/index.spec.ts b/packages/engine-formula/src/functions/math/acos/__tests__/index.spec.ts index e76d485e27..f0504e6e6c 100644 --- a/packages/engine-formula/src/functions/math/acos/__tests__/index.spec.ts +++ b/packages/engine-formula/src/functions/math/acos/__tests__/index.spec.ts @@ -18,41 +18,70 @@ import { describe, expect, it } from 'vitest'; import { FUNCTION_NAMES_MATH } from '../../function-names'; import { Acos } from '../index'; -import { NumberValueObject, StringValueObject } from '../../../../engine/value-object/primitive-object'; +import { BooleanValueObject, NullValueObject, NumberValueObject, StringValueObject } from '../../../../engine/value-object/primitive-object'; import { ArrayValueObject, transformToValue, transformToValueObject } from '../../../../engine/value-object/array-value-object'; +import { ErrorType } from '../../../../basics/error-type'; +import { ErrorValueObject } from '../../../../engine/value-object/base-value-object'; describe('Test acos function', () => { const testFunction = new Acos(FUNCTION_NAMES_MATH.ACOS); describe('Acos', () => { - it('Value is normal', () => { + it('Value is normal number', () => { const value = NumberValueObject.create(1); const result = testFunction.calculate(value); expect(result.getValue()).toBe(0); }); - it('Value is string number', () => { - const value = new StringValueObject('1'); + it('Value is number valid', () => { + const value = NumberValueObject.create(-2); const result = testFunction.calculate(value); - expect(result.getValue()).toBe(0); + expect(result.getValue()).toBe(ErrorType.NUM); + }); + + it('Value is number string', () => { + const value = StringValueObject.create('0.5'); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(1.0471975511965979); + }); + + it('Value is normal string', () => { + const value = StringValueObject.create('test'); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(ErrorType.VALUE); + }); + + it('Value is boolean', () => { + const value = BooleanValueObject.create(false); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(1.5707963267948966); + }); + it('Value is blank cell', () => { + const value = NullValueObject.create(); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(1.5707963267948966); + }); + it('Value is error', () => { + const value = ErrorValueObject.create(ErrorType.NAME); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(ErrorType.NAME); }); it('Value is array', () => { const valueArray = ArrayValueObject.create({ calculateValueList: transformToValueObject([ - [1, ' ', 1.23, true, false], - [0, '100', '2.34', 'test', -3], + [1, ' ', 1.23, true, false, null], + [0, '100', '2.34', 'test', -3, ErrorType.NAME], ]), rowCount: 2, - columnCount: 5, + columnCount: 6, unitId: '', sheetId: '', row: 0, column: 0, }); const result = testFunction.calculate(valueArray); - expect(transformToValue(result.getArrayValue())).toStrictEqual([[0, '#VALUE!', '#NUM!', 0, 1.5707963267948966], - [1.5707963267948966, '#NUM!', '#NUM!', '#VALUE!', '#NUM!']]); + expect(transformToValue(result.getArrayValue())).toStrictEqual([[0, ErrorType.VALUE, ErrorType.NUM, 0, 1.5707963267948966, 1.5707963267948966], [1.5707963267948966, ErrorType.NUM, ErrorType.NUM, ErrorType.VALUE, ErrorType.NUM, ErrorType.NAME]]); }); }); }); diff --git a/packages/engine-formula/src/functions/math/acos/index.ts b/packages/engine-formula/src/functions/math/acos/index.ts index 2c3ebbcbb7..eebee7b36b 100644 --- a/packages/engine-formula/src/functions/math/acos/index.ts +++ b/packages/engine-formula/src/functions/math/acos/index.ts @@ -14,9 +14,7 @@ * limitations under the License. */ -import { ErrorType } from '../../../basics/error-type'; import type { BaseValueObject } from '../../../engine/value-object/base-value-object'; -import { ErrorValueObject } from '../../../engine/value-object/base-value-object'; import { BaseFunction } from '../../base-function'; export class Acos extends BaseFunction { @@ -30,7 +28,7 @@ export class Acos extends BaseFunction { } if (variant.isError()) { - return new ErrorValueObject(ErrorType.VALUE); + return variant; } return variant.acos(); diff --git a/packages/engine-formula/src/functions/math/acosh/__tests__/index.spec.ts b/packages/engine-formula/src/functions/math/acosh/__tests__/index.spec.ts index 7506b2e400..159de1e19f 100644 --- a/packages/engine-formula/src/functions/math/acosh/__tests__/index.spec.ts +++ b/packages/engine-formula/src/functions/math/acosh/__tests__/index.spec.ts @@ -18,41 +18,70 @@ import { describe, expect, it } from 'vitest'; import { FUNCTION_NAMES_MATH } from '../../function-names'; import { Acosh } from '../index'; -import { NumberValueObject, StringValueObject } from '../../../../engine/value-object/primitive-object'; +import { BooleanValueObject, NullValueObject, NumberValueObject, StringValueObject } from '../../../../engine/value-object/primitive-object'; import { ArrayValueObject, transformToValue, transformToValueObject } from '../../../../engine/value-object/array-value-object'; +import { ErrorType } from '../../../../basics/error-type'; +import { ErrorValueObject } from '../../../../engine/value-object/base-value-object'; describe('Test acosh function', () => { const testFunction = new Acosh(FUNCTION_NAMES_MATH.ACOSH); describe('Acosh', () => { - it('Value is normal', () => { + it('Value is normal number', () => { const value = NumberValueObject.create(1); const result = testFunction.calculate(value); expect(result.getValue()).toBe(0); }); - it('Value is string number', () => { - const value = new StringValueObject('1'); + it('Value is number valid', () => { + const value = NumberValueObject.create(-2); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(ErrorType.NUM); + }); + + it('Value is number string', () => { + const value = StringValueObject.create('1.5'); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(0.9624236501192069); + }); + + it('Value is normal string', () => { + const value = StringValueObject.create('test'); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(ErrorType.VALUE); + }); + + it('Value is boolean', () => { + const value = BooleanValueObject.create(true); const result = testFunction.calculate(value); expect(result.getValue()).toBe(0); }); + it('Value is blank cell', () => { + const value = NullValueObject.create(); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(ErrorType.NUM); + }); + it('Value is error', () => { + const value = ErrorValueObject.create(ErrorType.NAME); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(ErrorType.NAME); + }); it('Value is array', () => { const valueArray = ArrayValueObject.create({ calculateValueList: transformToValueObject([ - [1, ' ', 1.23, true, false], - [0, '100', '2.34', 'test', -3], + [1, ' ', 1.23, true, false, null], + [0, '100', '2.34', 'test', -3, ErrorType.NAME], ]), rowCount: 2, - columnCount: 5, + columnCount: 6, unitId: '', sheetId: '', row: 0, column: 0, }); const result = testFunction.calculate(valueArray); - expect(transformToValue(result.getArrayValue())).toStrictEqual([[0, '#VALUE!', 0.6658635291565548, 0, '#NUM!'], - ['#NUM!', 5.298292365610484, 1.494153066724473, '#VALUE!', '#NUM!']]); + expect(transformToValue(result.getArrayValue())).toStrictEqual([[0, ErrorType.VALUE, 0.6658635291565548, 0, ErrorType.NUM, ErrorType.NUM], [ErrorType.NUM, 5.298292365610484, 1.494153066724473, ErrorType.VALUE, ErrorType.NUM, ErrorType.NAME]]); }); }); }); diff --git a/packages/engine-formula/src/functions/math/acosh/index.ts b/packages/engine-formula/src/functions/math/acosh/index.ts index 363941ad57..2bb3c01a8f 100644 --- a/packages/engine-formula/src/functions/math/acosh/index.ts +++ b/packages/engine-formula/src/functions/math/acosh/index.ts @@ -14,9 +14,7 @@ * limitations under the License. */ -import { ErrorType } from '../../../basics/error-type'; import type { BaseValueObject } from '../../../engine/value-object/base-value-object'; -import { ErrorValueObject } from '../../../engine/value-object/base-value-object'; import { BaseFunction } from '../../base-function'; export class Acosh extends BaseFunction { @@ -30,7 +28,7 @@ export class Acosh extends BaseFunction { } if (variant.isError()) { - return ErrorValueObject.create(ErrorType.VALUE); + return variant; } return variant.acosh(); } diff --git a/packages/engine-formula/src/functions/math/acot/__tests__/index.spec.ts b/packages/engine-formula/src/functions/math/acot/__tests__/index.spec.ts index cbac2fdbc8..93d1f3dce8 100644 --- a/packages/engine-formula/src/functions/math/acot/__tests__/index.spec.ts +++ b/packages/engine-formula/src/functions/math/acot/__tests__/index.spec.ts @@ -18,41 +18,70 @@ import { describe, expect, it } from 'vitest'; import { FUNCTION_NAMES_MATH } from '../../function-names'; import { Acot } from '../index'; -import { NumberValueObject, StringValueObject } from '../../../../engine/value-object/primitive-object'; +import { BooleanValueObject, NullValueObject, NumberValueObject, StringValueObject } from '../../../../engine/value-object/primitive-object'; import { ArrayValueObject, transformToValue, transformToValueObject } from '../../../../engine/value-object/array-value-object'; +import { ErrorType } from '../../../../basics/error-type'; +import { ErrorValueObject } from '../../../../engine/value-object/base-value-object'; describe('Test acot function', () => { const testFunction = new Acot(FUNCTION_NAMES_MATH.ACOT); describe('Acot', () => { - it('Value is normal', () => { + it('Value is normal number', () => { const value = NumberValueObject.create(1); const result = testFunction.calculate(value); expect(result.getValue()).toBe(0.7853981633974483); }); - it('Value is string number', () => { - const value = new StringValueObject('1'); + it('Value is number negative', () => { + const value = NumberValueObject.create(-2); const result = testFunction.calculate(value); - expect(result.getValue()).toBe(0.7853981633974483); + expect(result.getValue()).toBe(2.677945044588987); + }); + + it('Value is number string', () => { + const value = StringValueObject.create('1.5'); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(0.5880026035475675); + }); + + it('Value is normal string', () => { + const value = StringValueObject.create('test'); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(ErrorType.VALUE); + }); + + it('Value is boolean', () => { + const value = BooleanValueObject.create(false); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(1.5707963267948966); + }); + it('Value is blank cell', () => { + const value = NullValueObject.create(); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(1.5707963267948966); + }); + it('Value is error', () => { + const value = ErrorValueObject.create(ErrorType.NAME); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(ErrorType.NAME); }); it('Value is array', () => { const valueArray = ArrayValueObject.create({ calculateValueList: transformToValueObject([ - [1, ' ', 1.23, true, false], - [0, '100', '2.34', 'test', -3], + [1, ' ', 1.23, true, false, null], + [0, '100', '2.34', 'test', -3, ErrorType.NAME], ]), rowCount: 2, - columnCount: 5, + columnCount: 6, unitId: '', sheetId: '', row: 0, column: 0, }); const result = testFunction.calculate(valueArray); - expect(transformToValue(result.getArrayValue())).toStrictEqual([[0.7853981633974483, '#VALUE!', 0.682622552417217, 0.7853981633974483, 1.5707963267948966], - [1.5707963267948966, 0.009999666686665238, 0.40385979490737667, '#VALUE!', 2.819842099193151]]); + expect(transformToValue(result.getArrayValue())).toStrictEqual([[0.7853981633974483, ErrorType.VALUE, 0.682622552417217, 0.7853981633974483, 1.5707963267948966, 1.5707963267948966], [1.5707963267948966, 0.009999666686665238, 0.40385979490737667, ErrorType.VALUE, 2.819842099193151, ErrorType.NAME]]); }); }); }); diff --git a/packages/engine-formula/src/functions/math/asin/__tests__/index.spec.ts b/packages/engine-formula/src/functions/math/asin/__tests__/index.spec.ts new file mode 100644 index 0000000000..f9b1827acd --- /dev/null +++ b/packages/engine-formula/src/functions/math/asin/__tests__/index.spec.ts @@ -0,0 +1,87 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { describe, expect, it } from 'vitest'; + +import { FUNCTION_NAMES_MATH } from '../../function-names'; +import { Asin } from '../index'; +import { BooleanValueObject, NullValueObject, NumberValueObject, StringValueObject } from '../../../../engine/value-object/primitive-object'; +import { ArrayValueObject, transformToValue, transformToValueObject } from '../../../../engine/value-object/array-value-object'; +import { ErrorType } from '../../../../basics/error-type'; +import { ErrorValueObject } from '../../../../engine/value-object/base-value-object'; + +describe('Test asin function', () => { + const testFunction = new Asin(FUNCTION_NAMES_MATH.ASIN); + + describe('Asin', () => { + it('Value is normal number', () => { + const value = NumberValueObject.create(1); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(1.5707963267948966); + }); + + it('Value is number valid', () => { + const value = NumberValueObject.create(-2); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(ErrorType.NUM); + }); + + it('Value is number string', () => { + const value = StringValueObject.create('0.5'); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(0.5235987755982989); + }); + + it('Value is normal string', () => { + const value = StringValueObject.create('test'); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(ErrorType.VALUE); + }); + + it('Value is boolean', () => { + const value = BooleanValueObject.create(false); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(0); + }); + it('Value is blank cell', () => { + const value = NullValueObject.create(); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(0); + }); + it('Value is error', () => { + const value = ErrorValueObject.create(ErrorType.NAME); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(ErrorType.NAME); + }); + + it('Value is array', () => { + const valueArray = ArrayValueObject.create({ + calculateValueList: transformToValueObject([ + [1, ' ', 1.23, true, false, null], + [0, '100', '2.34', 'test', -3, ErrorType.NAME], + ]), + rowCount: 2, + columnCount: 6, + unitId: '', + sheetId: '', + row: 0, + column: 0, + }); + const result = testFunction.calculate(valueArray); + expect(transformToValue(result.getArrayValue())).toStrictEqual([[1.5707963267948966, '#VALUE!', ErrorType.NUM, 1.5707963267948966, 0, 0], [0, ErrorType.NUM, ErrorType.NUM, '#VALUE!', ErrorType.NUM, '#NAME?']]); + }); + }); +}); diff --git a/packages/engine-formula/src/functions/math/asin/index.ts b/packages/engine-formula/src/functions/math/asin/index.ts new file mode 100644 index 0000000000..6263f43ba8 --- /dev/null +++ b/packages/engine-formula/src/functions/math/asin/index.ts @@ -0,0 +1,36 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { BaseValueObject } from '../../../engine/value-object/base-value-object'; +import { BaseFunction } from '../../base-function'; + +export class Asin extends BaseFunction { + override minParams = 1; + + override maxParams = 1; + + override calculate(variant: BaseValueObject) { + if (variant.isString()) { + variant = variant.convertToNumberObjectValue(); + } + + if (variant.isError()) { + return variant; + } + + return variant.asin(); + } +} diff --git a/packages/engine-formula/src/functions/math/asinh/__tests__/index.spec.ts b/packages/engine-formula/src/functions/math/asinh/__tests__/index.spec.ts new file mode 100644 index 0000000000..8447a50da9 --- /dev/null +++ b/packages/engine-formula/src/functions/math/asinh/__tests__/index.spec.ts @@ -0,0 +1,87 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { describe, expect, it } from 'vitest'; + +import { FUNCTION_NAMES_MATH } from '../../function-names'; +import { Asinh } from '../index'; +import { BooleanValueObject, NullValueObject, NumberValueObject, StringValueObject } from '../../../../engine/value-object/primitive-object'; +import { ArrayValueObject, transformToValue, transformToValueObject } from '../../../../engine/value-object/array-value-object'; +import { ErrorType } from '../../../../basics/error-type'; +import { ErrorValueObject } from '../../../../engine/value-object/base-value-object'; + +describe('Test asinh function', () => { + const testFunction = new Asinh(FUNCTION_NAMES_MATH.ASINH); + + describe('Asinh', () => { + it('Value is normal number', () => { + const value = NumberValueObject.create(1); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(0.881373587019543); + }); + + it('Value is number negative', () => { + const value = NumberValueObject.create(-2); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(-1.4436354751788103); + }); + + it('Value is number string', () => { + const value = StringValueObject.create('0.5'); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(0.48121182505960347); + }); + + it('Value is normal string', () => { + const value = StringValueObject.create('test'); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(ErrorType.VALUE); + }); + + it('Value is boolean', () => { + const value = BooleanValueObject.create(false); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(0); + }); + it('Value is blank cell', () => { + const value = NullValueObject.create(); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(0); + }); + it('Value is error', () => { + const value = ErrorValueObject.create(ErrorType.NAME); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(ErrorType.NAME); + }); + + it('Value is array', () => { + const valueArray = ArrayValueObject.create({ + calculateValueList: transformToValueObject([ + [1, ' ', 1.23, true, false, null], + [0, '100', '2.34', 'test', -3, ErrorType.NAME], + ]), + rowCount: 2, + columnCount: 6, + unitId: '', + sheetId: '', + row: 0, + column: 0, + }); + const result = testFunction.calculate(valueArray); + expect(transformToValue(result.getArrayValue())).toStrictEqual([[0.881373587019543, ErrorType.VALUE, 1.0350378961923077, 0.881373587019543, 0, 0], [0, 5.298342365610589, 1.5861119704218916, ErrorType.VALUE, -1.8184464592320668, ErrorType.NAME]]); + }); + }); +}); diff --git a/packages/engine-formula/src/functions/math/asinh/index.ts b/packages/engine-formula/src/functions/math/asinh/index.ts new file mode 100644 index 0000000000..eb277fa2a1 --- /dev/null +++ b/packages/engine-formula/src/functions/math/asinh/index.ts @@ -0,0 +1,36 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { BaseValueObject } from '../../../engine/value-object/base-value-object'; +import { BaseFunction } from '../../base-function'; + +export class Asinh extends BaseFunction { + override minParams = 1; + + override maxParams = 1; + + override calculate(variant: BaseValueObject) { + if (variant.isString()) { + variant = variant.convertToNumberObjectValue(); + } + + if (variant.isError()) { + return variant; + } + + return variant.asinh(); + } +} diff --git a/packages/engine-formula/src/functions/math/atan/__tests__/index.spec.ts b/packages/engine-formula/src/functions/math/atan/__tests__/index.spec.ts new file mode 100644 index 0000000000..217dc78b7d --- /dev/null +++ b/packages/engine-formula/src/functions/math/atan/__tests__/index.spec.ts @@ -0,0 +1,87 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { describe, expect, it } from 'vitest'; + +import { FUNCTION_NAMES_MATH } from '../../function-names'; +import { Atan } from '../index'; +import { BooleanValueObject, NullValueObject, NumberValueObject, StringValueObject } from '../../../../engine/value-object/primitive-object'; +import { ArrayValueObject, transformToValue, transformToValueObject } from '../../../../engine/value-object/array-value-object'; +import { ErrorType } from '../../../../basics/error-type'; +import { ErrorValueObject } from '../../../../engine/value-object/base-value-object'; + +describe('Test atan function', () => { + const testFunction = new Atan(FUNCTION_NAMES_MATH.ATAN); + + describe('Atan', () => { + it('Value is normal number', () => { + const value = NumberValueObject.create(1); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(0.7853981633974483); + }); + + it('Value is number negative', () => { + const value = NumberValueObject.create(-2); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(-1.1071487177940904); + }); + + it('Value is number string', () => { + const value = StringValueObject.create('0.5'); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(0.4636476090008061); + }); + + it('Value is normal string', () => { + const value = StringValueObject.create('test'); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(ErrorType.VALUE); + }); + + it('Value is boolean', () => { + const value = BooleanValueObject.create(false); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(0); + }); + it('Value is blank cell', () => { + const value = NullValueObject.create(); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(0); + }); + it('Value is error', () => { + const value = ErrorValueObject.create(ErrorType.NAME); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(ErrorType.NAME); + }); + + it('Value is array', () => { + const valueArray = ArrayValueObject.create({ + calculateValueList: transformToValueObject([ + [1, ' ', 1.23, true, false, null], + [0, '100', '2.34', 'test', -3, ErrorType.NAME], + ]), + rowCount: 2, + columnCount: 6, + unitId: '', + sheetId: '', + row: 0, + column: 0, + }); + const result = testFunction.calculate(valueArray); + expect(transformToValue(result.getArrayValue())).toStrictEqual([[0.7853981633974483, ErrorType.VALUE, 0.8881737743776796, 0.7853981633974483, 0, 0], [0, 1.5607966601082315, 1.16693653188752, ErrorType.VALUE, -1.2490457723982544, ErrorType.NAME]]); + }); + }); +}); diff --git a/packages/engine-formula/src/functions/math/atan/index.ts b/packages/engine-formula/src/functions/math/atan/index.ts new file mode 100644 index 0000000000..3d5bfda69e --- /dev/null +++ b/packages/engine-formula/src/functions/math/atan/index.ts @@ -0,0 +1,36 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { BaseValueObject } from '../../../engine/value-object/base-value-object'; +import { BaseFunction } from '../../base-function'; + +export class Atan extends BaseFunction { + override minParams = 1; + + override maxParams = 1; + + override calculate(variant: BaseValueObject) { + if (variant.isString()) { + variant = variant.convertToNumberObjectValue(); + } + + if (variant.isError()) { + return variant; + } + + return variant.atan(); + } +} diff --git a/packages/engine-formula/src/functions/math/atan2/__tests__/index.spec.ts b/packages/engine-formula/src/functions/math/atan2/__tests__/index.spec.ts new file mode 100644 index 0000000000..0037d38616 --- /dev/null +++ b/packages/engine-formula/src/functions/math/atan2/__tests__/index.spec.ts @@ -0,0 +1,136 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { describe, expect, it } from 'vitest'; + +import { FUNCTION_NAMES_MATH } from '../../function-names'; +import { Atan2 } from '../index'; +import { BooleanValueObject, NullValueObject, NumberValueObject, StringValueObject } from '../../../../engine/value-object/primitive-object'; +import { ArrayValueObject, transformToValue, transformToValueObject } from '../../../../engine/value-object/array-value-object'; +import { ErrorType } from '../../../../basics/error-type'; +import { ErrorValueObject } from '../../../../engine/value-object/base-value-object'; + +describe('Test atan2 function', () => { + const testFunction = new Atan2(FUNCTION_NAMES_MATH.ATAN2); + + describe('Atan2', () => { + it('Value is normal number', () => { + const xNum = NumberValueObject.create(1); + const yNum = NumberValueObject.create(2); + const result = testFunction.calculate(xNum, yNum); + expect(result.getValue()).toBe(1.1071487177940904); + }); + it('Value is normal number 2', () => { + const xNum = NumberValueObject.create(8); + const yNum = NumberValueObject.create(9); + const result = testFunction.calculate(xNum, yNum); + expect(result.getValue()).toBe(0.844153986113171); + }); + + it('Value is number valid', () => { + const xNum = NumberValueObject.create(-2); + const yNum = NumberValueObject.create(-3); + const result = testFunction.calculate(xNum, yNum); + expect(result.getValue()).toBe(-2.1587989303424644); + }); + + it('Value is number string', () => { + const xNum = StringValueObject.create('0.5'); + const yNum = NumberValueObject.create(2); + const result = testFunction.calculate(xNum, yNum); + expect(result.getValue()).toBe(1.3258176636680326); + }); + + it('Value is normal string', () => { + const xNum = StringValueObject.create('test'); + const yNum = NumberValueObject.create(1); + const result = testFunction.calculate(xNum, yNum); + expect(result.getValue()).toBe(ErrorType.VALUE); + }); + + it('Value is boolean', () => { + const xNum = BooleanValueObject.create(false); + const yNum = NumberValueObject.create(1); + const result = testFunction.calculate(xNum, yNum); + expect(result.getValue()).toBe(1.5707963267948966); + }); + it('Value is blank cell', () => { + const xNum = NullValueObject.create(); + const yNum = NumberValueObject.create(1); + const result = testFunction.calculate(xNum, yNum); + expect(result.getValue()).toBe(1.5707963267948966); + }); + it('Value is error', () => { + const xNum = ErrorValueObject.create(ErrorType.NAME); + const yNum = NumberValueObject.create(1); + const result = testFunction.calculate(xNum, yNum); + expect(result.getValue()).toBe(ErrorType.NAME); + }); + it('Result is error', () => { + const xNum = NumberValueObject.create(0); + const yNum = NumberValueObject.create(0); + const result = testFunction.calculate(xNum, yNum); + expect(result.getValue()).toBe(ErrorType.DIV_BY_ZERO); + }); + + it('Value is array and number', () => { + const xNum = ArrayValueObject.create({ + calculateValueList: transformToValueObject([ + [1, ' ', 1.23, true, false, null], + [0, '100', '2.34', 'test', -3, ErrorType.NAME], + ]), + rowCount: 2, + columnCount: 6, + unitId: '', + sheetId: '', + row: 0, + column: 0, + }); + const yNum = NumberValueObject.create(1); + const result = testFunction.calculate(xNum, yNum); + expect(transformToValue(result.getArrayValue())).toStrictEqual([[0.7853981633974483, ErrorType.VALUE, 0.682622552417217, 0.7853981633974483, 1.5707963267948966, 1.5707963267948966], [1.5707963267948966, 0.009999666686665238, 0.40385979490737667, ErrorType.VALUE, 2.819842099193151, ErrorType.NAME]]); + }); + it('Value is array and array', () => { + const xNum = ArrayValueObject.create({ + calculateValueList: transformToValueObject([ + [1], + [2], + [3], + ]), + rowCount: 3, + columnCount: 1, + unitId: '', + sheetId: '', + row: 0, + column: 0, + }); + const yNum = ArrayValueObject.create({ + calculateValueList: transformToValueObject([ + [1, ' ', 1.23, true, false, null], + [0, '100', '2.34', 'test', -3, ErrorType.NAME], + ]), + rowCount: 2, + columnCount: 6, + unitId: '', + sheetId: '', + row: 0, + column: 0, + }); + const result = testFunction.calculate(xNum, yNum); + expect(transformToValue(result.getArrayValue())).toStrictEqual([[0.7853981633974483, ErrorType.VALUE, 0.8881737743776796, 0.7853981633974483, 0, 0], [0, 1.550798992821746, 0.8635794970038352, ErrorType.VALUE, -0.982793723247329, ErrorType.NAME], [ErrorType.NA, ErrorType.NA, ErrorType.NA, ErrorType.NA, ErrorType.NA, ErrorType.NA]]); + }); + }); +}); diff --git a/packages/engine-formula/src/functions/math/atan2/index.ts b/packages/engine-formula/src/functions/math/atan2/index.ts new file mode 100644 index 0000000000..6cafa4d766 --- /dev/null +++ b/packages/engine-formula/src/functions/math/atan2/index.ts @@ -0,0 +1,45 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { BaseValueObject } from '../../../engine/value-object/base-value-object'; +import { BaseFunction } from '../../base-function'; + +export class Atan2 extends BaseFunction { + override minParams = 2; + + override maxParams = 2; + + override calculate(xNum: BaseValueObject, yNum: BaseValueObject) { + if (xNum.isString()) { + xNum = xNum.convertToNumberObjectValue(); + } + + if (xNum.isError()) { + return xNum; + } + + if (yNum.isString()) { + yNum = yNum.convertToNumberObjectValue(); + } + + if (yNum.isError()) { + return yNum; + } + + // Note that the order of parameters is different from JavaScript + return yNum.atan2(xNum); + } +} diff --git a/packages/engine-formula/src/functions/math/atanh/__tests__/index.spec.ts b/packages/engine-formula/src/functions/math/atanh/__tests__/index.spec.ts new file mode 100644 index 0000000000..91c11519bc --- /dev/null +++ b/packages/engine-formula/src/functions/math/atanh/__tests__/index.spec.ts @@ -0,0 +1,87 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { describe, expect, it } from 'vitest'; + +import { FUNCTION_NAMES_MATH } from '../../function-names'; +import { Atanh } from '../index'; +import { BooleanValueObject, NullValueObject, NumberValueObject, StringValueObject } from '../../../../engine/value-object/primitive-object'; +import { ArrayValueObject, transformToValue, transformToValueObject } from '../../../../engine/value-object/array-value-object'; +import { ErrorType } from '../../../../basics/error-type'; +import { ErrorValueObject } from '../../../../engine/value-object/base-value-object'; + +describe('Test atanh function', () => { + const testFunction = new Atanh(FUNCTION_NAMES_MATH.ATANH); + + describe('Atanh', () => { + it('Value is normal number', () => { + const value = NumberValueObject.create(0.1); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(0.10033534773107558); + }); + + it('Value is number negative', () => { + const value = NumberValueObject.create(-2); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(ErrorType.NUM); + }); + + it('Value is number string', () => { + const value = StringValueObject.create('0.5'); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(0.5493061443340548); + }); + + it('Value is normal string', () => { + const value = StringValueObject.create('test'); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(ErrorType.VALUE); + }); + + it('Value is boolean', () => { + const value = BooleanValueObject.create(false); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(0); + }); + it('Value is blank cell', () => { + const value = NullValueObject.create(); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(0); + }); + it('Value is error', () => { + const value = ErrorValueObject.create(ErrorType.NAME); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(ErrorType.NAME); + }); + + it('Value is array', () => { + const valueArray = ArrayValueObject.create({ + calculateValueList: transformToValueObject([ + [1, ' ', 1.23, true, false, null], + [0, '100', '2.34', 'test', -3, ErrorType.NAME], + ]), + rowCount: 2, + columnCount: 6, + unitId: '', + sheetId: '', + row: 0, + column: 0, + }); + const result = testFunction.calculate(valueArray); + expect(transformToValue(result.getArrayValue())).toStrictEqual([[ErrorType.NUM, ErrorType.VALUE, ErrorType.NUM, ErrorType.NUM, 0, 0], [0, ErrorType.NUM, ErrorType.NUM, ErrorType.VALUE, ErrorType.NUM, ErrorType.NAME]]); + }); + }); +}); diff --git a/packages/engine-formula/src/functions/math/atanh/index.ts b/packages/engine-formula/src/functions/math/atanh/index.ts new file mode 100644 index 0000000000..c36d07116d --- /dev/null +++ b/packages/engine-formula/src/functions/math/atanh/index.ts @@ -0,0 +1,36 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { BaseValueObject } from '../../../engine/value-object/base-value-object'; +import { BaseFunction } from '../../base-function'; + +export class Atanh extends BaseFunction { + override minParams = 1; + + override maxParams = 1; + + override calculate(variant: BaseValueObject) { + if (variant.isString()) { + variant = variant.convertToNumberObjectValue(); + } + + if (variant.isError()) { + return variant; + } + + return variant.atanh(); + } +} diff --git a/packages/engine-formula/src/functions/math/cos/__tests__/index.spec.ts b/packages/engine-formula/src/functions/math/cos/__tests__/index.spec.ts new file mode 100644 index 0000000000..81fd1455fd --- /dev/null +++ b/packages/engine-formula/src/functions/math/cos/__tests__/index.spec.ts @@ -0,0 +1,87 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { describe, expect, it } from 'vitest'; + +import { FUNCTION_NAMES_MATH } from '../../function-names'; +import { Cos } from '../index'; +import { BooleanValueObject, NullValueObject, NumberValueObject, StringValueObject } from '../../../../engine/value-object/primitive-object'; +import { ArrayValueObject, transformToValue, transformToValueObject } from '../../../../engine/value-object/array-value-object'; +import { ErrorType } from '../../../../basics/error-type'; +import { ErrorValueObject } from '../../../../engine/value-object/base-value-object'; + +describe('Test cos function', () => { + const testFunction = new Cos(FUNCTION_NAMES_MATH.COS); + + describe('Cos', () => { + it('Value is normal number', () => { + const value = NumberValueObject.create(1); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(0.5403023058681398); + }); + + it('Value is number negative', () => { + const value = NumberValueObject.create(-2); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(-0.4161468365471424); + }); + + it('Value is number string', () => { + const value = StringValueObject.create('0.5'); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(0.8775825618903728); + }); + + it('Value is normal string', () => { + const value = StringValueObject.create('test'); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(ErrorType.VALUE); + }); + + it('Value is boolean', () => { + const value = BooleanValueObject.create(false); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(1); + }); + it('Value is blank cell', () => { + const value = NullValueObject.create(); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(1); + }); + it('Value is error', () => { + const value = ErrorValueObject.create(ErrorType.NAME); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(ErrorType.NAME); + }); + + it('Value is array', () => { + const valueArray = ArrayValueObject.create({ + calculateValueList: transformToValueObject([ + [1, ' ', 1.23, true, false, null], + [0, '100', '2.34', 'test', -3, ErrorType.NAME], + ]), + rowCount: 2, + columnCount: 6, + unitId: '', + sheetId: '', + row: 0, + column: 0, + }); + const result = testFunction.calculate(valueArray); + expect(transformToValue(result.getArrayValue())).toStrictEqual([[0.5403023058681398, ErrorType.VALUE, 0.3342377271245026, 0.5403023058681398, 1, 1], [1, 0.8623188722876839, -0.695563326462902, ErrorType.VALUE, -0.9899924966004454, ErrorType.NAME]]); + }); + }); +}); diff --git a/packages/engine-formula/src/functions/math/cos/index.ts b/packages/engine-formula/src/functions/math/cos/index.ts new file mode 100644 index 0000000000..df13bad3b1 --- /dev/null +++ b/packages/engine-formula/src/functions/math/cos/index.ts @@ -0,0 +1,36 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { BaseValueObject } from '../../../engine/value-object/base-value-object'; +import { BaseFunction } from '../../base-function'; + +export class Cos extends BaseFunction { + override minParams = 1; + + override maxParams = 1; + + override calculate(variant: BaseValueObject) { + if (variant.isString()) { + variant = variant.convertToNumberObjectValue(); + } + + if (variant.isError()) { + return variant; + } + + return variant.cos(); + } +} diff --git a/packages/engine-formula/src/functions/math/function-map.ts b/packages/engine-formula/src/functions/math/function-map.ts index 837d4e1f7a..dfa986deb4 100644 --- a/packages/engine-formula/src/functions/math/function-map.ts +++ b/packages/engine-formula/src/functions/math/function-map.ts @@ -18,6 +18,12 @@ import { Abs } from './abs'; import { Acos } from './acos'; import { Acosh } from './acosh'; import { Acot } from './acot'; +import { Asin } from './asin'; +import { Asinh } from './asinh'; +import { Atan } from './atan'; +import { Atan2 } from './atan2'; +import { Atanh } from './atanh'; +import { Cos } from './cos'; import { FUNCTION_NAMES_MATH } from './function-names'; import { Mod } from './mod'; import { Power } from './power'; @@ -26,17 +32,27 @@ import { Subtotal } from './subtotal'; import { Sum } from './sum'; import { Sumif } from './sumif'; import { Sumifs } from './sumifs'; +import { Tan } from './tan'; +import { Tanh } from './tanh'; export const functionMath = [ [Abs, FUNCTION_NAMES_MATH.ABS], [Acos, FUNCTION_NAMES_MATH.ACOS], [Acosh, FUNCTION_NAMES_MATH.ACOSH], [Acot, FUNCTION_NAMES_MATH.ACOT], + [Asin, FUNCTION_NAMES_MATH.ASIN], + [Asinh, FUNCTION_NAMES_MATH.ASINH], + [Atan, FUNCTION_NAMES_MATH.ATAN], + [Atan2, FUNCTION_NAMES_MATH.ATAN2], + [Atanh, FUNCTION_NAMES_MATH.ATANH], + [Cos, FUNCTION_NAMES_MATH.COS], [Mod, FUNCTION_NAMES_MATH.MOD], + [Power, FUNCTION_NAMES_MATH.POWER], + [Product, FUNCTION_NAMES_MATH.PRODUCT], [Subtotal, FUNCTION_NAMES_MATH.SUBTOTAL], [Sum, FUNCTION_NAMES_MATH.SUM], [Sumif, FUNCTION_NAMES_MATH.SUMIF], [Sumifs, FUNCTION_NAMES_MATH.SUMIFS], - [Power, FUNCTION_NAMES_MATH.POWER], - [Product, FUNCTION_NAMES_MATH.PRODUCT], + [Tan, FUNCTION_NAMES_MATH.TAN], + [Tanh, FUNCTION_NAMES_MATH.TANH], ]; diff --git a/packages/engine-formula/src/functions/math/tan/__tests__/index.spec.ts b/packages/engine-formula/src/functions/math/tan/__tests__/index.spec.ts new file mode 100644 index 0000000000..7faf8b6ddb --- /dev/null +++ b/packages/engine-formula/src/functions/math/tan/__tests__/index.spec.ts @@ -0,0 +1,87 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { describe, expect, it } from 'vitest'; + +import { FUNCTION_NAMES_MATH } from '../../function-names'; +import { Tan } from '../index'; +import { BooleanValueObject, NullValueObject, NumberValueObject, StringValueObject } from '../../../../engine/value-object/primitive-object'; +import { ArrayValueObject, transformToValue, transformToValueObject } from '../../../../engine/value-object/array-value-object'; +import { ErrorType } from '../../../../basics/error-type'; +import { ErrorValueObject } from '../../../../engine/value-object/base-value-object'; + +describe('Test tan function', () => { + const testFunction = new Tan(FUNCTION_NAMES_MATH.TAN); + + describe('Tan', () => { + it('Value is normal number', () => { + const value = NumberValueObject.create(1); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(1.5574077246549023); + }); + + it('Value is number negative', () => { + const value = NumberValueObject.create(-2); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(2.185039863261519); + }); + + it('Value is number string', () => { + const value = StringValueObject.create('0.5'); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(0.5463024898437905); + }); + + it('Value is normal string', () => { + const value = StringValueObject.create('test'); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(ErrorType.VALUE); + }); + + it('Value is boolean', () => { + const value = BooleanValueObject.create(false); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(0); + }); + it('Value is blank cell', () => { + const value = NullValueObject.create(); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(0); + }); + it('Value is error', () => { + const value = ErrorValueObject.create(ErrorType.NAME); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(ErrorType.NAME); + }); + + it('Value is array', () => { + const valueArray = ArrayValueObject.create({ + calculateValueList: transformToValueObject([ + [1, ' ', 1.23, true, false, null], + [0, '100', '2.34', 'test', -3, ErrorType.NAME], + ]), + rowCount: 2, + columnCount: 6, + unitId: '', + sheetId: '', + row: 0, + column: 0, + }); + const result = testFunction.calculate(valueArray); + expect(transformToValue(result.getArrayValue())).toStrictEqual([[1.5574077246549023, ErrorType.VALUE, 2.819815734268152, 1.5574077246549023, 0, 0], [0, -0.5872139151569291, -1.032925063376592, ErrorType.VALUE, 0.1425465430742778, ErrorType.NAME]]); + }); + }); +}); diff --git a/packages/engine-formula/src/functions/math/tan/index.ts b/packages/engine-formula/src/functions/math/tan/index.ts new file mode 100644 index 0000000000..210ec2f113 --- /dev/null +++ b/packages/engine-formula/src/functions/math/tan/index.ts @@ -0,0 +1,36 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { BaseValueObject } from '../../../engine/value-object/base-value-object'; +import { BaseFunction } from '../../base-function'; + +export class Tan extends BaseFunction { + override minParams = 1; + + override maxParams = 1; + + override calculate(variant: BaseValueObject) { + if (variant.isString()) { + variant = variant.convertToNumberObjectValue(); + } + + if (variant.isError()) { + return variant; + } + + return variant.tan(); + } +} diff --git a/packages/engine-formula/src/functions/math/tanh/__tests__/index.spec.ts b/packages/engine-formula/src/functions/math/tanh/__tests__/index.spec.ts new file mode 100644 index 0000000000..2d6c8aa7a3 --- /dev/null +++ b/packages/engine-formula/src/functions/math/tanh/__tests__/index.spec.ts @@ -0,0 +1,87 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { describe, expect, it } from 'vitest'; + +import { FUNCTION_NAMES_MATH } from '../../function-names'; +import { Tanh } from '../index'; +import { BooleanValueObject, NullValueObject, NumberValueObject, StringValueObject } from '../../../../engine/value-object/primitive-object'; +import { ArrayValueObject, transformToValue, transformToValueObject } from '../../../../engine/value-object/array-value-object'; +import { ErrorType } from '../../../../basics/error-type'; +import { ErrorValueObject } from '../../../../engine/value-object/base-value-object'; + +describe('Test tanh function', () => { + const testFunction = new Tanh(FUNCTION_NAMES_MATH.TANH); + + describe('Tanh', () => { + it('Value is normal number', () => { + const value = NumberValueObject.create(1); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(0.7615941559557649); + }); + + it('Value is number negative', () => { + const value = NumberValueObject.create(-2); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(-0.9640275800758169); + }); + + it('Value is number string', () => { + const value = StringValueObject.create('0.5'); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(0.46211715726000974); + }); + + it('Value is normal string', () => { + const value = StringValueObject.create('test'); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(ErrorType.VALUE); + }); + + it('Value is boolean', () => { + const value = BooleanValueObject.create(false); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(0); + }); + it('Value is blank cell', () => { + const value = NullValueObject.create(); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(0); + }); + it('Value is error', () => { + const value = ErrorValueObject.create(ErrorType.NAME); + const result = testFunction.calculate(value); + expect(result.getValue()).toBe(ErrorType.NAME); + }); + + it('Value is array', () => { + const valueArray = ArrayValueObject.create({ + calculateValueList: transformToValueObject([ + [1, ' ', 1.23, true, false, null], + [0, '100', '2.34', 'test', -3, ErrorType.NAME], + ]), + rowCount: 2, + columnCount: 6, + unitId: '', + sheetId: '', + row: 0, + column: 0, + }); + const result = testFunction.calculate(valueArray); + expect(transformToValue(result.getArrayValue())).toStrictEqual([[0.7615941559557649, ErrorType.VALUE, 0.8425793256589296, 0.7615941559557649, 0, 0], [0, 1, 0.9816125892654238, ErrorType.VALUE, -0.9950547536867305, ErrorType.NAME]]); + }); + }); +}); diff --git a/packages/engine-formula/src/functions/math/tanh/index.ts b/packages/engine-formula/src/functions/math/tanh/index.ts new file mode 100644 index 0000000000..468fc85681 --- /dev/null +++ b/packages/engine-formula/src/functions/math/tanh/index.ts @@ -0,0 +1,36 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { BaseValueObject } from '../../../engine/value-object/base-value-object'; +import { BaseFunction } from '../../base-function'; + +export class Tanh extends BaseFunction { + override minParams = 1; + + override maxParams = 1; + + override calculate(variant: BaseValueObject) { + if (variant.isString()) { + variant = variant.convertToNumberObjectValue(); + } + + if (variant.isError()) { + return variant; + } + + return variant.tanh(); + } +} diff --git a/packages/sheets-formula/src/controllers/formula-render.controller.ts b/packages/sheets-formula/src/controllers/formula-render.controller.ts index 2c81bcc3b3..e673f0a62a 100644 --- a/packages/sheets-formula/src/controllers/formula-render.controller.ts +++ b/packages/sheets-formula/src/controllers/formula-render.controller.ts @@ -17,7 +17,7 @@ import { LifecycleStages, OnLifecycle, RxDisposable } from '@univerjs/core'; import { Inject } from '@wendellhu/redi'; import { INTERCEPTOR_POINT, SheetInterceptorService } from '@univerjs/sheets'; -import { extractFormulaError, extractFormulaNumber } from './utils/utils'; +import { extractFormulaError } from './utils/utils'; const FORMULA_ERROR_MARK = { tl: { @@ -41,15 +41,6 @@ export class FormulaRenderManagerController extends RxDisposable { INTERCEPTOR_POINT.CELL_CONTENT, { handler: (cell, pos, next) => { - // Dealing with precision issues - const formulaNumber = extractFormulaNumber(cell); - if (formulaNumber !== null) { - return next({ - ...cell, - v: formulaNumber, - }); - } - const errorType = extractFormulaError(cell); if (!errorType) { return next(cell); diff --git a/packages/sheets-formula/src/locale/function-list/math/en-US.ts b/packages/sheets-formula/src/locale/function-list/math/en-US.ts index 94b47bff9c..118669dd5b 100644 --- a/packages/sheets-formula/src/locale/function-list/math/en-US.ts +++ b/packages/sheets-formula/src/locale/function-list/math/en-US.ts @@ -113,7 +113,7 @@ export default { }, }, ASIN: { - description: 'Returns the arcsine of a number', + description: 'Returns the arcsine of a number.', abstract: 'Returns the arcsine of a number', links: [ { @@ -122,12 +122,11 @@ export default { }, ], functionParameter: { - number1: { name: 'number1', detail: 'first' }, - number2: { name: 'number2', detail: 'second' }, + number: { name: 'number', detail: 'The sine of the angle you want and must be from -1 to 1.' }, }, }, ASINH: { - description: 'Returns the inverse hyperbolic sine of a number', + description: 'Returns the inverse hyperbolic sine of a number.', abstract: 'Returns the inverse hyperbolic sine of a number', links: [ { @@ -136,12 +135,11 @@ export default { }, ], functionParameter: { - number1: { name: 'number1', detail: 'first' }, - number2: { name: 'number2', detail: 'second' }, + number: { name: 'number', detail: 'Any real number.' }, }, }, ATAN: { - description: 'Returns the arctangent of a number', + description: 'Returns the arctangent of a number.', abstract: 'Returns the arctangent of a number', links: [ { @@ -150,12 +148,11 @@ export default { }, ], functionParameter: { - number1: { name: 'number1', detail: 'first' }, - number2: { name: 'number2', detail: 'second' }, + number: { name: 'number', detail: 'The tangent of the angle you want.' }, }, }, ATAN2: { - description: 'Returns the arctangent from x- and y-coordinates', + description: 'Returns the arctangent from x- and y-coordinates.', abstract: 'Returns the arctangent from x- and y-coordinates', links: [ { @@ -164,12 +161,12 @@ export default { }, ], functionParameter: { - number1: { name: 'number1', detail: 'first' }, - number2: { name: 'number2', detail: 'second' }, + xNum: { name: 'x_num', detail: 'The x-coordinate of the point.' }, + yNum: { name: 'y_num', detail: 'The y-coordinate of the point.' }, }, }, ATANH: { - description: 'Returns the inverse hyperbolic tangent of a number', + description: 'Returns the inverse hyperbolic tangent of a number.', abstract: 'Returns the inverse hyperbolic tangent of a number', links: [ { @@ -178,8 +175,7 @@ export default { }, ], functionParameter: { - number1: { name: 'number1', detail: 'first' }, - number2: { name: 'number2', detail: 'second' }, + number: { name: 'number', detail: 'Any real number between 1 and -1.' }, }, }, BASE: { @@ -267,7 +263,7 @@ export default { }, }, COS: { - description: 'Returns the cosine of a number', + description: 'Returns the cosine of a number.', abstract: 'Returns the cosine of a number', links: [ { @@ -276,8 +272,7 @@ export default { }, ], functionParameter: { - number1: { name: 'number1', detail: 'first' }, - number2: { name: 'number2', detail: 'second' }, + number: { name: 'number', detail: 'The angle in radians for which you want the cosine.' }, }, }, COSH: { @@ -1141,7 +1136,7 @@ export default { }, }, TAN: { - description: 'Returns the tangent of a number', + description: 'Returns the tangent of a number.', abstract: 'Returns the tangent of a number', links: [ { @@ -1150,12 +1145,11 @@ export default { }, ], functionParameter: { - number1: { name: 'number1', detail: 'first' }, - number2: { name: 'number2', detail: 'second' }, + number: { name: 'number', detail: 'The angle in radians for which you want the tangent.' }, }, }, TANH: { - description: 'Returns the hyperbolic tangent of a number', + description: 'Returns the hyperbolic tangent of a number.', abstract: 'Returns the hyperbolic tangent of a number', links: [ { @@ -1164,8 +1158,7 @@ export default { }, ], functionParameter: { - number1: { name: 'number1', detail: 'first' }, - number2: { name: 'number2', detail: 'second' }, + number: { name: 'number', detail: 'Any real number.' }, }, }, TRUNC: { diff --git a/packages/sheets-formula/src/locale/function-list/math/ja-JP.ts b/packages/sheets-formula/src/locale/function-list/math/ja-JP.ts index e57e33731e..b3ee6a4ac0 100644 --- a/packages/sheets-formula/src/locale/function-list/math/ja-JP.ts +++ b/packages/sheets-formula/src/locale/function-list/math/ja-JP.ts @@ -114,7 +114,7 @@ export default { }, ASIN: { description: '数値のアークサインを返します。', - abstract: '数値のアークサインを返します。', + abstract: '数値のアークサインを返します', links: [ { title: '指導', @@ -122,13 +122,12 @@ export default { }, ], functionParameter: { - number1: { name: 'number1', detail: 'first' }, - number2: { name: 'number2', detail: 'second' }, + number: { name: '数値', detail: '求める角度のサインの値を -1 ~ 1 の範囲で指定します。' }, }, }, ASINH: { description: '数値の双曲線逆正弦 (ハイパーボリック サインの逆関数) を返します。', - abstract: '数値の双曲線逆正弦 (ハイパーボリック サインの逆関数) を返します。', + abstract: '数値の双曲線逆正弦 (ハイパーボリック サインの逆関数) を返します', links: [ { title: '指導', @@ -136,13 +135,12 @@ export default { }, ], functionParameter: { - number1: { name: 'number1', detail: 'first' }, - number2: { name: 'number2', detail: 'second' }, + number: { name: '数値', detail: '実数を指定します。' }, }, }, ATAN: { description: '数値のアークタンジェントを返します。', - abstract: '数値のアークタンジェントを返します。', + abstract: '数値のアークタンジェントを返します', links: [ { title: '指導', @@ -150,13 +148,12 @@ export default { }, ], functionParameter: { - number1: { name: 'number1', detail: 'first' }, - number2: { name: 'number2', detail: 'second' }, + number: { name: '数値', detail: '求める角度のタンジェントの値を指定します。' }, }, }, ATAN2: { description: '指定された x-y 座標のアークタンジェントを返します。', - abstract: '指定された x-y 座標のアークタンジェントを返します。', + abstract: '指定された x-y 座標のアークタンジェントを返します', links: [ { title: '指導', @@ -164,13 +161,13 @@ export default { }, ], functionParameter: { - number1: { name: 'number1', detail: 'first' }, - number2: { name: 'number2', detail: 'second' }, + xNum: { name: 'x 座標', detail: '点の x 座標を指定します。' }, + yNum: { name: 'y 座標', detail: '点の y 座標を指定します。' }, }, }, ATANH: { description: '数値の双曲線逆正接 (ハイパーボリック タンジェントの逆関数) を返します。', - abstract: '数値の双曲線逆正接 (ハイパーボリック タンジェントの逆関数) を返します。', + abstract: '数値の双曲線逆正接 (ハイパーボリック タンジェントの逆関数) を返します', links: [ { title: '指導', @@ -178,8 +175,7 @@ export default { }, ], functionParameter: { - number1: { name: 'number1', detail: 'first' }, - number2: { name: 'number2', detail: 'second' }, + number: { name: '数値', detail: '-1 より大きく 1 より小さい実数を指定します。' }, }, }, BASE: { @@ -268,7 +264,7 @@ export default { }, COS: { description: '指定された角度のコサインを返します。', - abstract: '指定された角度のコサインを返します。', + abstract: '指定された角度のコサインを返します', links: [ { title: '指導', @@ -276,8 +272,7 @@ export default { }, ], functionParameter: { - number1: { name: 'number1', detail: 'first' }, - number2: { name: 'number2', detail: 'second' }, + number: { name: '数値', detail: 'コサインを求める角度をラジアンで指定します。' }, }, }, COSH: { @@ -1133,7 +1128,7 @@ export default { }, TAN: { description: '指定された角度のタンジェントを返します。', - abstract: '指定された角度のタンジェントを返します。', + abstract: '指定された角度のタンジェントを返します', links: [ { title: '指導', @@ -1141,13 +1136,12 @@ export default { }, ], functionParameter: { - number1: { name: 'number1', detail: 'first' }, - number2: { name: 'number2', detail: 'second' }, + number: { name: '数値', detail: 'タンジェントを求める角度をラジアンを単位として指定します。' }, }, }, TANH: { description: '数値の双曲線正接 (ハイパーボリック タンジェント) を返します。', - abstract: '数値の双曲線正接 (ハイパーボリック タンジェント) を返します。', + abstract: '数値の双曲線正接 (ハイパーボリック タンジェント) を返します', links: [ { title: '指導', @@ -1155,8 +1149,7 @@ export default { }, ], functionParameter: { - number1: { name: 'number1', detail: 'first' }, - number2: { name: 'number2', detail: 'second' }, + number: { name: '数値', detail: '実数を指定します。' }, }, }, TRUNC: { diff --git a/packages/sheets-formula/src/locale/function-list/math/zh-CN.ts b/packages/sheets-formula/src/locale/function-list/math/zh-CN.ts index 6d1de0091d..62d8504224 100644 --- a/packages/sheets-formula/src/locale/function-list/math/zh-CN.ts +++ b/packages/sheets-formula/src/locale/function-list/math/zh-CN.ts @@ -112,7 +112,7 @@ export default { }, }, ASIN: { - description: '返回数字的反正弦值', + description: '返回数字的反正弦值。', abstract: '返回数字的反正弦值', links: [ { @@ -121,12 +121,11 @@ export default { }, ], functionParameter: { - number1: { name: 'number1', detail: 'first' }, - number2: { name: 'number2', detail: 'second' }, + number: { name: '数值', detail: ' 所求角度的正弦值,必须介于 -1 到 1 之间。' }, }, }, ASINH: { - description: '返回数字的反双曲正弦值', + description: '返回数字的反双曲正弦值。', abstract: '返回数字的反双曲正弦值', links: [ { @@ -135,12 +134,11 @@ export default { }, ], functionParameter: { - number1: { name: 'number1', detail: 'first' }, - number2: { name: 'number2', detail: 'second' }, + number: { name: '数值', detail: '任意实数。' }, }, }, ATAN: { - description: '返回数字的反正切值', + description: '返回数字的反正切值。', abstract: '返回数字的反正切值', links: [ { @@ -149,12 +147,11 @@ export default { }, ], functionParameter: { - number1: { name: 'number1', detail: 'first' }, - number2: { name: 'number2', detail: 'second' }, + number: { name: '数值', detail: '所求角度的正切值。' }, }, }, ATAN2: { - description: '返回 X 和 Y 坐标的反正切值', + description: '返回 X 和 Y 坐标的反正切值。', abstract: '返回 X 和 Y 坐标的反正切值', links: [ { @@ -163,12 +160,12 @@ export default { }, ], functionParameter: { - number1: { name: 'number1', detail: 'first' }, - number2: { name: 'number2', detail: 'second' }, + xNum: { name: 'x 坐标', detail: '点的 x 坐标。' }, + yNum: { name: 'y 坐标', detail: '点的 y 坐标。' }, }, }, ATANH: { - description: '返回数字的反双曲正切值', + description: '返回数字的反双曲正切值。', abstract: '返回数字的反双曲正切值', links: [ { @@ -177,8 +174,7 @@ export default { }, ], functionParameter: { - number1: { name: 'number1', detail: 'first' }, - number2: { name: 'number2', detail: 'second' }, + number: { name: '数值', detail: '-1 到 1 之间的任意实数。' }, }, }, BASE: { @@ -266,7 +262,7 @@ export default { }, }, COS: { - description: '返回数字的余弦值', + description: '返回数字的余弦值。', abstract: '返回数字的余弦值', links: [ { @@ -275,8 +271,7 @@ export default { }, ], functionParameter: { - number1: { name: 'number1', detail: 'first' }, - number2: { name: 'number2', detail: 'second' }, + number: { name: '数值', detail: '想要求余弦的角度,以弧度表示。' }, }, }, COSH: { @@ -1142,7 +1137,7 @@ export default { }, }, TAN: { - description: '返回数字的正切值', + description: '返回数字的正切值。', abstract: '返回数字的正切值', links: [ { @@ -1151,12 +1146,11 @@ export default { }, ], functionParameter: { - number1: { name: 'number1', detail: 'first' }, - number2: { name: 'number2', detail: 'second' }, + number: { name: '数值', detail: '要求正切的角度,以弧度表示。' }, }, }, TANH: { - description: '返回数字的双曲正切值', + description: '返回数字的双曲正切值。', abstract: '返回数字的双曲正切值', links: [ { @@ -1165,8 +1159,7 @@ export default { }, ], functionParameter: { - number1: { name: 'number1', detail: 'first' }, - number2: { name: 'number2', detail: 'second' }, + number: { name: '数值', detail: '任意实数。' }, }, }, TRUNC: { diff --git a/packages/sheets-formula/src/services/function-list/math.ts b/packages/sheets-formula/src/services/function-list/math.ts index 5a768acd3b..a0611d37f8 100644 --- a/packages/sheets-formula/src/services/function-list/math.ts +++ b/packages/sheets-formula/src/services/function-list/math.ts @@ -151,16 +151,9 @@ export const FUNCTION_LIST_MATH: IFunctionInfo[] = [ abstract: 'formula.functionList.ASIN.abstract', functionParameter: [ { - name: 'formula.functionList.ASIN.functionParameter.number1.name', - detail: 'formula.functionList.ASIN.functionParameter.number1.detail', - example: 'A1:A20', - require: 1, - repeat: 0, - }, - { - name: 'formula.functionList.ASIN.functionParameter.number2.name', - detail: 'formula.functionList.ASIN.functionParameter.number2.detail', - example: 'A1:A20', + name: 'formula.functionList.ASIN.functionParameter.number.name', + detail: 'formula.functionList.ASIN.functionParameter.number.detail', + example: '0', require: 1, repeat: 0, }, @@ -173,16 +166,9 @@ export const FUNCTION_LIST_MATH: IFunctionInfo[] = [ abstract: 'formula.functionList.ASINH.abstract', functionParameter: [ { - name: 'formula.functionList.ASINH.functionParameter.number1.name', - detail: 'formula.functionList.ASINH.functionParameter.number1.detail', - example: 'A1:A20', - require: 1, - repeat: 0, - }, - { - name: 'formula.functionList.ASINH.functionParameter.number2.name', - detail: 'formula.functionList.ASINH.functionParameter.number2.detail', - example: 'A1:A20', + name: 'formula.functionList.ASINH.functionParameter.number.name', + detail: 'formula.functionList.ASINH.functionParameter.number.detail', + example: '10', require: 1, repeat: 0, }, @@ -195,16 +181,9 @@ export const FUNCTION_LIST_MATH: IFunctionInfo[] = [ abstract: 'formula.functionList.ATAN.abstract', functionParameter: [ { - name: 'formula.functionList.ATAN.functionParameter.number1.name', - detail: 'formula.functionList.ATAN.functionParameter.number1.detail', - example: 'A1:A20', - require: 1, - repeat: 0, - }, - { - name: 'formula.functionList.ATAN.functionParameter.number2.name', - detail: 'formula.functionList.ATAN.functionParameter.number2.detail', - example: 'A1:A20', + name: 'formula.functionList.ATAN.functionParameter.number.name', + detail: 'formula.functionList.ATAN.functionParameter.number.detail', + example: '1', require: 1, repeat: 0, }, @@ -217,16 +196,16 @@ export const FUNCTION_LIST_MATH: IFunctionInfo[] = [ abstract: 'formula.functionList.ATAN2.abstract', functionParameter: [ { - name: 'formula.functionList.ATAN2.functionParameter.number1.name', - detail: 'formula.functionList.ATAN2.functionParameter.number1.detail', - example: 'A1:A20', + name: 'formula.functionList.ATAN2.functionParameter.xNum.name', + detail: 'formula.functionList.ATAN2.functionParameter.xNum.detail', + example: '4', require: 1, repeat: 0, }, { - name: 'formula.functionList.ATAN2.functionParameter.number2.name', - detail: 'formula.functionList.ATAN2.functionParameter.number2.detail', - example: 'A1:A20', + name: 'formula.functionList.ATAN2.functionParameter.yNum.name', + detail: 'formula.functionList.ATAN2.functionParameter.yNum.detail', + example: '3', require: 1, repeat: 0, }, @@ -239,16 +218,9 @@ export const FUNCTION_LIST_MATH: IFunctionInfo[] = [ abstract: 'formula.functionList.ATANH.abstract', functionParameter: [ { - name: 'formula.functionList.ATANH.functionParameter.number1.name', - detail: 'formula.functionList.ATANH.functionParameter.number1.detail', - example: 'A1:A20', - require: 1, - repeat: 0, - }, - { - name: 'formula.functionList.ATANH.functionParameter.number2.name', - detail: 'formula.functionList.ATANH.functionParameter.number2.detail', - example: 'A1:A20', + name: 'formula.functionList.ATANH.functionParameter.number.name', + detail: 'formula.functionList.ATANH.functionParameter.number.detail', + example: '0.1', require: 1, repeat: 0, }, @@ -393,16 +365,9 @@ export const FUNCTION_LIST_MATH: IFunctionInfo[] = [ abstract: 'formula.functionList.COS.abstract', functionParameter: [ { - name: 'formula.functionList.COS.functionParameter.number1.name', - detail: 'formula.functionList.COS.functionParameter.number1.detail', - example: 'A1:A20', - require: 1, - repeat: 0, - }, - { - name: 'formula.functionList.COS.functionParameter.number2.name', - detail: 'formula.functionList.COS.functionParameter.number2.detail', - example: 'A1:A20', + name: 'formula.functionList.COS.functionParameter.number.name', + detail: 'formula.functionList.COS.functionParameter.number.detail', + example: '1', require: 1, repeat: 0, }, @@ -1772,16 +1737,9 @@ export const FUNCTION_LIST_MATH: IFunctionInfo[] = [ abstract: 'formula.functionList.TAN.abstract', functionParameter: [ { - name: 'formula.functionList.TAN.functionParameter.number1.name', - detail: 'formula.functionList.TAN.functionParameter.number1.detail', - example: 'A1:A20', - require: 1, - repeat: 0, - }, - { - name: 'formula.functionList.TAN.functionParameter.number2.name', - detail: 'formula.functionList.TAN.functionParameter.number2.detail', - example: 'A1:A20', + name: 'formula.functionList.TAN.functionParameter.number.name', + detail: 'formula.functionList.TAN.functionParameter.number.detail', + example: '1', require: 1, repeat: 0, }, @@ -1794,16 +1752,9 @@ export const FUNCTION_LIST_MATH: IFunctionInfo[] = [ abstract: 'formula.functionList.TANH.abstract', functionParameter: [ { - name: 'formula.functionList.TANH.functionParameter.number1.name', - detail: 'formula.functionList.TANH.functionParameter.number1.detail', - example: 'A1:A20', - require: 1, - repeat: 0, - }, - { - name: 'formula.functionList.TANH.functionParameter.number2.name', - detail: 'formula.functionList.TANH.functionParameter.number2.detail', - example: 'A1:A20', + name: 'formula.functionList.TANH.functionParameter.number.name', + detail: 'formula.functionList.TANH.functionParameter.number.detail', + example: '1', require: 1, repeat: 0, }, diff --git a/packages/sheets/src/controllers/number-cell.controller.ts b/packages/sheets/src/controllers/number-cell.controller.ts new file mode 100644 index 0000000000..09f69e23df --- /dev/null +++ b/packages/sheets/src/controllers/number-cell.controller.ts @@ -0,0 +1,60 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CellValueType, Disposable, LifecycleStages, OnLifecycle } from '@univerjs/core'; +import { stripErrorMargin } from '@univerjs/engine-formula'; +import { Inject } from '@wendellhu/redi'; +import { SheetInterceptorService } from '../services/sheet-interceptor/sheet-interceptor.service'; +import { INTERCEPTOR_POINT } from '../services/sheet-interceptor/interceptor-const'; + +@OnLifecycle(LifecycleStages.Ready, NumberCellDisplayController) +export class NumberCellDisplayController extends Disposable { + constructor( + @Inject(SheetInterceptorService) private _sheetInterceptorService: SheetInterceptorService) { + super(); + + this._initialize(); + } + + private _initialize(): void { + this._initInterceptorCellContent(); + } + + private _initInterceptorCellContent() { + this.disposeWithMe( + this._sheetInterceptorService.intercept(INTERCEPTOR_POINT.CELL_CONTENT, { + priority: 11, + handler: (cell, location, next) => { + // Skip if the cell contains a numfmt pattern + const style = location.workbook.getStyles().getStyleByCell(cell); + if (style?.n?.pattern) { + return next({ ...cell }); + } + + // Dealing with precision issues + if (cell?.t === CellValueType.NUMBER && typeof cell?.v === 'number') { + return next({ + ...cell, + v: stripErrorMargin(cell.v), + }); + } + + return next({ ...cell }); + }, + }) + ); + } +} diff --git a/packages/sheets/src/sheets-plugin.ts b/packages/sheets/src/sheets-plugin.ts index 9570b063c7..6d0fadc19b 100644 --- a/packages/sheets/src/sheets-plugin.ts +++ b/packages/sheets/src/sheets-plugin.ts @@ -39,6 +39,7 @@ import { RangeProtectionRuleModel } from './model/range-protection-rule.model'; import { RangeProtectionRefRangeService } from './services/permission/range-permission/range-protection.ref-range'; import { RangeProtectionService } from './services/permission/range-permission/range-protection.service'; import { ONLY_REGISTER_FORMULA_RELATED_MUTATIONS_KEY } from './controllers/config'; +import { NumberCellDisplayController } from './controllers/number-cell.controller'; const PLUGIN_NAME = 'SHEET_PLUGIN'; @@ -96,6 +97,7 @@ export class UniverSheetsPlugin extends Plugin { // controllers [BasicWorksheetController], [MergeCellController], + [NumberCellDisplayController], [DefinedNameDataController], // permission