@cj-tech-master/excelts 9.2.1 → 9.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -2
- package/README_zh.md +29 -6
- package/dist/browser/index.browser.d.ts +1 -1
- package/dist/browser/index.browser.js +4 -0
- package/dist/browser/index.d.ts +1 -1
- package/dist/browser/index.js +4 -0
- package/dist/browser/modules/excel/cell.d.ts +17 -3
- package/dist/browser/modules/excel/cell.js +170 -22
- package/dist/browser/modules/excel/defined-names.d.ts +96 -1
- package/dist/browser/modules/excel/defined-names.js +411 -21
- package/dist/browser/modules/excel/image.d.ts +11 -0
- package/dist/browser/modules/excel/image.js +24 -1
- package/dist/browser/modules/excel/stream/workbook-reader.browser.d.ts +9 -3
- package/dist/browser/modules/excel/stream/workbook-reader.browser.js +14 -0
- package/dist/browser/modules/excel/stream/workbook-reader.d.ts +2 -1
- package/dist/browser/modules/excel/stream/workbook-writer.browser.d.ts +39 -5
- package/dist/browser/modules/excel/stream/workbook-writer.browser.js +48 -1
- package/dist/browser/modules/excel/stream/workbook-writer.d.ts +3 -2
- package/dist/browser/modules/excel/stream/worksheet-reader.js +17 -1
- package/dist/browser/modules/excel/stream/worksheet-writer.d.ts +39 -6
- package/dist/browser/modules/excel/stream/worksheet-writer.js +45 -5
- package/dist/browser/modules/excel/table.js +15 -2
- package/dist/browser/modules/excel/types.d.ts +133 -2
- package/dist/browser/modules/excel/utils/col-cache.d.ts +1 -0
- package/dist/browser/modules/excel/utils/col-cache.js +15 -0
- package/dist/browser/modules/excel/utils/drawing-utils.d.ts +3 -3
- package/dist/browser/modules/excel/utils/drawing-utils.js +4 -0
- package/dist/browser/modules/excel/utils/external-link-formula.d.ts +76 -0
- package/dist/browser/modules/excel/utils/external-link-formula.js +208 -0
- package/dist/browser/modules/excel/utils/iterate-stream.d.ts +9 -3
- package/dist/browser/modules/excel/utils/iterate-stream.js +3 -1
- package/dist/browser/modules/excel/utils/ooxml-paths.d.ts +19 -0
- package/dist/browser/modules/excel/utils/ooxml-paths.js +37 -2
- package/dist/browser/modules/excel/utils/shared-strings.d.ts +8 -3
- package/dist/browser/modules/excel/utils/shared-strings.js +21 -2
- package/dist/browser/modules/excel/utils/workbook-protection.d.ts +30 -0
- package/dist/browser/modules/excel/utils/workbook-protection.js +30 -0
- package/dist/browser/modules/excel/workbook.browser.d.ts +257 -6
- package/dist/browser/modules/excel/workbook.browser.js +318 -34
- package/dist/browser/modules/excel/workbook.d.ts +1 -1
- package/dist/browser/modules/excel/worksheet.d.ts +3 -1
- package/dist/browser/modules/excel/worksheet.js +21 -2
- package/dist/browser/modules/excel/xlsx/rel-type.d.ts +15 -0
- package/dist/browser/modules/excel/xlsx/rel-type.js +16 -1
- package/dist/browser/modules/excel/xlsx/xform/book/defined-name-xform.d.ts +6 -5
- package/dist/browser/modules/excel/xlsx/xform/book/defined-name-xform.js +21 -86
- package/dist/browser/modules/excel/xlsx/xform/book/external-link-xform.d.ts +84 -0
- package/dist/browser/modules/excel/xlsx/xform/book/external-link-xform.js +330 -0
- package/dist/browser/modules/excel/xlsx/xform/book/external-reference-xform.d.ts +17 -0
- package/dist/browser/modules/excel/xlsx/xform/book/external-reference-xform.js +24 -0
- package/dist/browser/modules/excel/xlsx/xform/book/workbook-calc-properties-xform.d.ts +3 -0
- package/dist/browser/modules/excel/xlsx/xform/book/workbook-calc-properties-xform.js +11 -2
- package/dist/browser/modules/excel/xlsx/xform/book/workbook-protection-xform.d.ts +20 -0
- package/dist/browser/modules/excel/xlsx/xform/book/workbook-protection-xform.js +66 -0
- package/dist/browser/modules/excel/xlsx/xform/book/workbook-xform.js +38 -5
- package/dist/browser/modules/excel/xlsx/xform/core/content-types-xform.js +19 -1
- package/dist/browser/modules/excel/xlsx/xform/core/metadata-xform.d.ts +56 -0
- package/dist/browser/modules/excel/xlsx/xform/core/metadata-xform.js +158 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.d.ts +26 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.js +105 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +3 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/drawing-xform.js +10 -2
- package/dist/browser/modules/excel/xlsx/xform/sheet/cell-xform.d.ts +1 -1
- package/dist/browser/modules/excel/xlsx/xform/sheet/cell-xform.js +166 -8
- package/dist/browser/modules/excel/xlsx/xform/sheet/data-validations-xform.js +1 -1
- package/dist/browser/modules/excel/xlsx/xform/sheet/ignored-errors-xform.d.ts +21 -0
- package/dist/browser/modules/excel/xlsx/xform/sheet/ignored-errors-xform.js +80 -0
- package/dist/browser/modules/excel/xlsx/xform/sheet/worksheet-xform.js +9 -4
- package/dist/browser/modules/excel/xlsx/xform/style/border-xform.js +4 -1
- package/dist/browser/modules/excel/xlsx/xlsx.browser.d.ts +172 -13
- package/dist/browser/modules/excel/xlsx/xlsx.browser.js +410 -20
- package/dist/browser/modules/excel/xlsx/xlsx.d.ts +7 -4
- package/dist/browser/modules/excel/xlsx/xlsx.js +4 -5
- package/dist/browser/modules/formula/compile/address-utils.d.ts +62 -0
- package/dist/browser/modules/formula/compile/address-utils.js +83 -0
- package/dist/browser/modules/formula/compile/binder.d.ts +42 -0
- package/dist/browser/modules/formula/compile/binder.js +487 -0
- package/dist/browser/modules/formula/compile/bound-ast.d.ts +230 -0
- package/dist/browser/modules/formula/compile/bound-ast.js +80 -0
- package/dist/browser/modules/formula/compile/compiled-formula.d.ts +137 -0
- package/dist/browser/modules/formula/compile/compiled-formula.js +383 -0
- package/dist/browser/modules/formula/compile/dependency-analysis.d.ts +93 -0
- package/dist/browser/modules/formula/compile/dependency-analysis.js +432 -0
- package/dist/browser/modules/formula/compile/structured-ref-utils.d.ts +93 -0
- package/dist/browser/modules/formula/compile/structured-ref-utils.js +136 -0
- package/dist/browser/modules/formula/default-syntax-probe.d.ts +79 -0
- package/dist/browser/modules/formula/default-syntax-probe.js +83 -0
- package/dist/browser/modules/formula/functions/_date-context.d.ts +4 -0
- package/dist/browser/modules/formula/functions/_date-context.js +29 -0
- package/dist/browser/modules/formula/functions/_shared.d.ts +121 -0
- package/dist/browser/modules/formula/functions/_shared.js +381 -0
- package/dist/browser/modules/formula/functions/conditional.d.ts +27 -0
- package/dist/browser/modules/formula/functions/conditional.js +343 -0
- package/dist/browser/modules/formula/functions/database.d.ts +37 -0
- package/dist/browser/modules/formula/functions/database.js +274 -0
- package/dist/browser/modules/formula/functions/date.d.ts +61 -0
- package/dist/browser/modules/formula/functions/date.js +855 -0
- package/dist/browser/modules/formula/functions/dynamic-array.d.ts +23 -0
- package/dist/browser/modules/formula/functions/dynamic-array.js +860 -0
- package/dist/browser/modules/formula/functions/engineering.d.ts +57 -0
- package/dist/browser/modules/formula/functions/engineering.js +1128 -0
- package/dist/browser/modules/formula/functions/financial.d.ts +202 -0
- package/dist/browser/modules/formula/functions/financial.js +2296 -0
- package/dist/browser/modules/formula/functions/lookup.d.ts +18 -0
- package/dist/browser/modules/formula/functions/lookup.js +886 -0
- package/dist/browser/modules/formula/functions/math.d.ts +114 -0
- package/dist/browser/modules/formula/functions/math.js +1406 -0
- package/dist/browser/modules/formula/functions/statistical.d.ts +193 -0
- package/dist/browser/modules/formula/functions/statistical.js +3390 -0
- package/dist/browser/modules/formula/functions/text.d.ts +86 -0
- package/dist/browser/modules/formula/functions/text.js +1845 -0
- package/dist/browser/modules/formula/host-registry.d.ts +53 -0
- package/dist/browser/modules/formula/host-registry.js +69 -0
- package/dist/browser/modules/formula/index.d.ts +39 -0
- package/dist/browser/modules/formula/index.js +49 -0
- package/dist/browser/modules/formula/install.d.ts +62 -0
- package/dist/browser/modules/formula/install.js +88 -0
- package/dist/browser/modules/formula/integration/apply-writeback-plan.d.ts +26 -0
- package/dist/browser/modules/formula/integration/apply-writeback-plan.js +210 -0
- package/dist/browser/modules/formula/integration/calculate-formulas-impl.d.ts +30 -0
- package/dist/browser/modules/formula/integration/calculate-formulas-impl.js +616 -0
- package/dist/browser/modules/formula/integration/calculate-formulas.d.ts +67 -0
- package/dist/browser/modules/formula/integration/calculate-formulas.js +68 -0
- package/dist/browser/modules/formula/integration/formula-instance.d.ts +64 -0
- package/dist/browser/modules/formula/integration/formula-instance.js +79 -0
- package/dist/browser/modules/formula/integration/workbook-adapter.d.ts +26 -0
- package/dist/browser/modules/formula/integration/workbook-adapter.js +324 -0
- package/dist/browser/modules/formula/integration/workbook-snapshot.d.ts +267 -0
- package/dist/browser/modules/formula/integration/workbook-snapshot.js +77 -0
- package/dist/browser/modules/formula/materialize/build-writeback-plan.d.ts +34 -0
- package/dist/browser/modules/formula/materialize/build-writeback-plan.js +473 -0
- package/dist/browser/modules/formula/materialize/spill-engine.d.ts +9 -0
- package/dist/browser/modules/formula/materialize/spill-engine.js +38 -0
- package/dist/browser/modules/formula/materialize/types.d.ts +179 -0
- package/dist/browser/modules/formula/materialize/types.js +29 -0
- package/dist/browser/modules/formula/materialize/writeback-plan.d.ts +167 -0
- package/dist/browser/modules/formula/materialize/writeback-plan.js +27 -0
- package/dist/browser/modules/formula/runtime/evaluator.d.ts +151 -0
- package/dist/browser/modules/formula/runtime/evaluator.js +2291 -0
- package/dist/browser/modules/formula/runtime/function-registry.d.ts +47 -0
- package/dist/browser/modules/formula/runtime/function-registry.js +840 -0
- package/dist/browser/modules/formula/runtime/values.d.ts +211 -0
- package/dist/browser/modules/formula/runtime/values.js +385 -0
- package/dist/browser/modules/formula/syntax/ast.d.ts +129 -0
- package/dist/browser/modules/formula/syntax/ast.js +28 -0
- package/dist/browser/modules/formula/syntax/parser.d.ts +18 -0
- package/dist/browser/modules/formula/syntax/parser.js +439 -0
- package/dist/browser/modules/formula/syntax/token-types.d.ts +153 -0
- package/dist/browser/modules/formula/syntax/token-types.js +59 -0
- package/dist/browser/modules/formula/syntax/tokenizer.d.ts +10 -0
- package/dist/browser/modules/formula/syntax/tokenizer.js +1074 -0
- package/dist/browser/modules/pdf/excel-bridge.js +9 -0
- package/dist/cjs/index.js +4 -0
- package/dist/cjs/modules/excel/cell.js +170 -22
- package/dist/cjs/modules/excel/defined-names.js +411 -21
- package/dist/cjs/modules/excel/image.js +24 -1
- package/dist/cjs/modules/excel/stream/workbook-reader.browser.js +14 -0
- package/dist/cjs/modules/excel/stream/workbook-writer.browser.js +48 -1
- package/dist/cjs/modules/excel/stream/worksheet-reader.js +17 -1
- package/dist/cjs/modules/excel/stream/worksheet-writer.js +45 -5
- package/dist/cjs/modules/excel/table.js +15 -2
- package/dist/cjs/modules/excel/utils/col-cache.js +15 -0
- package/dist/cjs/modules/excel/utils/drawing-utils.js +4 -0
- package/dist/cjs/modules/excel/utils/external-link-formula.js +212 -0
- package/dist/cjs/modules/excel/utils/iterate-stream.js +3 -1
- package/dist/cjs/modules/excel/utils/ooxml-paths.js +42 -2
- package/dist/cjs/modules/excel/utils/shared-strings.js +21 -2
- package/dist/cjs/modules/excel/utils/workbook-protection.js +33 -0
- package/dist/cjs/modules/excel/workbook.browser.js +318 -34
- package/dist/cjs/modules/excel/worksheet.js +20 -1
- package/dist/cjs/modules/excel/xlsx/rel-type.js +16 -1
- package/dist/cjs/modules/excel/xlsx/xform/book/defined-name-xform.js +21 -86
- package/dist/cjs/modules/excel/xlsx/xform/book/external-link-xform.js +333 -0
- package/dist/cjs/modules/excel/xlsx/xform/book/external-reference-xform.js +27 -0
- package/dist/cjs/modules/excel/xlsx/xform/book/workbook-calc-properties-xform.js +11 -2
- package/dist/cjs/modules/excel/xlsx/xform/book/workbook-protection-xform.js +69 -0
- package/dist/cjs/modules/excel/xlsx/xform/book/workbook-xform.js +38 -5
- package/dist/cjs/modules/excel/xlsx/xform/core/content-types-xform.js +18 -0
- package/dist/cjs/modules/excel/xlsx/xform/core/metadata-xform.js +161 -0
- package/dist/cjs/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.js +108 -0
- package/dist/cjs/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +3 -0
- package/dist/cjs/modules/excel/xlsx/xform/drawing/drawing-xform.js +10 -2
- package/dist/cjs/modules/excel/xlsx/xform/sheet/cell-xform.js +166 -8
- package/dist/cjs/modules/excel/xlsx/xform/sheet/data-validations-xform.js +1 -1
- package/dist/cjs/modules/excel/xlsx/xform/sheet/ignored-errors-xform.js +83 -0
- package/dist/cjs/modules/excel/xlsx/xform/sheet/worksheet-xform.js +9 -4
- package/dist/cjs/modules/excel/xlsx/xform/style/border-xform.js +4 -1
- package/dist/cjs/modules/excel/xlsx/xlsx.browser.js +408 -18
- package/dist/cjs/modules/excel/xlsx/xlsx.js +4 -5
- package/dist/cjs/modules/formula/compile/address-utils.js +89 -0
- package/dist/cjs/modules/formula/compile/binder.js +489 -0
- package/dist/cjs/modules/formula/compile/bound-ast.js +68 -0
- package/dist/cjs/modules/formula/compile/compiled-formula.js +387 -0
- package/dist/cjs/modules/formula/compile/dependency-analysis.js +437 -0
- package/dist/cjs/modules/formula/compile/structured-ref-utils.js +141 -0
- package/dist/cjs/modules/formula/default-syntax-probe.js +87 -0
- package/dist/cjs/modules/formula/functions/_date-context.js +33 -0
- package/dist/cjs/modules/formula/functions/_shared.js +396 -0
- package/dist/cjs/modules/formula/functions/conditional.js +354 -0
- package/dist/cjs/modules/formula/functions/database.js +288 -0
- package/dist/cjs/modules/formula/functions/date.js +883 -0
- package/dist/cjs/modules/formula/functions/dynamic-array.js +881 -0
- package/dist/cjs/modules/formula/functions/engineering.js +1183 -0
- package/dist/cjs/modules/formula/functions/financial.js +2348 -0
- package/dist/cjs/modules/formula/functions/lookup.js +902 -0
- package/dist/cjs/modules/formula/functions/math.js +1487 -0
- package/dist/cjs/modules/formula/functions/statistical.js +3488 -0
- package/dist/cjs/modules/formula/functions/text.js +1889 -0
- package/dist/cjs/modules/formula/host-registry.js +75 -0
- package/dist/cjs/modules/formula/index.js +58 -0
- package/dist/cjs/modules/formula/install.js +93 -0
- package/dist/cjs/modules/formula/integration/apply-writeback-plan.js +213 -0
- package/dist/cjs/modules/formula/integration/calculate-formulas-impl.js +619 -0
- package/dist/cjs/modules/formula/integration/calculate-formulas.js +71 -0
- package/dist/cjs/modules/formula/integration/formula-instance.js +82 -0
- package/dist/cjs/modules/formula/integration/workbook-adapter.js +327 -0
- package/dist/cjs/modules/formula/integration/workbook-snapshot.js +84 -0
- package/dist/cjs/modules/formula/materialize/build-writeback-plan.js +475 -0
- package/dist/cjs/modules/formula/materialize/spill-engine.js +42 -0
- package/dist/cjs/modules/formula/materialize/types.js +32 -0
- package/dist/cjs/modules/formula/materialize/writeback-plan.js +28 -0
- package/dist/cjs/modules/formula/runtime/evaluator.js +2298 -0
- package/dist/cjs/modules/formula/runtime/function-registry.js +846 -0
- package/dist/cjs/modules/formula/runtime/values.js +385 -0
- package/dist/cjs/modules/formula/syntax/ast.js +8 -0
- package/dist/cjs/modules/formula/syntax/parser.js +440 -0
- package/dist/cjs/modules/formula/syntax/token-types.js +32 -0
- package/dist/cjs/modules/formula/syntax/tokenizer.js +1076 -0
- package/dist/cjs/modules/pdf/excel-bridge.js +9 -0
- package/dist/esm/index.browser.js +4 -0
- package/dist/esm/index.js +4 -0
- package/dist/esm/modules/excel/cell.js +170 -22
- package/dist/esm/modules/excel/defined-names.js +411 -21
- package/dist/esm/modules/excel/image.js +24 -1
- package/dist/esm/modules/excel/stream/workbook-reader.browser.js +14 -0
- package/dist/esm/modules/excel/stream/workbook-writer.browser.js +48 -1
- package/dist/esm/modules/excel/stream/worksheet-reader.js +17 -1
- package/dist/esm/modules/excel/stream/worksheet-writer.js +45 -5
- package/dist/esm/modules/excel/table.js +15 -2
- package/dist/esm/modules/excel/utils/col-cache.js +15 -0
- package/dist/esm/modules/excel/utils/drawing-utils.js +4 -0
- package/dist/esm/modules/excel/utils/external-link-formula.js +208 -0
- package/dist/esm/modules/excel/utils/iterate-stream.js +3 -1
- package/dist/esm/modules/excel/utils/ooxml-paths.js +37 -2
- package/dist/esm/modules/excel/utils/shared-strings.js +21 -2
- package/dist/esm/modules/excel/utils/workbook-protection.js +30 -0
- package/dist/esm/modules/excel/workbook.browser.js +318 -34
- package/dist/esm/modules/excel/worksheet.js +21 -2
- package/dist/esm/modules/excel/xlsx/rel-type.js +16 -1
- package/dist/esm/modules/excel/xlsx/xform/book/defined-name-xform.js +21 -86
- package/dist/esm/modules/excel/xlsx/xform/book/external-link-xform.js +330 -0
- package/dist/esm/modules/excel/xlsx/xform/book/external-reference-xform.js +24 -0
- package/dist/esm/modules/excel/xlsx/xform/book/workbook-calc-properties-xform.js +11 -2
- package/dist/esm/modules/excel/xlsx/xform/book/workbook-protection-xform.js +66 -0
- package/dist/esm/modules/excel/xlsx/xform/book/workbook-xform.js +38 -5
- package/dist/esm/modules/excel/xlsx/xform/core/content-types-xform.js +19 -1
- package/dist/esm/modules/excel/xlsx/xform/core/metadata-xform.js +158 -0
- package/dist/esm/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.js +105 -0
- package/dist/esm/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +3 -0
- package/dist/esm/modules/excel/xlsx/xform/drawing/drawing-xform.js +10 -2
- package/dist/esm/modules/excel/xlsx/xform/sheet/cell-xform.js +166 -8
- package/dist/esm/modules/excel/xlsx/xform/sheet/data-validations-xform.js +1 -1
- package/dist/esm/modules/excel/xlsx/xform/sheet/ignored-errors-xform.js +80 -0
- package/dist/esm/modules/excel/xlsx/xform/sheet/worksheet-xform.js +9 -4
- package/dist/esm/modules/excel/xlsx/xform/style/border-xform.js +4 -1
- package/dist/esm/modules/excel/xlsx/xlsx.browser.js +410 -20
- package/dist/esm/modules/excel/xlsx/xlsx.js +4 -5
- package/dist/esm/modules/formula/compile/address-utils.js +83 -0
- package/dist/esm/modules/formula/compile/binder.js +487 -0
- package/dist/esm/modules/formula/compile/bound-ast.js +80 -0
- package/dist/esm/modules/formula/compile/compiled-formula.js +383 -0
- package/dist/esm/modules/formula/compile/dependency-analysis.js +432 -0
- package/dist/esm/modules/formula/compile/structured-ref-utils.js +136 -0
- package/dist/esm/modules/formula/default-syntax-probe.js +83 -0
- package/dist/esm/modules/formula/functions/_date-context.js +29 -0
- package/dist/esm/modules/formula/functions/_shared.js +381 -0
- package/dist/esm/modules/formula/functions/conditional.js +343 -0
- package/dist/esm/modules/formula/functions/database.js +274 -0
- package/dist/esm/modules/formula/functions/date.js +855 -0
- package/dist/esm/modules/formula/functions/dynamic-array.js +860 -0
- package/dist/esm/modules/formula/functions/engineering.js +1128 -0
- package/dist/esm/modules/formula/functions/financial.js +2296 -0
- package/dist/esm/modules/formula/functions/lookup.js +886 -0
- package/dist/esm/modules/formula/functions/math.js +1406 -0
- package/dist/esm/modules/formula/functions/statistical.js +3390 -0
- package/dist/esm/modules/formula/functions/text.js +1845 -0
- package/dist/esm/modules/formula/host-registry.js +69 -0
- package/dist/esm/modules/formula/index.js +49 -0
- package/dist/esm/modules/formula/install.js +88 -0
- package/dist/esm/modules/formula/integration/apply-writeback-plan.js +210 -0
- package/dist/esm/modules/formula/integration/calculate-formulas-impl.js +616 -0
- package/dist/esm/modules/formula/integration/calculate-formulas.js +68 -0
- package/dist/esm/modules/formula/integration/formula-instance.js +79 -0
- package/dist/esm/modules/formula/integration/workbook-adapter.js +324 -0
- package/dist/esm/modules/formula/integration/workbook-snapshot.js +77 -0
- package/dist/esm/modules/formula/materialize/build-writeback-plan.js +473 -0
- package/dist/esm/modules/formula/materialize/spill-engine.js +38 -0
- package/dist/esm/modules/formula/materialize/types.js +29 -0
- package/dist/esm/modules/formula/materialize/writeback-plan.js +27 -0
- package/dist/esm/modules/formula/runtime/evaluator.js +2291 -0
- package/dist/esm/modules/formula/runtime/function-registry.js +840 -0
- package/dist/esm/modules/formula/runtime/values.js +385 -0
- package/dist/esm/modules/formula/syntax/ast.js +28 -0
- package/dist/esm/modules/formula/syntax/parser.js +439 -0
- package/dist/esm/modules/formula/syntax/token-types.js +59 -0
- package/dist/esm/modules/formula/syntax/tokenizer.js +1074 -0
- package/dist/esm/modules/pdf/excel-bridge.js +9 -0
- package/dist/iife/excelts.iife.js +2302 -373
- package/dist/iife/excelts.iife.js.map +1 -1
- package/dist/iife/excelts.iife.min.js +34 -34
- package/dist/types/index.browser.d.ts +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/modules/excel/cell.d.ts +17 -3
- package/dist/types/modules/excel/defined-names.d.ts +96 -1
- package/dist/types/modules/excel/image.d.ts +11 -0
- package/dist/types/modules/excel/stream/workbook-reader.browser.d.ts +9 -3
- package/dist/types/modules/excel/stream/workbook-reader.d.ts +2 -1
- package/dist/types/modules/excel/stream/workbook-writer.browser.d.ts +39 -5
- package/dist/types/modules/excel/stream/workbook-writer.d.ts +3 -2
- package/dist/types/modules/excel/stream/worksheet-writer.d.ts +39 -6
- package/dist/types/modules/excel/types.d.ts +133 -2
- package/dist/types/modules/excel/utils/col-cache.d.ts +1 -0
- package/dist/types/modules/excel/utils/drawing-utils.d.ts +3 -3
- package/dist/types/modules/excel/utils/external-link-formula.d.ts +76 -0
- package/dist/types/modules/excel/utils/iterate-stream.d.ts +9 -3
- package/dist/types/modules/excel/utils/ooxml-paths.d.ts +19 -0
- package/dist/types/modules/excel/utils/shared-strings.d.ts +8 -3
- package/dist/types/modules/excel/utils/workbook-protection.d.ts +30 -0
- package/dist/types/modules/excel/workbook.browser.d.ts +257 -6
- package/dist/types/modules/excel/workbook.d.ts +1 -1
- package/dist/types/modules/excel/worksheet.d.ts +3 -1
- package/dist/types/modules/excel/xlsx/rel-type.d.ts +15 -0
- package/dist/types/modules/excel/xlsx/xform/book/defined-name-xform.d.ts +6 -5
- package/dist/types/modules/excel/xlsx/xform/book/external-link-xform.d.ts +84 -0
- package/dist/types/modules/excel/xlsx/xform/book/external-reference-xform.d.ts +17 -0
- package/dist/types/modules/excel/xlsx/xform/book/workbook-calc-properties-xform.d.ts +3 -0
- package/dist/types/modules/excel/xlsx/xform/book/workbook-protection-xform.d.ts +20 -0
- package/dist/types/modules/excel/xlsx/xform/core/metadata-xform.d.ts +56 -0
- package/dist/types/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.d.ts +26 -0
- package/dist/types/modules/excel/xlsx/xform/sheet/cell-xform.d.ts +1 -1
- package/dist/types/modules/excel/xlsx/xform/sheet/ignored-errors-xform.d.ts +21 -0
- package/dist/types/modules/excel/xlsx/xlsx.browser.d.ts +172 -13
- package/dist/types/modules/excel/xlsx/xlsx.d.ts +7 -4
- package/dist/types/modules/formula/compile/address-utils.d.ts +62 -0
- package/dist/types/modules/formula/compile/binder.d.ts +42 -0
- package/dist/types/modules/formula/compile/bound-ast.d.ts +230 -0
- package/dist/types/modules/formula/compile/compiled-formula.d.ts +137 -0
- package/dist/types/modules/formula/compile/dependency-analysis.d.ts +93 -0
- package/dist/types/modules/formula/compile/structured-ref-utils.d.ts +93 -0
- package/dist/types/modules/formula/default-syntax-probe.d.ts +79 -0
- package/dist/types/modules/formula/functions/_date-context.d.ts +4 -0
- package/dist/types/modules/formula/functions/_shared.d.ts +121 -0
- package/dist/types/modules/formula/functions/conditional.d.ts +27 -0
- package/dist/types/modules/formula/functions/database.d.ts +37 -0
- package/dist/types/modules/formula/functions/date.d.ts +61 -0
- package/dist/types/modules/formula/functions/dynamic-array.d.ts +23 -0
- package/dist/types/modules/formula/functions/engineering.d.ts +57 -0
- package/dist/types/modules/formula/functions/financial.d.ts +202 -0
- package/dist/types/modules/formula/functions/lookup.d.ts +18 -0
- package/dist/types/modules/formula/functions/math.d.ts +114 -0
- package/dist/types/modules/formula/functions/statistical.d.ts +193 -0
- package/dist/types/modules/formula/functions/text.d.ts +86 -0
- package/dist/types/modules/formula/host-registry.d.ts +53 -0
- package/dist/types/modules/formula/index.d.ts +39 -0
- package/dist/types/modules/formula/install.d.ts +62 -0
- package/dist/types/modules/formula/integration/apply-writeback-plan.d.ts +26 -0
- package/dist/types/modules/formula/integration/calculate-formulas-impl.d.ts +30 -0
- package/dist/types/modules/formula/integration/calculate-formulas.d.ts +67 -0
- package/dist/types/modules/formula/integration/formula-instance.d.ts +64 -0
- package/dist/types/modules/formula/integration/workbook-adapter.d.ts +26 -0
- package/dist/types/modules/formula/integration/workbook-snapshot.d.ts +267 -0
- package/dist/types/modules/formula/materialize/build-writeback-plan.d.ts +34 -0
- package/dist/types/modules/formula/materialize/spill-engine.d.ts +9 -0
- package/dist/types/modules/formula/materialize/types.d.ts +179 -0
- package/dist/types/modules/formula/materialize/writeback-plan.d.ts +167 -0
- package/dist/types/modules/formula/runtime/evaluator.d.ts +151 -0
- package/dist/types/modules/formula/runtime/function-registry.d.ts +47 -0
- package/dist/types/modules/formula/runtime/values.d.ts +211 -0
- package/dist/types/modules/formula/syntax/ast.d.ts +129 -0
- package/dist/types/modules/formula/syntax/parser.d.ts +18 -0
- package/dist/types/modules/formula/syntax/token-types.d.ts +153 -0
- package/dist/types/modules/formula/syntax/tokenizer.d.ts +10 -0
- package/package.json +28 -28
|
@@ -0,0 +1,1487 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Math / Aggregate Functions — Native RuntimeValue implementation.
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.fnTRUNC = exports.fnSIGN = exports.fnRANDBETWEEN = exports.fnRAND = exports.fnPI = exports.fnEXP = exports.fnLOG10 = exports.fnLOG = exports.fnLN = exports.fnSQRTPI = exports.fnSQRT = exports.fnROUNDUP = exports.fnROUNDDOWN = exports.fnROUND = exports.fnPOWER = exports.fnMOD = exports.fnINT = exports.fnFLOOR = exports.fnCEILING = exports.fnABS = exports.fnSUMPRODUCT = exports.fnPRODUCT = exports.fnCOUNTBLANK = exports.fnCOUNTA = exports.fnCOUNT = exports.fnMAX = exports.fnMIN = exports.fnAVERAGE = exports.fnSUM = exports.fnACOTH = exports.fnACOT = exports.fnCOTH = exports.fnCSCH = exports.fnSECH = exports.fnCOT = exports.fnCSC = exports.fnSEC = exports.fnATANH = exports.fnACOSH = exports.fnASINH = exports.fnTANH = exports.fnCOSH = exports.fnSINH = exports.fnATAN2 = exports.fnATAN = exports.fnACOS = exports.fnASIN = exports.fnTAN = exports.fnCOS = exports.fnSIN = void 0;
|
|
7
|
+
exports.fnSERIESSUM = exports.fnMUNIT = exports.fnMINVERSE = exports.fnMDETERM = exports.fnMMULT = exports.fnPERMUT = exports.fnCOMBINA = exports.fnCOMBIN = exports.fnFACTDOUBLE = exports.fnFACT = exports.fnMULTINOMIAL = exports.fnSUMXMY2 = exports.fnSUMX2PY2 = exports.fnSUMX2MY2 = exports.fnRADIANS = exports.fnDEGREES = exports.fnARABIC = exports.fnROMAN = exports.fnDECIMAL = exports.fnBASE = exports.fnQUOTIENT = exports.fnMROUND = exports.fnODD = exports.fnEVEN = exports.fnLCM = exports.fnGCD = exports.fnSUMSQ = void 0;
|
|
8
|
+
const values_1 = require("../runtime/values");
|
|
9
|
+
const _shared_1 = require("./_shared");
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// Internal Helpers
|
|
12
|
+
// ============================================================================
|
|
13
|
+
/**
|
|
14
|
+
* Apply a rounding operation using an integer factor, avoiding the
|
|
15
|
+
* floating-point drift that `Math.pow(10, d) / Math.pow(10, d)` introduces
|
|
16
|
+
* when `d` is negative (e.g. `1/0.1` is not exactly `10`).
|
|
17
|
+
*
|
|
18
|
+
* For `digits >= 0` we scale up by `10^digits`, round, and scale back down.
|
|
19
|
+
* For `digits < 0` we divide by `10^|digits|`, round, and multiply back up.
|
|
20
|
+
* In both branches the scaling factor is an integer, so only one rounding
|
|
21
|
+
* error is introduced.
|
|
22
|
+
*/
|
|
23
|
+
function applyRounding(value, digits, round) {
|
|
24
|
+
const d = Math.trunc(digits);
|
|
25
|
+
// Clamp digits to Excel's documented range [-127, 127]. Without this
|
|
26
|
+
// guard, extreme inputs blow `Math.pow(10, d)` up to Infinity; the
|
|
27
|
+
// resulting `round(value * Infinity) / Infinity` is NaN, which then
|
|
28
|
+
// leaks through the whole rounding family (ROUND / ROUNDDOWN /
|
|
29
|
+
// ROUNDUP / TRUNC / MROUND) and persists to the worksheet. Return
|
|
30
|
+
// `value` itself for well-behaved "nothing to do" edge cases (d very
|
|
31
|
+
// large is effectively "no rounding"; d very negative rounds to 0).
|
|
32
|
+
if (!Number.isFinite(value)) {
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
if (d >= 308) {
|
|
36
|
+
return value;
|
|
37
|
+
}
|
|
38
|
+
if (d <= -308) {
|
|
39
|
+
return round(0);
|
|
40
|
+
}
|
|
41
|
+
if (d >= 0) {
|
|
42
|
+
const factor = Math.pow(10, d);
|
|
43
|
+
if (!Number.isFinite(factor) || factor === 0) {
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
46
|
+
return round(value * factor) / factor;
|
|
47
|
+
}
|
|
48
|
+
const factor = Math.pow(10, -d);
|
|
49
|
+
if (!Number.isFinite(factor) || factor === 0) {
|
|
50
|
+
return value;
|
|
51
|
+
}
|
|
52
|
+
return round(value / factor) * factor;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Round half away from zero, matching Excel's ROUND semantics.
|
|
56
|
+
*
|
|
57
|
+
* JavaScript's `Math.round` rounds half toward +∞ (so `Math.round(-0.5)`
|
|
58
|
+
* returns `-0` instead of `-1`), whereas Excel rounds the magnitude and
|
|
59
|
+
* preserves the sign: `ROUND(-0.5, 0) = -1`. This helper implements the
|
|
60
|
+
* Excel rule by operating on the absolute value and restoring the sign.
|
|
61
|
+
*/
|
|
62
|
+
function roundHalfAwayFromZero(n) {
|
|
63
|
+
return n < 0 ? -Math.round(-n) : Math.round(n);
|
|
64
|
+
}
|
|
65
|
+
// ============================================================================
|
|
66
|
+
// Trigonometric Functions
|
|
67
|
+
// ============================================================================
|
|
68
|
+
const fnSIN = args => {
|
|
69
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
70
|
+
return (0, values_1.isError)(n) ? n : (0, values_1.rvNumber)(Math.sin(n.value));
|
|
71
|
+
};
|
|
72
|
+
exports.fnSIN = fnSIN;
|
|
73
|
+
const fnCOS = args => {
|
|
74
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
75
|
+
return (0, values_1.isError)(n) ? n : (0, values_1.rvNumber)(Math.cos(n.value));
|
|
76
|
+
};
|
|
77
|
+
exports.fnCOS = fnCOS;
|
|
78
|
+
const fnTAN = args => {
|
|
79
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
80
|
+
return (0, values_1.isError)(n) ? n : (0, values_1.rvNumber)(Math.tan(n.value));
|
|
81
|
+
};
|
|
82
|
+
exports.fnTAN = fnTAN;
|
|
83
|
+
const fnASIN = args => {
|
|
84
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
85
|
+
if ((0, values_1.isError)(n)) {
|
|
86
|
+
return n;
|
|
87
|
+
}
|
|
88
|
+
if (n.value < -1 || n.value > 1) {
|
|
89
|
+
return values_1.ERRORS.NUM;
|
|
90
|
+
}
|
|
91
|
+
return (0, values_1.rvNumber)(Math.asin(n.value));
|
|
92
|
+
};
|
|
93
|
+
exports.fnASIN = fnASIN;
|
|
94
|
+
const fnACOS = args => {
|
|
95
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
96
|
+
if ((0, values_1.isError)(n)) {
|
|
97
|
+
return n;
|
|
98
|
+
}
|
|
99
|
+
if (n.value < -1 || n.value > 1) {
|
|
100
|
+
return values_1.ERRORS.NUM;
|
|
101
|
+
}
|
|
102
|
+
return (0, values_1.rvNumber)(Math.acos(n.value));
|
|
103
|
+
};
|
|
104
|
+
exports.fnACOS = fnACOS;
|
|
105
|
+
const fnATAN = args => {
|
|
106
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
107
|
+
return (0, values_1.isError)(n) ? n : (0, values_1.rvNumber)(Math.atan(n.value));
|
|
108
|
+
};
|
|
109
|
+
exports.fnATAN = fnATAN;
|
|
110
|
+
const fnATAN2 = args => {
|
|
111
|
+
const x = (0, _shared_1.argToNumber)(args[0]);
|
|
112
|
+
if ((0, values_1.isError)(x)) {
|
|
113
|
+
return x;
|
|
114
|
+
}
|
|
115
|
+
const y = (0, _shared_1.argToNumber)(args[1]);
|
|
116
|
+
if ((0, values_1.isError)(y)) {
|
|
117
|
+
return y;
|
|
118
|
+
}
|
|
119
|
+
if (x.value === 0 && y.value === 0) {
|
|
120
|
+
return values_1.ERRORS.DIV0;
|
|
121
|
+
}
|
|
122
|
+
return (0, values_1.rvNumber)(Math.atan2(y.value, x.value));
|
|
123
|
+
};
|
|
124
|
+
exports.fnATAN2 = fnATAN2;
|
|
125
|
+
const fnSINH = args => {
|
|
126
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
127
|
+
if ((0, values_1.isError)(n)) {
|
|
128
|
+
return n;
|
|
129
|
+
}
|
|
130
|
+
// sinh(x) overflows double for |x| > ~710. Excel returns #NUM! rather
|
|
131
|
+
// than a silent Infinity (which would poison downstream arithmetic).
|
|
132
|
+
const r = Math.sinh(n.value);
|
|
133
|
+
return isFinite(r) ? (0, values_1.rvNumber)(r) : values_1.ERRORS.NUM;
|
|
134
|
+
};
|
|
135
|
+
exports.fnSINH = fnSINH;
|
|
136
|
+
const fnCOSH = args => {
|
|
137
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
138
|
+
if ((0, values_1.isError)(n)) {
|
|
139
|
+
return n;
|
|
140
|
+
}
|
|
141
|
+
const r = Math.cosh(n.value);
|
|
142
|
+
return isFinite(r) ? (0, values_1.rvNumber)(r) : values_1.ERRORS.NUM;
|
|
143
|
+
};
|
|
144
|
+
exports.fnCOSH = fnCOSH;
|
|
145
|
+
const fnTANH = args => {
|
|
146
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
147
|
+
return (0, values_1.isError)(n) ? n : (0, values_1.rvNumber)(Math.tanh(n.value));
|
|
148
|
+
};
|
|
149
|
+
exports.fnTANH = fnTANH;
|
|
150
|
+
const fnASINH = args => {
|
|
151
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
152
|
+
return (0, values_1.isError)(n) ? n : (0, values_1.rvNumber)(Math.asinh(n.value));
|
|
153
|
+
};
|
|
154
|
+
exports.fnASINH = fnASINH;
|
|
155
|
+
const fnACOSH = args => {
|
|
156
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
157
|
+
if ((0, values_1.isError)(n)) {
|
|
158
|
+
return n;
|
|
159
|
+
}
|
|
160
|
+
if (n.value < 1) {
|
|
161
|
+
return values_1.ERRORS.NUM;
|
|
162
|
+
}
|
|
163
|
+
return (0, values_1.rvNumber)(Math.acosh(n.value));
|
|
164
|
+
};
|
|
165
|
+
exports.fnACOSH = fnACOSH;
|
|
166
|
+
const fnATANH = args => {
|
|
167
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
168
|
+
if ((0, values_1.isError)(n)) {
|
|
169
|
+
return n;
|
|
170
|
+
}
|
|
171
|
+
if (n.value <= -1 || n.value >= 1) {
|
|
172
|
+
return values_1.ERRORS.NUM;
|
|
173
|
+
}
|
|
174
|
+
return (0, values_1.rvNumber)(Math.atanh(n.value));
|
|
175
|
+
};
|
|
176
|
+
exports.fnATANH = fnATANH;
|
|
177
|
+
/**
|
|
178
|
+
* Secondary trigonometric family (SEC / CSC / COT and hyperbolic /
|
|
179
|
+
* inverse variants). None of these exist on the JavaScript Math object
|
|
180
|
+
* so we derive them from the standard sin / cos / tan primitives, with
|
|
181
|
+
* explicit guards at the discontinuities (π/2 for SEC, multiples of π
|
|
182
|
+
* for CSC / COT, zero for the H variants).
|
|
183
|
+
*/
|
|
184
|
+
const fnSEC = args => {
|
|
185
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
186
|
+
if ((0, values_1.isError)(n)) {
|
|
187
|
+
return n;
|
|
188
|
+
}
|
|
189
|
+
const c = Math.cos(n.value);
|
|
190
|
+
return c === 0 ? values_1.ERRORS.DIV0 : (0, values_1.rvNumber)(1 / c);
|
|
191
|
+
};
|
|
192
|
+
exports.fnSEC = fnSEC;
|
|
193
|
+
const fnCSC = args => {
|
|
194
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
195
|
+
if ((0, values_1.isError)(n)) {
|
|
196
|
+
return n;
|
|
197
|
+
}
|
|
198
|
+
const s = Math.sin(n.value);
|
|
199
|
+
return s === 0 ? values_1.ERRORS.DIV0 : (0, values_1.rvNumber)(1 / s);
|
|
200
|
+
};
|
|
201
|
+
exports.fnCSC = fnCSC;
|
|
202
|
+
const fnCOT = args => {
|
|
203
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
204
|
+
if ((0, values_1.isError)(n)) {
|
|
205
|
+
return n;
|
|
206
|
+
}
|
|
207
|
+
const s = Math.sin(n.value);
|
|
208
|
+
if (s === 0) {
|
|
209
|
+
return values_1.ERRORS.DIV0;
|
|
210
|
+
}
|
|
211
|
+
return (0, values_1.rvNumber)(Math.cos(n.value) / s);
|
|
212
|
+
};
|
|
213
|
+
exports.fnCOT = fnCOT;
|
|
214
|
+
const fnSECH = args => {
|
|
215
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
216
|
+
if ((0, values_1.isError)(n)) {
|
|
217
|
+
return n;
|
|
218
|
+
}
|
|
219
|
+
// sech(x) = 1/cosh(x); cosh is never zero for real x, but it does
|
|
220
|
+
// overflow to Infinity for |x| > ~710 — return 0 (the mathematical
|
|
221
|
+
// limit) rather than dividing and producing NaN.
|
|
222
|
+
const c = Math.cosh(n.value);
|
|
223
|
+
return Number.isFinite(c) ? (0, values_1.rvNumber)(1 / c) : (0, values_1.rvNumber)(0);
|
|
224
|
+
};
|
|
225
|
+
exports.fnSECH = fnSECH;
|
|
226
|
+
const fnCSCH = args => {
|
|
227
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
228
|
+
if ((0, values_1.isError)(n)) {
|
|
229
|
+
return n;
|
|
230
|
+
}
|
|
231
|
+
if (n.value === 0) {
|
|
232
|
+
return values_1.ERRORS.DIV0;
|
|
233
|
+
}
|
|
234
|
+
const s = Math.sinh(n.value);
|
|
235
|
+
if (!Number.isFinite(s)) {
|
|
236
|
+
return (0, values_1.rvNumber)(0);
|
|
237
|
+
}
|
|
238
|
+
return (0, values_1.rvNumber)(1 / s);
|
|
239
|
+
};
|
|
240
|
+
exports.fnCSCH = fnCSCH;
|
|
241
|
+
const fnCOTH = args => {
|
|
242
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
243
|
+
if ((0, values_1.isError)(n)) {
|
|
244
|
+
return n;
|
|
245
|
+
}
|
|
246
|
+
if (n.value === 0) {
|
|
247
|
+
return values_1.ERRORS.DIV0;
|
|
248
|
+
}
|
|
249
|
+
return (0, values_1.rvNumber)(1 / Math.tanh(n.value));
|
|
250
|
+
};
|
|
251
|
+
exports.fnCOTH = fnCOTH;
|
|
252
|
+
const fnACOT = args => {
|
|
253
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
254
|
+
if ((0, values_1.isError)(n)) {
|
|
255
|
+
return n;
|
|
256
|
+
}
|
|
257
|
+
// Excel's ACOT returns values in (0, π), not (-π/2, π/2) like
|
|
258
|
+
// Math.atan. Map: ACOT(x) = π/2 − atan(x).
|
|
259
|
+
return (0, values_1.rvNumber)(Math.PI / 2 - Math.atan(n.value));
|
|
260
|
+
};
|
|
261
|
+
exports.fnACOT = fnACOT;
|
|
262
|
+
const fnACOTH = args => {
|
|
263
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
264
|
+
if ((0, values_1.isError)(n)) {
|
|
265
|
+
return n;
|
|
266
|
+
}
|
|
267
|
+
// Defined only for |x| > 1.
|
|
268
|
+
if (n.value >= -1 && n.value <= 1) {
|
|
269
|
+
return values_1.ERRORS.NUM;
|
|
270
|
+
}
|
|
271
|
+
return (0, values_1.rvNumber)(0.5 * Math.log((n.value + 1) / (n.value - 1)));
|
|
272
|
+
};
|
|
273
|
+
exports.fnACOTH = fnACOTH;
|
|
274
|
+
// ============================================================================
|
|
275
|
+
// Math / Aggregate Functions
|
|
276
|
+
// ============================================================================
|
|
277
|
+
const fnSUM = args => {
|
|
278
|
+
const nums = (0, _shared_1.flattenNumbers)(args);
|
|
279
|
+
const err = (0, _shared_1.firstError)(nums);
|
|
280
|
+
if (err) {
|
|
281
|
+
return err;
|
|
282
|
+
}
|
|
283
|
+
let sum = 0;
|
|
284
|
+
for (const n of nums) {
|
|
285
|
+
sum += n.value;
|
|
286
|
+
}
|
|
287
|
+
// Fail fast on overflow to Infinity; otherwise the result leaks into
|
|
288
|
+
// any formula that aggregates it (AVERAGE, STDEV, etc.) and those
|
|
289
|
+
// downstream callers would then fan #NUM! out across the graph.
|
|
290
|
+
return Number.isFinite(sum) ? (0, values_1.rvNumber)(sum) : values_1.ERRORS.NUM;
|
|
291
|
+
};
|
|
292
|
+
exports.fnSUM = fnSUM;
|
|
293
|
+
const fnAVERAGE = args => {
|
|
294
|
+
const nums = (0, _shared_1.flattenNumbers)(args);
|
|
295
|
+
const err = (0, _shared_1.firstError)(nums);
|
|
296
|
+
if (err) {
|
|
297
|
+
return err;
|
|
298
|
+
}
|
|
299
|
+
if (nums.length === 0) {
|
|
300
|
+
return values_1.ERRORS.DIV0;
|
|
301
|
+
}
|
|
302
|
+
let sum = 0;
|
|
303
|
+
for (const n of nums) {
|
|
304
|
+
sum += n.value;
|
|
305
|
+
}
|
|
306
|
+
const avg = sum / nums.length;
|
|
307
|
+
return Number.isFinite(avg) ? (0, values_1.rvNumber)(avg) : values_1.ERRORS.NUM;
|
|
308
|
+
};
|
|
309
|
+
exports.fnAVERAGE = fnAVERAGE;
|
|
310
|
+
const fnMIN = args => {
|
|
311
|
+
const nums = (0, _shared_1.flattenNumbers)(args);
|
|
312
|
+
const err = (0, _shared_1.firstError)(nums);
|
|
313
|
+
if (err) {
|
|
314
|
+
return err;
|
|
315
|
+
}
|
|
316
|
+
if (nums.length === 0) {
|
|
317
|
+
return (0, values_1.rvNumber)(0);
|
|
318
|
+
}
|
|
319
|
+
let min = Infinity;
|
|
320
|
+
for (const n of nums) {
|
|
321
|
+
if (n.value < min) {
|
|
322
|
+
min = n.value;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return (0, values_1.rvNumber)(min);
|
|
326
|
+
};
|
|
327
|
+
exports.fnMIN = fnMIN;
|
|
328
|
+
const fnMAX = args => {
|
|
329
|
+
const nums = (0, _shared_1.flattenNumbers)(args);
|
|
330
|
+
const err = (0, _shared_1.firstError)(nums);
|
|
331
|
+
if (err) {
|
|
332
|
+
return err;
|
|
333
|
+
}
|
|
334
|
+
if (nums.length === 0) {
|
|
335
|
+
return (0, values_1.rvNumber)(0);
|
|
336
|
+
}
|
|
337
|
+
let max = -Infinity;
|
|
338
|
+
for (const n of nums) {
|
|
339
|
+
if (n.value > max) {
|
|
340
|
+
max = n.value;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
return (0, values_1.rvNumber)(max);
|
|
344
|
+
};
|
|
345
|
+
exports.fnMAX = fnMAX;
|
|
346
|
+
const fnCOUNT = args => {
|
|
347
|
+
let count = 0;
|
|
348
|
+
const all = (0, _shared_1.flattenAll)(args);
|
|
349
|
+
for (const v of all) {
|
|
350
|
+
if (v.kind === 1 /* RVKind.Number */) {
|
|
351
|
+
count++;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
return (0, values_1.rvNumber)(count);
|
|
355
|
+
};
|
|
356
|
+
exports.fnCOUNT = fnCOUNT;
|
|
357
|
+
const fnCOUNTA = args => {
|
|
358
|
+
let count = 0;
|
|
359
|
+
const all = (0, _shared_1.flattenAll)(args);
|
|
360
|
+
for (const v of all) {
|
|
361
|
+
// Count everything that is not blank and not empty string
|
|
362
|
+
if (v.kind !== 0 /* RVKind.Blank */ && !(v.kind === 2 /* RVKind.String */ && v.value === "")) {
|
|
363
|
+
count++;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return (0, values_1.rvNumber)(count);
|
|
367
|
+
};
|
|
368
|
+
exports.fnCOUNTA = fnCOUNTA;
|
|
369
|
+
const fnCOUNTBLANK = args => {
|
|
370
|
+
let count = 0;
|
|
371
|
+
const all = (0, _shared_1.flattenAll)(args);
|
|
372
|
+
for (const v of all) {
|
|
373
|
+
if (v.kind === 0 /* RVKind.Blank */ || (v.kind === 2 /* RVKind.String */ && v.value === "")) {
|
|
374
|
+
count++;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
return (0, values_1.rvNumber)(count);
|
|
378
|
+
};
|
|
379
|
+
exports.fnCOUNTBLANK = fnCOUNTBLANK;
|
|
380
|
+
const fnPRODUCT = args => {
|
|
381
|
+
const nums = (0, _shared_1.flattenNumbers)(args);
|
|
382
|
+
const err = (0, _shared_1.firstError)(nums);
|
|
383
|
+
if (err) {
|
|
384
|
+
return err;
|
|
385
|
+
}
|
|
386
|
+
if (nums.length === 0) {
|
|
387
|
+
return (0, values_1.rvNumber)(0);
|
|
388
|
+
}
|
|
389
|
+
let product = 1;
|
|
390
|
+
for (const n of nums) {
|
|
391
|
+
product *= n.value;
|
|
392
|
+
}
|
|
393
|
+
// Excel surfaces an overflow as #NUM! rather than letting Infinity
|
|
394
|
+
// propagate into subsequent arithmetic.
|
|
395
|
+
return isFinite(product) ? (0, values_1.rvNumber)(product) : values_1.ERRORS.NUM;
|
|
396
|
+
};
|
|
397
|
+
exports.fnPRODUCT = fnPRODUCT;
|
|
398
|
+
const fnSUMPRODUCT = args => {
|
|
399
|
+
if (args.length === 0) {
|
|
400
|
+
return values_1.ERRORS.VALUE;
|
|
401
|
+
}
|
|
402
|
+
// Promote scalar args to 1x1 arrays. Excel allows a scalar (or 1x1 array)
|
|
403
|
+
// to broadcast to the surrounding array's shape, e.g. SUMPRODUCT(1, A1:A10)
|
|
404
|
+
// is equivalent to SUMPRODUCT(A1:A10). All non-broadcast arrays must share
|
|
405
|
+
// the same height/width — only 1x1 may be broadcast.
|
|
406
|
+
const arrays = [];
|
|
407
|
+
for (const a of args) {
|
|
408
|
+
if ((0, values_1.isArray)(a)) {
|
|
409
|
+
arrays.push(a);
|
|
410
|
+
}
|
|
411
|
+
else {
|
|
412
|
+
arrays.push((0, values_1.rvArray)([[(0, values_1.topLeft)(a)]]));
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
// Find the target dimensions: the max height/width across all non-1x1 arrays.
|
|
416
|
+
// 1x1 arrays are eligible to broadcast to whatever size is chosen.
|
|
417
|
+
let rows = 1;
|
|
418
|
+
let cols = 1;
|
|
419
|
+
for (const arr of arrays) {
|
|
420
|
+
if (arr.height !== 1 || arr.width !== 1) {
|
|
421
|
+
if (rows === 1 && cols === 1) {
|
|
422
|
+
rows = arr.height;
|
|
423
|
+
cols = arr.width;
|
|
424
|
+
}
|
|
425
|
+
else if (arr.height !== rows || arr.width !== cols) {
|
|
426
|
+
// Two different non-1x1 shapes — incompatible.
|
|
427
|
+
return values_1.ERRORS.VALUE;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
let sum = 0;
|
|
432
|
+
for (let r = 0; r < rows; r++) {
|
|
433
|
+
for (let c = 0; c < cols; c++) {
|
|
434
|
+
let product = 1;
|
|
435
|
+
for (const arr of arrays) {
|
|
436
|
+
// Broadcast 1x1 arrays to the target cell position.
|
|
437
|
+
const val = arr.height === 1 && arr.width === 1 ? arr.rows[0][0] : arr.rows[r][c];
|
|
438
|
+
if (val.kind === 4 /* RVKind.Error */) {
|
|
439
|
+
return val;
|
|
440
|
+
}
|
|
441
|
+
const n = val.kind === 1 /* RVKind.Number */
|
|
442
|
+
? val.value
|
|
443
|
+
: val.kind === 3 /* RVKind.Boolean */
|
|
444
|
+
? val.value
|
|
445
|
+
? 1
|
|
446
|
+
: 0
|
|
447
|
+
: 0;
|
|
448
|
+
product *= n;
|
|
449
|
+
}
|
|
450
|
+
sum += product;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
if (!Number.isFinite(sum)) {
|
|
454
|
+
return values_1.ERRORS.NUM;
|
|
455
|
+
}
|
|
456
|
+
return (0, values_1.rvNumber)(sum);
|
|
457
|
+
};
|
|
458
|
+
exports.fnSUMPRODUCT = fnSUMPRODUCT;
|
|
459
|
+
// ============================================================================
|
|
460
|
+
// Math Functions
|
|
461
|
+
// ============================================================================
|
|
462
|
+
const fnABS = args => {
|
|
463
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
464
|
+
return (0, values_1.isError)(n) ? n : (0, values_1.rvNumber)(Math.abs(n.value));
|
|
465
|
+
};
|
|
466
|
+
exports.fnABS = fnABS;
|
|
467
|
+
const fnCEILING = args => {
|
|
468
|
+
const num = (0, _shared_1.argToNumber)(args[0]);
|
|
469
|
+
if ((0, values_1.isError)(num)) {
|
|
470
|
+
return num;
|
|
471
|
+
}
|
|
472
|
+
const sigRV = args.length > 1 ? (0, _shared_1.argToNumber)(args[1]) : (0, values_1.rvNumber)(1);
|
|
473
|
+
if ((0, values_1.isError)(sigRV)) {
|
|
474
|
+
return sigRV;
|
|
475
|
+
}
|
|
476
|
+
const sig = sigRV.value;
|
|
477
|
+
if (sig === 0) {
|
|
478
|
+
return (0, values_1.rvNumber)(0);
|
|
479
|
+
}
|
|
480
|
+
// CEILING (the non-MATH variant) requires number and significance to share
|
|
481
|
+
// a sign. `CEILING(2, -1)` in Excel is #NUM!; only `CEILING.MATH` tolerates
|
|
482
|
+
// a negative significance with a positive number.
|
|
483
|
+
if (num.value !== 0 && Math.sign(num.value) !== Math.sign(sig)) {
|
|
484
|
+
return values_1.ERRORS.NUM;
|
|
485
|
+
}
|
|
486
|
+
return (0, values_1.rvNumber)(Math.ceil(num.value / sig) * sig);
|
|
487
|
+
};
|
|
488
|
+
exports.fnCEILING = fnCEILING;
|
|
489
|
+
const fnFLOOR = args => {
|
|
490
|
+
const num = (0, _shared_1.argToNumber)(args[0]);
|
|
491
|
+
if ((0, values_1.isError)(num)) {
|
|
492
|
+
return num;
|
|
493
|
+
}
|
|
494
|
+
const sigRV = args.length > 1 ? (0, _shared_1.argToNumber)(args[1]) : (0, values_1.rvNumber)(1);
|
|
495
|
+
if ((0, values_1.isError)(sigRV)) {
|
|
496
|
+
return sigRV;
|
|
497
|
+
}
|
|
498
|
+
const sig = sigRV.value;
|
|
499
|
+
if (sig === 0) {
|
|
500
|
+
return values_1.ERRORS.DIV0;
|
|
501
|
+
}
|
|
502
|
+
if (num.value !== 0 && Math.sign(num.value) !== Math.sign(sig)) {
|
|
503
|
+
return values_1.ERRORS.NUM;
|
|
504
|
+
}
|
|
505
|
+
return (0, values_1.rvNumber)(Math.floor(num.value / sig) * sig);
|
|
506
|
+
};
|
|
507
|
+
exports.fnFLOOR = fnFLOOR;
|
|
508
|
+
const fnINT = args => {
|
|
509
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
510
|
+
return (0, values_1.isError)(n) ? n : (0, values_1.rvNumber)(Math.floor(n.value));
|
|
511
|
+
};
|
|
512
|
+
exports.fnINT = fnINT;
|
|
513
|
+
const fnMOD = args => {
|
|
514
|
+
const num = (0, _shared_1.argToNumber)(args[0]);
|
|
515
|
+
if ((0, values_1.isError)(num)) {
|
|
516
|
+
return num;
|
|
517
|
+
}
|
|
518
|
+
const div = (0, _shared_1.argToNumber)(args[1]);
|
|
519
|
+
if ((0, values_1.isError)(div)) {
|
|
520
|
+
return div;
|
|
521
|
+
}
|
|
522
|
+
if (div.value === 0) {
|
|
523
|
+
return values_1.ERRORS.DIV0;
|
|
524
|
+
}
|
|
525
|
+
return (0, values_1.rvNumber)(num.value - div.value * Math.floor(num.value / div.value));
|
|
526
|
+
};
|
|
527
|
+
exports.fnMOD = fnMOD;
|
|
528
|
+
const fnPOWER = args => {
|
|
529
|
+
const base = (0, _shared_1.argToNumber)(args[0]);
|
|
530
|
+
if ((0, values_1.isError)(base)) {
|
|
531
|
+
return base;
|
|
532
|
+
}
|
|
533
|
+
const exp = (0, _shared_1.argToNumber)(args[1]);
|
|
534
|
+
if ((0, values_1.isError)(exp)) {
|
|
535
|
+
return exp;
|
|
536
|
+
}
|
|
537
|
+
// Distinguish the two degenerate-base cases Excel handles separately:
|
|
538
|
+
// POWER(0, 0) → 1 (by convention, matches Excel)
|
|
539
|
+
// POWER(0, <0) → #DIV/0!
|
|
540
|
+
// POWER(<0, non-int) → #NUM! (complex result; Math.pow returns NaN)
|
|
541
|
+
if (base.value === 0) {
|
|
542
|
+
if (exp.value < 0) {
|
|
543
|
+
return values_1.ERRORS.DIV0;
|
|
544
|
+
}
|
|
545
|
+
if (exp.value === 0) {
|
|
546
|
+
return (0, values_1.rvNumber)(1);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
const result = Math.pow(base.value, exp.value);
|
|
550
|
+
if (Number.isNaN(result)) {
|
|
551
|
+
return values_1.ERRORS.NUM;
|
|
552
|
+
}
|
|
553
|
+
return !isFinite(result) ? values_1.ERRORS.NUM : (0, values_1.rvNumber)(result);
|
|
554
|
+
};
|
|
555
|
+
exports.fnPOWER = fnPOWER;
|
|
556
|
+
const fnROUND = args => {
|
|
557
|
+
const num = (0, _shared_1.argToNumber)(args[0]);
|
|
558
|
+
if ((0, values_1.isError)(num)) {
|
|
559
|
+
return num;
|
|
560
|
+
}
|
|
561
|
+
const digitsRV = args.length > 1 ? (0, _shared_1.argToNumber)(args[1]) : (0, values_1.rvNumber)(0);
|
|
562
|
+
if ((0, values_1.isError)(digitsRV)) {
|
|
563
|
+
return digitsRV;
|
|
564
|
+
}
|
|
565
|
+
return (0, values_1.rvNumber)(applyRounding(num.value, digitsRV.value, roundHalfAwayFromZero));
|
|
566
|
+
};
|
|
567
|
+
exports.fnROUND = fnROUND;
|
|
568
|
+
const fnROUNDDOWN = args => {
|
|
569
|
+
const num = (0, _shared_1.argToNumber)(args[0]);
|
|
570
|
+
if ((0, values_1.isError)(num)) {
|
|
571
|
+
return num;
|
|
572
|
+
}
|
|
573
|
+
const digitsRV = args.length > 1 ? (0, _shared_1.argToNumber)(args[1]) : (0, values_1.rvNumber)(0);
|
|
574
|
+
if ((0, values_1.isError)(digitsRV)) {
|
|
575
|
+
return digitsRV;
|
|
576
|
+
}
|
|
577
|
+
return (0, values_1.rvNumber)(applyRounding(num.value, digitsRV.value, Math.trunc));
|
|
578
|
+
};
|
|
579
|
+
exports.fnROUNDDOWN = fnROUNDDOWN;
|
|
580
|
+
const fnROUNDUP = args => {
|
|
581
|
+
const num = (0, _shared_1.argToNumber)(args[0]);
|
|
582
|
+
if ((0, values_1.isError)(num)) {
|
|
583
|
+
return num;
|
|
584
|
+
}
|
|
585
|
+
const digitsRV = args.length > 1 ? (0, _shared_1.argToNumber)(args[1]) : (0, values_1.rvNumber)(0);
|
|
586
|
+
if ((0, values_1.isError)(digitsRV)) {
|
|
587
|
+
return digitsRV;
|
|
588
|
+
}
|
|
589
|
+
// ROUNDUP rounds away from zero for the fractional part at the requested
|
|
590
|
+
// precision. We emulate this by ceiling the scaled absolute value and
|
|
591
|
+
// restoring the sign.
|
|
592
|
+
const sign = num.value >= 0 ? 1 : -1;
|
|
593
|
+
const rounded = applyRounding(Math.abs(num.value), digitsRV.value, Math.ceil);
|
|
594
|
+
return (0, values_1.rvNumber)(sign * rounded);
|
|
595
|
+
};
|
|
596
|
+
exports.fnROUNDUP = fnROUNDUP;
|
|
597
|
+
const fnSQRT = args => {
|
|
598
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
599
|
+
if ((0, values_1.isError)(n)) {
|
|
600
|
+
return n;
|
|
601
|
+
}
|
|
602
|
+
if (n.value < 0) {
|
|
603
|
+
return values_1.ERRORS.NUM;
|
|
604
|
+
}
|
|
605
|
+
return (0, values_1.rvNumber)(Math.sqrt(n.value));
|
|
606
|
+
};
|
|
607
|
+
exports.fnSQRT = fnSQRT;
|
|
608
|
+
/**
|
|
609
|
+
* SQRTPI(number) — returns the square root of (number × π). Useful in
|
|
610
|
+
* statistical formulas and Gauss integrals.
|
|
611
|
+
*/
|
|
612
|
+
const fnSQRTPI = args => {
|
|
613
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
614
|
+
if ((0, values_1.isError)(n)) {
|
|
615
|
+
return n;
|
|
616
|
+
}
|
|
617
|
+
if (n.value < 0) {
|
|
618
|
+
return values_1.ERRORS.NUM;
|
|
619
|
+
}
|
|
620
|
+
return (0, values_1.rvNumber)(Math.sqrt(n.value * Math.PI));
|
|
621
|
+
};
|
|
622
|
+
exports.fnSQRTPI = fnSQRTPI;
|
|
623
|
+
const fnLN = args => {
|
|
624
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
625
|
+
if ((0, values_1.isError)(n)) {
|
|
626
|
+
return n;
|
|
627
|
+
}
|
|
628
|
+
if (n.value <= 0) {
|
|
629
|
+
return values_1.ERRORS.NUM;
|
|
630
|
+
}
|
|
631
|
+
return (0, values_1.rvNumber)(Math.log(n.value));
|
|
632
|
+
};
|
|
633
|
+
exports.fnLN = fnLN;
|
|
634
|
+
const fnLOG = args => {
|
|
635
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
636
|
+
if ((0, values_1.isError)(n)) {
|
|
637
|
+
return n;
|
|
638
|
+
}
|
|
639
|
+
if (n.value <= 0) {
|
|
640
|
+
return values_1.ERRORS.NUM;
|
|
641
|
+
}
|
|
642
|
+
const baseRV = args.length > 1 ? (0, _shared_1.argToNumber)(args[1]) : (0, values_1.rvNumber)(10);
|
|
643
|
+
if ((0, values_1.isError)(baseRV)) {
|
|
644
|
+
return baseRV;
|
|
645
|
+
}
|
|
646
|
+
if (baseRV.value <= 0 || baseRV.value === 1) {
|
|
647
|
+
return values_1.ERRORS.NUM;
|
|
648
|
+
}
|
|
649
|
+
return (0, values_1.rvNumber)(Math.log(n.value) / Math.log(baseRV.value));
|
|
650
|
+
};
|
|
651
|
+
exports.fnLOG = fnLOG;
|
|
652
|
+
const fnLOG10 = args => {
|
|
653
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
654
|
+
if ((0, values_1.isError)(n)) {
|
|
655
|
+
return n;
|
|
656
|
+
}
|
|
657
|
+
if (n.value <= 0) {
|
|
658
|
+
return values_1.ERRORS.NUM;
|
|
659
|
+
}
|
|
660
|
+
return (0, values_1.rvNumber)(Math.log10(n.value));
|
|
661
|
+
};
|
|
662
|
+
exports.fnLOG10 = fnLOG10;
|
|
663
|
+
const fnEXP = args => {
|
|
664
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
665
|
+
if ((0, values_1.isError)(n)) {
|
|
666
|
+
return n;
|
|
667
|
+
}
|
|
668
|
+
// EXP(~710) overflows double to Infinity. Excel returns #NUM! in that
|
|
669
|
+
// regime rather than letting the non-finite result propagate.
|
|
670
|
+
const r = Math.exp(n.value);
|
|
671
|
+
return isFinite(r) ? (0, values_1.rvNumber)(r) : values_1.ERRORS.NUM;
|
|
672
|
+
};
|
|
673
|
+
exports.fnEXP = fnEXP;
|
|
674
|
+
const fnPI = () => (0, values_1.rvNumber)(Math.PI);
|
|
675
|
+
exports.fnPI = fnPI;
|
|
676
|
+
const fnRAND = () => (0, values_1.rvNumber)(Math.random());
|
|
677
|
+
exports.fnRAND = fnRAND;
|
|
678
|
+
const fnRANDBETWEEN = args => {
|
|
679
|
+
const bottom = (0, _shared_1.argToNumber)(args[0]);
|
|
680
|
+
if ((0, values_1.isError)(bottom)) {
|
|
681
|
+
return bottom;
|
|
682
|
+
}
|
|
683
|
+
const top = (0, _shared_1.argToNumber)(args[1]);
|
|
684
|
+
if ((0, values_1.isError)(top)) {
|
|
685
|
+
return top;
|
|
686
|
+
}
|
|
687
|
+
const lo = Math.ceil(bottom.value);
|
|
688
|
+
const hi = Math.floor(top.value);
|
|
689
|
+
// Excel returns #NUM! when bottom > top; otherwise the formula below would
|
|
690
|
+
// produce a garbage integer from a negative range.
|
|
691
|
+
if (lo > hi) {
|
|
692
|
+
return values_1.ERRORS.NUM;
|
|
693
|
+
}
|
|
694
|
+
return (0, values_1.rvNumber)(Math.floor(Math.random() * (hi - lo + 1)) + lo);
|
|
695
|
+
};
|
|
696
|
+
exports.fnRANDBETWEEN = fnRANDBETWEEN;
|
|
697
|
+
const fnSIGN = args => {
|
|
698
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
699
|
+
if ((0, values_1.isError)(n)) {
|
|
700
|
+
return n;
|
|
701
|
+
}
|
|
702
|
+
// `Math.sign(-0)` returns `-0` (preserving IEEE-754 sign bit). Excel's
|
|
703
|
+
// SIGN normalises zero to +0 (since the documented result for a zero
|
|
704
|
+
// input is 0, not distinguishing signed zero). The `|| 0` collapses
|
|
705
|
+
// both ±0 into `+0` while leaving ±1 untouched.
|
|
706
|
+
return (0, values_1.rvNumber)(Math.sign(n.value) || 0);
|
|
707
|
+
};
|
|
708
|
+
exports.fnSIGN = fnSIGN;
|
|
709
|
+
// ============================================================================
|
|
710
|
+
// Additional Math Functions
|
|
711
|
+
// ============================================================================
|
|
712
|
+
const fnTRUNC = args => {
|
|
713
|
+
const num = (0, _shared_1.argToNumber)(args[0]);
|
|
714
|
+
if ((0, values_1.isError)(num)) {
|
|
715
|
+
return num;
|
|
716
|
+
}
|
|
717
|
+
const digitsRV = args.length > 1 ? (0, _shared_1.argToNumber)(args[1]) : (0, values_1.rvNumber)(0);
|
|
718
|
+
if ((0, values_1.isError)(digitsRV)) {
|
|
719
|
+
return digitsRV;
|
|
720
|
+
}
|
|
721
|
+
return (0, values_1.rvNumber)(applyRounding(num.value, digitsRV.value, Math.trunc));
|
|
722
|
+
};
|
|
723
|
+
exports.fnTRUNC = fnTRUNC;
|
|
724
|
+
const fnSUMSQ = args => {
|
|
725
|
+
const nums = (0, _shared_1.flattenNumbers)(args);
|
|
726
|
+
const err = (0, _shared_1.firstError)(nums);
|
|
727
|
+
if (err) {
|
|
728
|
+
return err;
|
|
729
|
+
}
|
|
730
|
+
let sum = 0;
|
|
731
|
+
for (const n of nums) {
|
|
732
|
+
sum += n.value ** 2;
|
|
733
|
+
}
|
|
734
|
+
return isFinite(sum) ? (0, values_1.rvNumber)(sum) : values_1.ERRORS.NUM;
|
|
735
|
+
};
|
|
736
|
+
exports.fnSUMSQ = fnSUMSQ;
|
|
737
|
+
const fnGCD = args => {
|
|
738
|
+
const nums = (0, _shared_1.flattenNumbers)(args);
|
|
739
|
+
const err = (0, _shared_1.firstError)(nums);
|
|
740
|
+
if (err) {
|
|
741
|
+
return err;
|
|
742
|
+
}
|
|
743
|
+
if (nums.length === 0) {
|
|
744
|
+
return (0, values_1.rvNumber)(0);
|
|
745
|
+
}
|
|
746
|
+
// Excel rejects any negative argument with #NUM!; truncate toward zero
|
|
747
|
+
// for non-integer positives (previous `Math.floor(-5.5) = -6` then
|
|
748
|
+
// `Math.abs` produced 6 instead of #NUM!).
|
|
749
|
+
const coerce = (v) => {
|
|
750
|
+
if (v < 0) {
|
|
751
|
+
return values_1.ERRORS.NUM;
|
|
752
|
+
}
|
|
753
|
+
return Math.trunc(v);
|
|
754
|
+
};
|
|
755
|
+
const first = coerce(nums[0].value);
|
|
756
|
+
if (typeof first !== "number") {
|
|
757
|
+
return first;
|
|
758
|
+
}
|
|
759
|
+
let result = first;
|
|
760
|
+
for (let i = 1; i < nums.length; i++) {
|
|
761
|
+
const bi = coerce(nums[i].value);
|
|
762
|
+
if (typeof bi !== "number") {
|
|
763
|
+
return bi;
|
|
764
|
+
}
|
|
765
|
+
let b = bi;
|
|
766
|
+
while (b) {
|
|
767
|
+
const t = b;
|
|
768
|
+
b = result % b;
|
|
769
|
+
result = t;
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
return (0, values_1.rvNumber)(result);
|
|
773
|
+
};
|
|
774
|
+
exports.fnGCD = fnGCD;
|
|
775
|
+
const fnLCM = args => {
|
|
776
|
+
const nums = (0, _shared_1.flattenNumbers)(args);
|
|
777
|
+
const err = (0, _shared_1.firstError)(nums);
|
|
778
|
+
if (err) {
|
|
779
|
+
return err;
|
|
780
|
+
}
|
|
781
|
+
if (nums.length === 0) {
|
|
782
|
+
return (0, values_1.rvNumber)(0);
|
|
783
|
+
}
|
|
784
|
+
const coerce = (v) => {
|
|
785
|
+
if (v < 0) {
|
|
786
|
+
return values_1.ERRORS.NUM;
|
|
787
|
+
}
|
|
788
|
+
return Math.trunc(v);
|
|
789
|
+
};
|
|
790
|
+
const first = coerce(nums[0].value);
|
|
791
|
+
if (typeof first !== "number") {
|
|
792
|
+
return first;
|
|
793
|
+
}
|
|
794
|
+
let result = first;
|
|
795
|
+
for (let i = 1; i < nums.length; i++) {
|
|
796
|
+
const bi = coerce(nums[i].value);
|
|
797
|
+
if (typeof bi !== "number") {
|
|
798
|
+
return bi;
|
|
799
|
+
}
|
|
800
|
+
const b = bi;
|
|
801
|
+
if (result === 0 && b === 0) {
|
|
802
|
+
result = 0;
|
|
803
|
+
}
|
|
804
|
+
else {
|
|
805
|
+
let g = result;
|
|
806
|
+
let t = b;
|
|
807
|
+
while (t) {
|
|
808
|
+
const tmp = t;
|
|
809
|
+
t = g % t;
|
|
810
|
+
g = tmp;
|
|
811
|
+
}
|
|
812
|
+
result = (result * b) / g;
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
return (0, values_1.rvNumber)(result);
|
|
816
|
+
};
|
|
817
|
+
exports.fnLCM = fnLCM;
|
|
818
|
+
// ============================================================================
|
|
819
|
+
// More Math Functions
|
|
820
|
+
// ============================================================================
|
|
821
|
+
const fnEVEN = args => {
|
|
822
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
823
|
+
if ((0, values_1.isError)(n)) {
|
|
824
|
+
return n;
|
|
825
|
+
}
|
|
826
|
+
const sign = n.value >= 0 ? 1 : -1;
|
|
827
|
+
const abs = Math.abs(n.value);
|
|
828
|
+
const ceil = Math.ceil(abs);
|
|
829
|
+
return (0, values_1.rvNumber)(sign * (ceil % 2 === 0 ? ceil : ceil + 1));
|
|
830
|
+
};
|
|
831
|
+
exports.fnEVEN = fnEVEN;
|
|
832
|
+
const fnODD = args => {
|
|
833
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
834
|
+
if ((0, values_1.isError)(n)) {
|
|
835
|
+
return n;
|
|
836
|
+
}
|
|
837
|
+
if (n.value === 0) {
|
|
838
|
+
return (0, values_1.rvNumber)(1);
|
|
839
|
+
}
|
|
840
|
+
const sign = n.value >= 0 ? 1 : -1;
|
|
841
|
+
const abs = Math.abs(n.value);
|
|
842
|
+
const ceil = Math.ceil(abs);
|
|
843
|
+
return (0, values_1.rvNumber)(sign * (ceil % 2 === 1 ? ceil : ceil + 1));
|
|
844
|
+
};
|
|
845
|
+
exports.fnODD = fnODD;
|
|
846
|
+
const fnMROUND = args => {
|
|
847
|
+
const num = (0, _shared_1.argToNumber)(args[0]);
|
|
848
|
+
if ((0, values_1.isError)(num)) {
|
|
849
|
+
return num;
|
|
850
|
+
}
|
|
851
|
+
const multiple = (0, _shared_1.argToNumber)(args[1]);
|
|
852
|
+
if ((0, values_1.isError)(multiple)) {
|
|
853
|
+
return multiple;
|
|
854
|
+
}
|
|
855
|
+
if (multiple.value === 0) {
|
|
856
|
+
return (0, values_1.rvNumber)(0);
|
|
857
|
+
}
|
|
858
|
+
if ((num.value > 0 && multiple.value < 0) || (num.value < 0 && multiple.value > 0)) {
|
|
859
|
+
return values_1.ERRORS.NUM;
|
|
860
|
+
}
|
|
861
|
+
return (0, values_1.rvNumber)(roundHalfAwayFromZero(num.value / multiple.value) * multiple.value);
|
|
862
|
+
};
|
|
863
|
+
exports.fnMROUND = fnMROUND;
|
|
864
|
+
const fnQUOTIENT = args => {
|
|
865
|
+
const num = (0, _shared_1.argToNumber)(args[0]);
|
|
866
|
+
if ((0, values_1.isError)(num)) {
|
|
867
|
+
return num;
|
|
868
|
+
}
|
|
869
|
+
const den = (0, _shared_1.argToNumber)(args[1]);
|
|
870
|
+
if ((0, values_1.isError)(den)) {
|
|
871
|
+
return den;
|
|
872
|
+
}
|
|
873
|
+
if (den.value === 0) {
|
|
874
|
+
return values_1.ERRORS.DIV0;
|
|
875
|
+
}
|
|
876
|
+
return (0, values_1.rvNumber)(Math.trunc(num.value / den.value));
|
|
877
|
+
};
|
|
878
|
+
exports.fnQUOTIENT = fnQUOTIENT;
|
|
879
|
+
const fnBASE = args => {
|
|
880
|
+
const num = (0, _shared_1.argToNumber)(args[0]);
|
|
881
|
+
if ((0, values_1.isError)(num)) {
|
|
882
|
+
return num;
|
|
883
|
+
}
|
|
884
|
+
const radix = (0, _shared_1.argToNumber)(args[1]);
|
|
885
|
+
if ((0, values_1.isError)(radix)) {
|
|
886
|
+
return radix;
|
|
887
|
+
}
|
|
888
|
+
if (radix.value < 2 || radix.value > 36) {
|
|
889
|
+
return values_1.ERRORS.NUM;
|
|
890
|
+
}
|
|
891
|
+
const minLenRV = args.length > 2 ? (0, _shared_1.argToNumber)(args[2]) : (0, values_1.rvNumber)(0);
|
|
892
|
+
if ((0, values_1.isError)(minLenRV)) {
|
|
893
|
+
return minLenRV;
|
|
894
|
+
}
|
|
895
|
+
const result = Math.floor(num.value).toString(Math.floor(radix.value)).toUpperCase();
|
|
896
|
+
return (0, values_1.rvString)(minLenRV.value > 0 ? result.padStart(minLenRV.value, "0") : result);
|
|
897
|
+
};
|
|
898
|
+
exports.fnBASE = fnBASE;
|
|
899
|
+
const fnDECIMAL = args => {
|
|
900
|
+
const e = (0, values_1.topLeft)(args[0]);
|
|
901
|
+
if (e.kind === 4 /* RVKind.Error */) {
|
|
902
|
+
return e;
|
|
903
|
+
}
|
|
904
|
+
const text = (0, values_1.toStringRV)(e);
|
|
905
|
+
const radix = (0, _shared_1.argToNumber)(args[1]);
|
|
906
|
+
if ((0, values_1.isError)(radix)) {
|
|
907
|
+
return radix;
|
|
908
|
+
}
|
|
909
|
+
if (radix.value < 2 || radix.value > 36) {
|
|
910
|
+
return values_1.ERRORS.NUM;
|
|
911
|
+
}
|
|
912
|
+
// `parseInt("1G", 16)` returns 1 because JavaScript silently stops at
|
|
913
|
+
// the first invalid digit. Excel's DECIMAL requires every character in
|
|
914
|
+
// the input to be a valid digit for the given radix, so we validate
|
|
915
|
+
// strictly before delegating.
|
|
916
|
+
const base = Math.floor(radix.value);
|
|
917
|
+
const trimmed = text.trim();
|
|
918
|
+
if (trimmed === "") {
|
|
919
|
+
return values_1.ERRORS.NUM;
|
|
920
|
+
}
|
|
921
|
+
// Digit alphabet up to base 36: 0-9, A-Z (case-insensitive).
|
|
922
|
+
const match = /^[+-]?([0-9A-Za-z]+)$/.exec(trimmed);
|
|
923
|
+
if (!match) {
|
|
924
|
+
return values_1.ERRORS.NUM;
|
|
925
|
+
}
|
|
926
|
+
const digits = match[1].toUpperCase();
|
|
927
|
+
for (const ch of digits) {
|
|
928
|
+
const d = ch >= "0" && ch <= "9" ? ch.charCodeAt(0) - 48 : ch.charCodeAt(0) - 55;
|
|
929
|
+
if (d < 0 || d >= base) {
|
|
930
|
+
return values_1.ERRORS.NUM;
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
const result = parseInt(trimmed, base);
|
|
934
|
+
if (isNaN(result)) {
|
|
935
|
+
return values_1.ERRORS.NUM;
|
|
936
|
+
}
|
|
937
|
+
return (0, values_1.rvNumber)(result);
|
|
938
|
+
};
|
|
939
|
+
exports.fnDECIMAL = fnDECIMAL;
|
|
940
|
+
const fnROMAN = args => {
|
|
941
|
+
const num = (0, _shared_1.argToNumber)(args[0]);
|
|
942
|
+
if ((0, values_1.isError)(num)) {
|
|
943
|
+
return num;
|
|
944
|
+
}
|
|
945
|
+
let n = Math.floor(num.value);
|
|
946
|
+
if (n < 0 || n > 3999) {
|
|
947
|
+
return values_1.ERRORS.VALUE;
|
|
948
|
+
}
|
|
949
|
+
if (n === 0) {
|
|
950
|
+
return (0, values_1.rvString)("");
|
|
951
|
+
}
|
|
952
|
+
// The optional `form` argument (0=classic through 4=simplified) controls
|
|
953
|
+
// how far Excel will collapse repeated characters into subtractive pairs.
|
|
954
|
+
// Higher forms introduce additional patterns beyond the classic IV/IX/
|
|
955
|
+
// XL/XC/CD/CM pairs — e.g. form 1 allows LM for 950, form 4 uses the
|
|
956
|
+
// maximally short forms. A value of TRUE (1) / FALSE (0) maps to form 0
|
|
957
|
+
// / 4 the way Excel does.
|
|
958
|
+
let form = 0;
|
|
959
|
+
if (args.length > 1 && args[1].kind !== 0 /* RVKind.Blank */) {
|
|
960
|
+
const f = (0, _shared_1.argToNumber)(args[1]);
|
|
961
|
+
if ((0, values_1.isError)(f)) {
|
|
962
|
+
return f;
|
|
963
|
+
}
|
|
964
|
+
if (f.value === 1 && f.value === 1) {
|
|
965
|
+
// Boolean inputs flow through argToNumber as 0/1 already.
|
|
966
|
+
}
|
|
967
|
+
form = Math.floor(f.value);
|
|
968
|
+
if (form < 0 || form > 4) {
|
|
969
|
+
return values_1.ERRORS.VALUE;
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
// Classic table (form 0) — subtractive pairs IV, IX, XL, XC, CD, CM.
|
|
973
|
+
const vals = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
|
|
974
|
+
const syms = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"];
|
|
975
|
+
// Forms 1-4 progressively introduce aggressive subtractive pairs
|
|
976
|
+
// (LM=950, VC=95, IC=99, etc.). Each extra must only trigger at its
|
|
977
|
+
// `minForm` or higher — and must NOT duplicate a value the classic
|
|
978
|
+
// table already covers, or we'd emit the same subtractive pair twice
|
|
979
|
+
// per occurrence (e.g. 1999 would become "CMCMCXCIX" instead of
|
|
980
|
+
// "MCMXCIX").
|
|
981
|
+
const extraByForm = [
|
|
982
|
+
{ value: 995, sym: "VM", minForm: 4 },
|
|
983
|
+
{ value: 990, sym: "XM", minForm: 3 },
|
|
984
|
+
{ value: 950, sym: "LM", minForm: 1 },
|
|
985
|
+
{ value: 495, sym: "VD", minForm: 4 },
|
|
986
|
+
{ value: 490, sym: "XD", minForm: 3 },
|
|
987
|
+
{ value: 450, sym: "LD", minForm: 1 },
|
|
988
|
+
{ value: 99, sym: "IC", minForm: 2 },
|
|
989
|
+
{ value: 95, sym: "VC", minForm: 1 },
|
|
990
|
+
{ value: 49, sym: "IL", minForm: 2 },
|
|
991
|
+
{ value: 45, sym: "VL", minForm: 1 }
|
|
992
|
+
];
|
|
993
|
+
let result = "";
|
|
994
|
+
// Merge: walk from largest remainder, trying any applicable extra then
|
|
995
|
+
// the classic table entry.
|
|
996
|
+
while (n > 0) {
|
|
997
|
+
let matched = false;
|
|
998
|
+
for (const ex of extraByForm) {
|
|
999
|
+
if (form >= ex.minForm && n >= ex.value) {
|
|
1000
|
+
result += ex.sym;
|
|
1001
|
+
n -= ex.value;
|
|
1002
|
+
matched = true;
|
|
1003
|
+
break;
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
if (matched) {
|
|
1007
|
+
continue;
|
|
1008
|
+
}
|
|
1009
|
+
for (let i = 0; i < vals.length; i++) {
|
|
1010
|
+
if (n >= vals[i]) {
|
|
1011
|
+
result += syms[i];
|
|
1012
|
+
n -= vals[i];
|
|
1013
|
+
matched = true;
|
|
1014
|
+
break;
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
if (!matched) {
|
|
1018
|
+
// Safety net — should not happen since the classic table covers 1.
|
|
1019
|
+
break;
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
return (0, values_1.rvString)(result);
|
|
1023
|
+
};
|
|
1024
|
+
exports.fnROMAN = fnROMAN;
|
|
1025
|
+
const fnARABIC = args => {
|
|
1026
|
+
const s = (0, values_1.topLeft)(args[0]);
|
|
1027
|
+
if (s.kind === 4 /* RVKind.Error */) {
|
|
1028
|
+
return s;
|
|
1029
|
+
}
|
|
1030
|
+
const text = (0, values_1.toStringRV)(s).toUpperCase().trim();
|
|
1031
|
+
if (text === "") {
|
|
1032
|
+
return (0, values_1.rvNumber)(0);
|
|
1033
|
+
}
|
|
1034
|
+
const romanMap = { I: 1, V: 5, X: 10, L: 50, C: 100, D: 500, M: 1000 };
|
|
1035
|
+
let result = 0;
|
|
1036
|
+
for (let i = 0; i < text.length; i++) {
|
|
1037
|
+
const current = romanMap[text[i]];
|
|
1038
|
+
const next = romanMap[text[i + 1]];
|
|
1039
|
+
if (current === undefined) {
|
|
1040
|
+
return values_1.ERRORS.VALUE;
|
|
1041
|
+
}
|
|
1042
|
+
if (next && current < next) {
|
|
1043
|
+
result -= current;
|
|
1044
|
+
}
|
|
1045
|
+
else {
|
|
1046
|
+
result += current;
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
return (0, values_1.rvNumber)(result);
|
|
1050
|
+
};
|
|
1051
|
+
exports.fnARABIC = fnARABIC;
|
|
1052
|
+
const fnDEGREES = args => {
|
|
1053
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
1054
|
+
return (0, values_1.isError)(n) ? n : (0, values_1.rvNumber)((n.value * 180) / Math.PI);
|
|
1055
|
+
};
|
|
1056
|
+
exports.fnDEGREES = fnDEGREES;
|
|
1057
|
+
const fnRADIANS = args => {
|
|
1058
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
1059
|
+
return (0, values_1.isError)(n) ? n : (0, values_1.rvNumber)((n.value * Math.PI) / 180);
|
|
1060
|
+
};
|
|
1061
|
+
exports.fnRADIANS = fnRADIANS;
|
|
1062
|
+
/**
|
|
1063
|
+
* Shared driver for SUMX2MY2 / SUMX2PY2 / SUMXMY2. Walks two arrays in
|
|
1064
|
+
* lock-step and reduces `combine(x, y)` across matching numeric cells.
|
|
1065
|
+
* Non-numeric cells are skipped (Excel behaviour) and errors propagate.
|
|
1066
|
+
*/
|
|
1067
|
+
function sumPairedArrays(args, combine) {
|
|
1068
|
+
const a0 = args[0];
|
|
1069
|
+
const a1 = args[1];
|
|
1070
|
+
if (a0.kind !== 5 /* RVKind.Array */ || a1.kind !== 5 /* RVKind.Array */) {
|
|
1071
|
+
return values_1.ERRORS.VALUE;
|
|
1072
|
+
}
|
|
1073
|
+
const h = Math.min(a0.height, a1.height);
|
|
1074
|
+
const w = Math.min(a0.width, a1.width);
|
|
1075
|
+
let sum = 0;
|
|
1076
|
+
for (let r = 0; r < h; r++) {
|
|
1077
|
+
for (let c = 0; c < w; c++) {
|
|
1078
|
+
const x = a0.rows[r][c];
|
|
1079
|
+
const y = a1.rows[r][c];
|
|
1080
|
+
if (x.kind === 4 /* RVKind.Error */) {
|
|
1081
|
+
return x;
|
|
1082
|
+
}
|
|
1083
|
+
if (y.kind === 4 /* RVKind.Error */) {
|
|
1084
|
+
return y;
|
|
1085
|
+
}
|
|
1086
|
+
if (x.kind !== 1 /* RVKind.Number */ || y.kind !== 1 /* RVKind.Number */) {
|
|
1087
|
+
continue;
|
|
1088
|
+
}
|
|
1089
|
+
sum += combine(x.value, y.value);
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
return (0, values_1.rvNumber)(sum);
|
|
1093
|
+
}
|
|
1094
|
+
const fnSUMX2MY2 = args => sumPairedArrays(args, (x, y) => x * x - y * y);
|
|
1095
|
+
exports.fnSUMX2MY2 = fnSUMX2MY2;
|
|
1096
|
+
const fnSUMX2PY2 = args => sumPairedArrays(args, (x, y) => x * x + y * y);
|
|
1097
|
+
exports.fnSUMX2PY2 = fnSUMX2PY2;
|
|
1098
|
+
const fnSUMXMY2 = args => sumPairedArrays(args, (x, y) => (x - y) ** 2);
|
|
1099
|
+
exports.fnSUMXMY2 = fnSUMXMY2;
|
|
1100
|
+
const fnMULTINOMIAL = args => {
|
|
1101
|
+
const nums = (0, _shared_1.flattenNumbers)(args);
|
|
1102
|
+
const err = (0, _shared_1.firstError)(nums);
|
|
1103
|
+
if (err) {
|
|
1104
|
+
return err;
|
|
1105
|
+
}
|
|
1106
|
+
// Work in log space so the numerator (sum! ≈ up to ~1e307 around sum = 170)
|
|
1107
|
+
// doesn't overflow before we divide. Summing logs avoids the NaN case
|
|
1108
|
+
// `Infinity / Infinity` that the direct product formulation would hit
|
|
1109
|
+
// for large inputs.
|
|
1110
|
+
let sum = 0;
|
|
1111
|
+
let lnDenom = 0;
|
|
1112
|
+
for (const n of nums) {
|
|
1113
|
+
const ni = Math.floor(n.value);
|
|
1114
|
+
if (ni < 0) {
|
|
1115
|
+
return values_1.ERRORS.NUM;
|
|
1116
|
+
}
|
|
1117
|
+
sum += ni;
|
|
1118
|
+
for (let i = 2; i <= ni; i++) {
|
|
1119
|
+
lnDenom += Math.log(i);
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
let lnNumer = 0;
|
|
1123
|
+
for (let i = 2; i <= sum; i++) {
|
|
1124
|
+
lnNumer += Math.log(i);
|
|
1125
|
+
}
|
|
1126
|
+
const result = Math.exp(lnNumer - lnDenom);
|
|
1127
|
+
if (!isFinite(result)) {
|
|
1128
|
+
return values_1.ERRORS.NUM;
|
|
1129
|
+
}
|
|
1130
|
+
// Round to the nearest integer — the log-exp round-trip introduces sub-ulp
|
|
1131
|
+
// noise that would otherwise leave us with things like `20.0000000001`.
|
|
1132
|
+
return (0, values_1.rvNumber)(Math.round(result));
|
|
1133
|
+
};
|
|
1134
|
+
exports.fnMULTINOMIAL = fnMULTINOMIAL;
|
|
1135
|
+
const fnFACT = args => {
|
|
1136
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
1137
|
+
if ((0, values_1.isError)(n)) {
|
|
1138
|
+
return n;
|
|
1139
|
+
}
|
|
1140
|
+
const num = Math.floor(n.value);
|
|
1141
|
+
if (num < 0) {
|
|
1142
|
+
return values_1.ERRORS.NUM;
|
|
1143
|
+
}
|
|
1144
|
+
if (num > 170) {
|
|
1145
|
+
return values_1.ERRORS.NUM;
|
|
1146
|
+
}
|
|
1147
|
+
let result = 1;
|
|
1148
|
+
for (let i = 2; i <= num; i++) {
|
|
1149
|
+
result *= i;
|
|
1150
|
+
}
|
|
1151
|
+
return (0, values_1.rvNumber)(result);
|
|
1152
|
+
};
|
|
1153
|
+
exports.fnFACT = fnFACT;
|
|
1154
|
+
const fnFACTDOUBLE = args => {
|
|
1155
|
+
const n = (0, _shared_1.argToNumber)(args[0]);
|
|
1156
|
+
if ((0, values_1.isError)(n)) {
|
|
1157
|
+
return n;
|
|
1158
|
+
}
|
|
1159
|
+
const num = Math.floor(n.value);
|
|
1160
|
+
if (num < -1) {
|
|
1161
|
+
return values_1.ERRORS.NUM;
|
|
1162
|
+
}
|
|
1163
|
+
if (num <= 0) {
|
|
1164
|
+
return (0, values_1.rvNumber)(1);
|
|
1165
|
+
}
|
|
1166
|
+
let result = 1;
|
|
1167
|
+
for (let i = num; i > 0; i -= 2) {
|
|
1168
|
+
result *= i;
|
|
1169
|
+
if (!isFinite(result)) {
|
|
1170
|
+
return values_1.ERRORS.NUM;
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
return (0, values_1.rvNumber)(result);
|
|
1174
|
+
};
|
|
1175
|
+
exports.fnFACTDOUBLE = fnFACTDOUBLE;
|
|
1176
|
+
const fnCOMBIN = args => {
|
|
1177
|
+
const nRV = (0, _shared_1.argToNumber)(args[0]);
|
|
1178
|
+
if ((0, values_1.isError)(nRV)) {
|
|
1179
|
+
return nRV;
|
|
1180
|
+
}
|
|
1181
|
+
const kRV = (0, _shared_1.argToNumber)(args[1]);
|
|
1182
|
+
if ((0, values_1.isError)(kRV)) {
|
|
1183
|
+
return kRV;
|
|
1184
|
+
}
|
|
1185
|
+
const ni = Math.floor(nRV.value);
|
|
1186
|
+
const ki = Math.floor(kRV.value);
|
|
1187
|
+
if (ni < 0 || ki < 0 || ki > ni) {
|
|
1188
|
+
return values_1.ERRORS.NUM;
|
|
1189
|
+
}
|
|
1190
|
+
// Use the `C(n, k) = C(n, k-1) * (n-k+1)/k` recurrence and pick the
|
|
1191
|
+
// smaller of k / (n-k) so the loop runs at most n/2 iterations. The
|
|
1192
|
+
// interleaved divide keeps the running value bounded and preserves
|
|
1193
|
+
// near-full double precision until the final product overflows
|
|
1194
|
+
// magnitude ~1e308 (at which point we surface #NUM!).
|
|
1195
|
+
const kEff = Math.min(ki, ni - ki);
|
|
1196
|
+
let result = 1;
|
|
1197
|
+
for (let i = 0; i < kEff; i++) {
|
|
1198
|
+
result = (result * (ni - i)) / (i + 1);
|
|
1199
|
+
if (!isFinite(result)) {
|
|
1200
|
+
return values_1.ERRORS.NUM;
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
// Excel returns an integer for COMBIN when the value fits in a double
|
|
1204
|
+
// exactly (≤ 2^53); beyond that (e.g. COMBIN(100, 50) ≈ 1e29) the
|
|
1205
|
+
// result is fundamentally approximate, so rounding only makes sense
|
|
1206
|
+
// below 2^53.
|
|
1207
|
+
return (0, values_1.rvNumber)(result < 9.007199254740992e15 ? Math.round(result) : result);
|
|
1208
|
+
};
|
|
1209
|
+
exports.fnCOMBIN = fnCOMBIN;
|
|
1210
|
+
const fnCOMBINA = args => {
|
|
1211
|
+
const nRV = (0, _shared_1.argToNumber)(args[0]);
|
|
1212
|
+
if ((0, values_1.isError)(nRV)) {
|
|
1213
|
+
return nRV;
|
|
1214
|
+
}
|
|
1215
|
+
const kRV = (0, _shared_1.argToNumber)(args[1]);
|
|
1216
|
+
if ((0, values_1.isError)(kRV)) {
|
|
1217
|
+
return kRV;
|
|
1218
|
+
}
|
|
1219
|
+
// Special case: Excel's COMBINA(0, 0) is 1 even though the delegated
|
|
1220
|
+
// `COMBIN(-1, 0)` would flag #NUM! under our generic validation.
|
|
1221
|
+
if (nRV.value === 0 && kRV.value === 0) {
|
|
1222
|
+
return (0, values_1.rvNumber)(1);
|
|
1223
|
+
}
|
|
1224
|
+
return (0, exports.fnCOMBIN)([(0, values_1.rvNumber)(nRV.value + kRV.value - 1), kRV]);
|
|
1225
|
+
};
|
|
1226
|
+
exports.fnCOMBINA = fnCOMBINA;
|
|
1227
|
+
const fnPERMUT = args => {
|
|
1228
|
+
const nRV = (0, _shared_1.argToNumber)(args[0]);
|
|
1229
|
+
if ((0, values_1.isError)(nRV)) {
|
|
1230
|
+
return nRV;
|
|
1231
|
+
}
|
|
1232
|
+
const kRV = (0, _shared_1.argToNumber)(args[1]);
|
|
1233
|
+
if ((0, values_1.isError)(kRV)) {
|
|
1234
|
+
return kRV;
|
|
1235
|
+
}
|
|
1236
|
+
const ni = Math.floor(nRV.value);
|
|
1237
|
+
const ki = Math.floor(kRV.value);
|
|
1238
|
+
if (ni < 0 || ki < 0 || ki > ni) {
|
|
1239
|
+
return values_1.ERRORS.NUM;
|
|
1240
|
+
}
|
|
1241
|
+
let result = 1;
|
|
1242
|
+
for (let i = 0; i < ki; i++) {
|
|
1243
|
+
result *= ni - i;
|
|
1244
|
+
}
|
|
1245
|
+
return (0, values_1.rvNumber)(result);
|
|
1246
|
+
};
|
|
1247
|
+
exports.fnPERMUT = fnPERMUT;
|
|
1248
|
+
// ============================================================================
|
|
1249
|
+
// Matrix functions: MMULT, MDETERM, MINVERSE, MUNIT
|
|
1250
|
+
// ============================================================================
|
|
1251
|
+
/**
|
|
1252
|
+
* Extract a numeric matrix from an ArrayValue. Returns #VALUE! when any
|
|
1253
|
+
* cell is non-numeric or an error propagates.
|
|
1254
|
+
*/
|
|
1255
|
+
function asNumericMatrix(v) {
|
|
1256
|
+
if (!(0, values_1.isArray)(v)) {
|
|
1257
|
+
return values_1.ERRORS.VALUE;
|
|
1258
|
+
}
|
|
1259
|
+
const arr = v;
|
|
1260
|
+
const out = [];
|
|
1261
|
+
for (const row of arr.rows) {
|
|
1262
|
+
const r = [];
|
|
1263
|
+
for (const cell of row) {
|
|
1264
|
+
if (cell.kind === 4 /* RVKind.Error */) {
|
|
1265
|
+
return cell;
|
|
1266
|
+
}
|
|
1267
|
+
if (cell.kind !== 1 /* RVKind.Number */) {
|
|
1268
|
+
return values_1.ERRORS.VALUE;
|
|
1269
|
+
}
|
|
1270
|
+
r.push(cell.value);
|
|
1271
|
+
}
|
|
1272
|
+
out.push(r);
|
|
1273
|
+
}
|
|
1274
|
+
return out;
|
|
1275
|
+
}
|
|
1276
|
+
/**
|
|
1277
|
+
* MMULT(array1, array2) — matrix product. Dimensions must be
|
|
1278
|
+
* (m×k) × (k×n) = (m×n); mismatched sizes return #VALUE!.
|
|
1279
|
+
*/
|
|
1280
|
+
const fnMMULT = args => {
|
|
1281
|
+
const a = asNumericMatrix(args[0]);
|
|
1282
|
+
if ("kind" in a) {
|
|
1283
|
+
return a;
|
|
1284
|
+
}
|
|
1285
|
+
const b = asNumericMatrix(args[1]);
|
|
1286
|
+
if ("kind" in b) {
|
|
1287
|
+
return b;
|
|
1288
|
+
}
|
|
1289
|
+
const m = a.length;
|
|
1290
|
+
const k = a[0]?.length ?? 0;
|
|
1291
|
+
const k2 = b.length;
|
|
1292
|
+
const n = b[0]?.length ?? 0;
|
|
1293
|
+
if (m === 0 || k === 0 || n === 0 || k !== k2) {
|
|
1294
|
+
return values_1.ERRORS.VALUE;
|
|
1295
|
+
}
|
|
1296
|
+
const rows = [];
|
|
1297
|
+
for (let i = 0; i < m; i++) {
|
|
1298
|
+
const row = [];
|
|
1299
|
+
for (let j = 0; j < n; j++) {
|
|
1300
|
+
let sum = 0;
|
|
1301
|
+
for (let p = 0; p < k; p++) {
|
|
1302
|
+
sum += a[i][p] * b[p][j];
|
|
1303
|
+
}
|
|
1304
|
+
row.push((0, values_1.rvNumber)(sum));
|
|
1305
|
+
}
|
|
1306
|
+
rows.push(row);
|
|
1307
|
+
}
|
|
1308
|
+
return (0, values_1.rvArray)(rows);
|
|
1309
|
+
};
|
|
1310
|
+
exports.fnMMULT = fnMMULT;
|
|
1311
|
+
/**
|
|
1312
|
+
* MDETERM(array) — determinant of a square matrix via Gaussian
|
|
1313
|
+
* elimination with partial pivoting. Non-square or non-numeric input
|
|
1314
|
+
* returns #VALUE!.
|
|
1315
|
+
*/
|
|
1316
|
+
const fnMDETERM = args => {
|
|
1317
|
+
const mat = asNumericMatrix(args[0]);
|
|
1318
|
+
if ("kind" in mat) {
|
|
1319
|
+
return mat;
|
|
1320
|
+
}
|
|
1321
|
+
const n = mat.length;
|
|
1322
|
+
if (n === 0 || mat[0].length !== n) {
|
|
1323
|
+
return values_1.ERRORS.VALUE;
|
|
1324
|
+
}
|
|
1325
|
+
// Copy rows so we don't mutate the caller's array.
|
|
1326
|
+
const a = mat.map(r => r.slice());
|
|
1327
|
+
let det = 1;
|
|
1328
|
+
for (let i = 0; i < n; i++) {
|
|
1329
|
+
// Partial pivot: find row with largest |a[r][i]| for r in [i, n).
|
|
1330
|
+
let pivot = i;
|
|
1331
|
+
for (let r = i + 1; r < n; r++) {
|
|
1332
|
+
if (Math.abs(a[r][i]) > Math.abs(a[pivot][i])) {
|
|
1333
|
+
pivot = r;
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
if (Math.abs(a[pivot][i]) < 1e-14) {
|
|
1337
|
+
return (0, values_1.rvNumber)(0);
|
|
1338
|
+
}
|
|
1339
|
+
if (pivot !== i) {
|
|
1340
|
+
const tmp = a[i];
|
|
1341
|
+
a[i] = a[pivot];
|
|
1342
|
+
a[pivot] = tmp;
|
|
1343
|
+
det = -det;
|
|
1344
|
+
}
|
|
1345
|
+
det *= a[i][i];
|
|
1346
|
+
for (let r = i + 1; r < n; r++) {
|
|
1347
|
+
const factor = a[r][i] / a[i][i];
|
|
1348
|
+
for (let c = i; c < n; c++) {
|
|
1349
|
+
a[r][c] -= factor * a[i][c];
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
return (0, values_1.rvNumber)(det);
|
|
1354
|
+
};
|
|
1355
|
+
exports.fnMDETERM = fnMDETERM;
|
|
1356
|
+
/**
|
|
1357
|
+
* MINVERSE(array) — inverse of a square matrix via Gauss-Jordan
|
|
1358
|
+
* elimination. Singular matrices return #NUM!; non-square return
|
|
1359
|
+
* #VALUE!.
|
|
1360
|
+
*/
|
|
1361
|
+
const fnMINVERSE = args => {
|
|
1362
|
+
const mat = asNumericMatrix(args[0]);
|
|
1363
|
+
if ("kind" in mat) {
|
|
1364
|
+
return mat;
|
|
1365
|
+
}
|
|
1366
|
+
const n = mat.length;
|
|
1367
|
+
if (n === 0 || mat[0].length !== n) {
|
|
1368
|
+
return values_1.ERRORS.VALUE;
|
|
1369
|
+
}
|
|
1370
|
+
// Build augmented matrix [A | I].
|
|
1371
|
+
const aug = [];
|
|
1372
|
+
for (let i = 0; i < n; i++) {
|
|
1373
|
+
const row = new Array(2 * n).fill(0);
|
|
1374
|
+
for (let j = 0; j < n; j++) {
|
|
1375
|
+
row[j] = mat[i][j];
|
|
1376
|
+
}
|
|
1377
|
+
row[n + i] = 1;
|
|
1378
|
+
aug.push(row);
|
|
1379
|
+
}
|
|
1380
|
+
// Gauss-Jordan elimination with partial pivoting.
|
|
1381
|
+
for (let i = 0; i < n; i++) {
|
|
1382
|
+
let pivot = i;
|
|
1383
|
+
for (let r = i + 1; r < n; r++) {
|
|
1384
|
+
if (Math.abs(aug[r][i]) > Math.abs(aug[pivot][i])) {
|
|
1385
|
+
pivot = r;
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
if (Math.abs(aug[pivot][i]) < 1e-14) {
|
|
1389
|
+
return values_1.ERRORS.NUM; // singular
|
|
1390
|
+
}
|
|
1391
|
+
if (pivot !== i) {
|
|
1392
|
+
const tmp = aug[i];
|
|
1393
|
+
aug[i] = aug[pivot];
|
|
1394
|
+
aug[pivot] = tmp;
|
|
1395
|
+
}
|
|
1396
|
+
const diag = aug[i][i];
|
|
1397
|
+
for (let c = 0; c < 2 * n; c++) {
|
|
1398
|
+
aug[i][c] /= diag;
|
|
1399
|
+
}
|
|
1400
|
+
for (let r = 0; r < n; r++) {
|
|
1401
|
+
if (r === i) {
|
|
1402
|
+
continue;
|
|
1403
|
+
}
|
|
1404
|
+
const factor = aug[r][i];
|
|
1405
|
+
if (factor === 0) {
|
|
1406
|
+
continue;
|
|
1407
|
+
}
|
|
1408
|
+
for (let c = 0; c < 2 * n; c++) {
|
|
1409
|
+
aug[r][c] -= factor * aug[i][c];
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
// Extract inverse from right half.
|
|
1414
|
+
const rows = [];
|
|
1415
|
+
for (let i = 0; i < n; i++) {
|
|
1416
|
+
const row = [];
|
|
1417
|
+
for (let j = 0; j < n; j++) {
|
|
1418
|
+
row.push((0, values_1.rvNumber)(aug[i][n + j]));
|
|
1419
|
+
}
|
|
1420
|
+
rows.push(row);
|
|
1421
|
+
}
|
|
1422
|
+
return (0, values_1.rvArray)(rows);
|
|
1423
|
+
};
|
|
1424
|
+
exports.fnMINVERSE = fnMINVERSE;
|
|
1425
|
+
/**
|
|
1426
|
+
* MUNIT(dimension) — n×n identity matrix.
|
|
1427
|
+
*/
|
|
1428
|
+
const fnMUNIT = args => {
|
|
1429
|
+
const nV = (0, values_1.toNumberRV)((0, values_1.topLeft)(args[0]));
|
|
1430
|
+
if ((0, values_1.isError)(nV)) {
|
|
1431
|
+
return nV;
|
|
1432
|
+
}
|
|
1433
|
+
const n = Math.trunc(nV.value);
|
|
1434
|
+
if (n < 1) {
|
|
1435
|
+
return values_1.ERRORS.VALUE;
|
|
1436
|
+
}
|
|
1437
|
+
const rows = [];
|
|
1438
|
+
for (let i = 0; i < n; i++) {
|
|
1439
|
+
const row = new Array(n);
|
|
1440
|
+
for (let j = 0; j < n; j++) {
|
|
1441
|
+
row[j] = (0, values_1.rvNumber)(i === j ? 1 : 0);
|
|
1442
|
+
}
|
|
1443
|
+
rows.push(row);
|
|
1444
|
+
}
|
|
1445
|
+
return (0, values_1.rvArray)(rows);
|
|
1446
|
+
};
|
|
1447
|
+
exports.fnMUNIT = fnMUNIT;
|
|
1448
|
+
// ============================================================================
|
|
1449
|
+
// SERIESSUM
|
|
1450
|
+
// ============================================================================
|
|
1451
|
+
/**
|
|
1452
|
+
* SERIESSUM(x, n, m, coefficients) — returns the sum of a power series
|
|
1453
|
+
* x^n * coef[0] + x^(n+m) * coef[1] + x^(n+2m) * coef[2] + …
|
|
1454
|
+
*/
|
|
1455
|
+
const fnSERIESSUM = args => {
|
|
1456
|
+
const xV = (0, values_1.toNumberRV)((0, values_1.topLeft)(args[0]));
|
|
1457
|
+
if ((0, values_1.isError)(xV)) {
|
|
1458
|
+
return xV;
|
|
1459
|
+
}
|
|
1460
|
+
const nV = (0, values_1.toNumberRV)((0, values_1.topLeft)(args[1]));
|
|
1461
|
+
if ((0, values_1.isError)(nV)) {
|
|
1462
|
+
return nV;
|
|
1463
|
+
}
|
|
1464
|
+
const mV = (0, values_1.toNumberRV)((0, values_1.topLeft)(args[2]));
|
|
1465
|
+
if ((0, values_1.isError)(mV)) {
|
|
1466
|
+
return mV;
|
|
1467
|
+
}
|
|
1468
|
+
const coeffs = (0, _shared_1.flattenNumbers)([args[3]]);
|
|
1469
|
+
const err = (0, _shared_1.firstError)(coeffs);
|
|
1470
|
+
if (err) {
|
|
1471
|
+
return err;
|
|
1472
|
+
}
|
|
1473
|
+
if (coeffs.length === 0) {
|
|
1474
|
+
return values_1.ERRORS.VALUE;
|
|
1475
|
+
}
|
|
1476
|
+
let total = 0;
|
|
1477
|
+
let exponent = nV.value;
|
|
1478
|
+
for (const c of coeffs) {
|
|
1479
|
+
total += c.value * Math.pow(xV.value, exponent);
|
|
1480
|
+
exponent += mV.value;
|
|
1481
|
+
}
|
|
1482
|
+
if (!isFinite(total)) {
|
|
1483
|
+
return values_1.ERRORS.NUM;
|
|
1484
|
+
}
|
|
1485
|
+
return (0, values_1.rvNumber)(total);
|
|
1486
|
+
};
|
|
1487
|
+
exports.fnSERIESSUM = fnSERIESSUM;
|