@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.
Files changed (383) hide show
  1. package/README.md +25 -2
  2. package/README_zh.md +29 -6
  3. package/dist/browser/index.browser.d.ts +1 -1
  4. package/dist/browser/index.browser.js +4 -0
  5. package/dist/browser/index.d.ts +1 -1
  6. package/dist/browser/index.js +4 -0
  7. package/dist/browser/modules/excel/cell.d.ts +17 -3
  8. package/dist/browser/modules/excel/cell.js +170 -22
  9. package/dist/browser/modules/excel/defined-names.d.ts +96 -1
  10. package/dist/browser/modules/excel/defined-names.js +411 -21
  11. package/dist/browser/modules/excel/image.d.ts +11 -0
  12. package/dist/browser/modules/excel/image.js +24 -1
  13. package/dist/browser/modules/excel/stream/workbook-reader.browser.d.ts +9 -3
  14. package/dist/browser/modules/excel/stream/workbook-reader.browser.js +14 -0
  15. package/dist/browser/modules/excel/stream/workbook-reader.d.ts +2 -1
  16. package/dist/browser/modules/excel/stream/workbook-writer.browser.d.ts +39 -5
  17. package/dist/browser/modules/excel/stream/workbook-writer.browser.js +48 -1
  18. package/dist/browser/modules/excel/stream/workbook-writer.d.ts +3 -2
  19. package/dist/browser/modules/excel/stream/worksheet-reader.js +17 -1
  20. package/dist/browser/modules/excel/stream/worksheet-writer.d.ts +39 -6
  21. package/dist/browser/modules/excel/stream/worksheet-writer.js +45 -5
  22. package/dist/browser/modules/excel/table.js +15 -2
  23. package/dist/browser/modules/excel/types.d.ts +133 -2
  24. package/dist/browser/modules/excel/utils/col-cache.d.ts +1 -0
  25. package/dist/browser/modules/excel/utils/col-cache.js +15 -0
  26. package/dist/browser/modules/excel/utils/drawing-utils.d.ts +3 -3
  27. package/dist/browser/modules/excel/utils/drawing-utils.js +4 -0
  28. package/dist/browser/modules/excel/utils/external-link-formula.d.ts +76 -0
  29. package/dist/browser/modules/excel/utils/external-link-formula.js +208 -0
  30. package/dist/browser/modules/excel/utils/iterate-stream.d.ts +9 -3
  31. package/dist/browser/modules/excel/utils/iterate-stream.js +3 -1
  32. package/dist/browser/modules/excel/utils/ooxml-paths.d.ts +19 -0
  33. package/dist/browser/modules/excel/utils/ooxml-paths.js +37 -2
  34. package/dist/browser/modules/excel/utils/shared-strings.d.ts +8 -3
  35. package/dist/browser/modules/excel/utils/shared-strings.js +21 -2
  36. package/dist/browser/modules/excel/utils/workbook-protection.d.ts +30 -0
  37. package/dist/browser/modules/excel/utils/workbook-protection.js +30 -0
  38. package/dist/browser/modules/excel/workbook.browser.d.ts +257 -6
  39. package/dist/browser/modules/excel/workbook.browser.js +318 -34
  40. package/dist/browser/modules/excel/workbook.d.ts +1 -1
  41. package/dist/browser/modules/excel/worksheet.d.ts +3 -1
  42. package/dist/browser/modules/excel/worksheet.js +21 -2
  43. package/dist/browser/modules/excel/xlsx/rel-type.d.ts +15 -0
  44. package/dist/browser/modules/excel/xlsx/rel-type.js +16 -1
  45. package/dist/browser/modules/excel/xlsx/xform/book/defined-name-xform.d.ts +6 -5
  46. package/dist/browser/modules/excel/xlsx/xform/book/defined-name-xform.js +21 -86
  47. package/dist/browser/modules/excel/xlsx/xform/book/external-link-xform.d.ts +84 -0
  48. package/dist/browser/modules/excel/xlsx/xform/book/external-link-xform.js +330 -0
  49. package/dist/browser/modules/excel/xlsx/xform/book/external-reference-xform.d.ts +17 -0
  50. package/dist/browser/modules/excel/xlsx/xform/book/external-reference-xform.js +24 -0
  51. package/dist/browser/modules/excel/xlsx/xform/book/workbook-calc-properties-xform.d.ts +3 -0
  52. package/dist/browser/modules/excel/xlsx/xform/book/workbook-calc-properties-xform.js +11 -2
  53. package/dist/browser/modules/excel/xlsx/xform/book/workbook-protection-xform.d.ts +20 -0
  54. package/dist/browser/modules/excel/xlsx/xform/book/workbook-protection-xform.js +66 -0
  55. package/dist/browser/modules/excel/xlsx/xform/book/workbook-xform.js +38 -5
  56. package/dist/browser/modules/excel/xlsx/xform/core/content-types-xform.js +19 -1
  57. package/dist/browser/modules/excel/xlsx/xform/core/metadata-xform.d.ts +56 -0
  58. package/dist/browser/modules/excel/xlsx/xform/core/metadata-xform.js +158 -0
  59. package/dist/browser/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.d.ts +26 -0
  60. package/dist/browser/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.js +105 -0
  61. package/dist/browser/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +3 -0
  62. package/dist/browser/modules/excel/xlsx/xform/drawing/drawing-xform.js +10 -2
  63. package/dist/browser/modules/excel/xlsx/xform/sheet/cell-xform.d.ts +1 -1
  64. package/dist/browser/modules/excel/xlsx/xform/sheet/cell-xform.js +166 -8
  65. package/dist/browser/modules/excel/xlsx/xform/sheet/data-validations-xform.js +1 -1
  66. package/dist/browser/modules/excel/xlsx/xform/sheet/ignored-errors-xform.d.ts +21 -0
  67. package/dist/browser/modules/excel/xlsx/xform/sheet/ignored-errors-xform.js +80 -0
  68. package/dist/browser/modules/excel/xlsx/xform/sheet/worksheet-xform.js +9 -4
  69. package/dist/browser/modules/excel/xlsx/xform/style/border-xform.js +4 -1
  70. package/dist/browser/modules/excel/xlsx/xlsx.browser.d.ts +172 -13
  71. package/dist/browser/modules/excel/xlsx/xlsx.browser.js +410 -20
  72. package/dist/browser/modules/excel/xlsx/xlsx.d.ts +7 -4
  73. package/dist/browser/modules/excel/xlsx/xlsx.js +4 -5
  74. package/dist/browser/modules/formula/compile/address-utils.d.ts +62 -0
  75. package/dist/browser/modules/formula/compile/address-utils.js +83 -0
  76. package/dist/browser/modules/formula/compile/binder.d.ts +42 -0
  77. package/dist/browser/modules/formula/compile/binder.js +487 -0
  78. package/dist/browser/modules/formula/compile/bound-ast.d.ts +230 -0
  79. package/dist/browser/modules/formula/compile/bound-ast.js +80 -0
  80. package/dist/browser/modules/formula/compile/compiled-formula.d.ts +137 -0
  81. package/dist/browser/modules/formula/compile/compiled-formula.js +383 -0
  82. package/dist/browser/modules/formula/compile/dependency-analysis.d.ts +93 -0
  83. package/dist/browser/modules/formula/compile/dependency-analysis.js +432 -0
  84. package/dist/browser/modules/formula/compile/structured-ref-utils.d.ts +93 -0
  85. package/dist/browser/modules/formula/compile/structured-ref-utils.js +136 -0
  86. package/dist/browser/modules/formula/default-syntax-probe.d.ts +79 -0
  87. package/dist/browser/modules/formula/default-syntax-probe.js +83 -0
  88. package/dist/browser/modules/formula/functions/_date-context.d.ts +4 -0
  89. package/dist/browser/modules/formula/functions/_date-context.js +29 -0
  90. package/dist/browser/modules/formula/functions/_shared.d.ts +121 -0
  91. package/dist/browser/modules/formula/functions/_shared.js +381 -0
  92. package/dist/browser/modules/formula/functions/conditional.d.ts +27 -0
  93. package/dist/browser/modules/formula/functions/conditional.js +343 -0
  94. package/dist/browser/modules/formula/functions/database.d.ts +37 -0
  95. package/dist/browser/modules/formula/functions/database.js +274 -0
  96. package/dist/browser/modules/formula/functions/date.d.ts +61 -0
  97. package/dist/browser/modules/formula/functions/date.js +855 -0
  98. package/dist/browser/modules/formula/functions/dynamic-array.d.ts +23 -0
  99. package/dist/browser/modules/formula/functions/dynamic-array.js +860 -0
  100. package/dist/browser/modules/formula/functions/engineering.d.ts +57 -0
  101. package/dist/browser/modules/formula/functions/engineering.js +1128 -0
  102. package/dist/browser/modules/formula/functions/financial.d.ts +202 -0
  103. package/dist/browser/modules/formula/functions/financial.js +2296 -0
  104. package/dist/browser/modules/formula/functions/lookup.d.ts +18 -0
  105. package/dist/browser/modules/formula/functions/lookup.js +886 -0
  106. package/dist/browser/modules/formula/functions/math.d.ts +114 -0
  107. package/dist/browser/modules/formula/functions/math.js +1406 -0
  108. package/dist/browser/modules/formula/functions/statistical.d.ts +193 -0
  109. package/dist/browser/modules/formula/functions/statistical.js +3390 -0
  110. package/dist/browser/modules/formula/functions/text.d.ts +86 -0
  111. package/dist/browser/modules/formula/functions/text.js +1845 -0
  112. package/dist/browser/modules/formula/host-registry.d.ts +53 -0
  113. package/dist/browser/modules/formula/host-registry.js +69 -0
  114. package/dist/browser/modules/formula/index.d.ts +39 -0
  115. package/dist/browser/modules/formula/index.js +49 -0
  116. package/dist/browser/modules/formula/install.d.ts +62 -0
  117. package/dist/browser/modules/formula/install.js +88 -0
  118. package/dist/browser/modules/formula/integration/apply-writeback-plan.d.ts +26 -0
  119. package/dist/browser/modules/formula/integration/apply-writeback-plan.js +210 -0
  120. package/dist/browser/modules/formula/integration/calculate-formulas-impl.d.ts +30 -0
  121. package/dist/browser/modules/formula/integration/calculate-formulas-impl.js +616 -0
  122. package/dist/browser/modules/formula/integration/calculate-formulas.d.ts +67 -0
  123. package/dist/browser/modules/formula/integration/calculate-formulas.js +68 -0
  124. package/dist/browser/modules/formula/integration/formula-instance.d.ts +64 -0
  125. package/dist/browser/modules/formula/integration/formula-instance.js +79 -0
  126. package/dist/browser/modules/formula/integration/workbook-adapter.d.ts +26 -0
  127. package/dist/browser/modules/formula/integration/workbook-adapter.js +324 -0
  128. package/dist/browser/modules/formula/integration/workbook-snapshot.d.ts +267 -0
  129. package/dist/browser/modules/formula/integration/workbook-snapshot.js +77 -0
  130. package/dist/browser/modules/formula/materialize/build-writeback-plan.d.ts +34 -0
  131. package/dist/browser/modules/formula/materialize/build-writeback-plan.js +473 -0
  132. package/dist/browser/modules/formula/materialize/spill-engine.d.ts +9 -0
  133. package/dist/browser/modules/formula/materialize/spill-engine.js +38 -0
  134. package/dist/browser/modules/formula/materialize/types.d.ts +179 -0
  135. package/dist/browser/modules/formula/materialize/types.js +29 -0
  136. package/dist/browser/modules/formula/materialize/writeback-plan.d.ts +167 -0
  137. package/dist/browser/modules/formula/materialize/writeback-plan.js +27 -0
  138. package/dist/browser/modules/formula/runtime/evaluator.d.ts +151 -0
  139. package/dist/browser/modules/formula/runtime/evaluator.js +2291 -0
  140. package/dist/browser/modules/formula/runtime/function-registry.d.ts +47 -0
  141. package/dist/browser/modules/formula/runtime/function-registry.js +840 -0
  142. package/dist/browser/modules/formula/runtime/values.d.ts +211 -0
  143. package/dist/browser/modules/formula/runtime/values.js +385 -0
  144. package/dist/browser/modules/formula/syntax/ast.d.ts +129 -0
  145. package/dist/browser/modules/formula/syntax/ast.js +28 -0
  146. package/dist/browser/modules/formula/syntax/parser.d.ts +18 -0
  147. package/dist/browser/modules/formula/syntax/parser.js +439 -0
  148. package/dist/browser/modules/formula/syntax/token-types.d.ts +153 -0
  149. package/dist/browser/modules/formula/syntax/token-types.js +59 -0
  150. package/dist/browser/modules/formula/syntax/tokenizer.d.ts +10 -0
  151. package/dist/browser/modules/formula/syntax/tokenizer.js +1074 -0
  152. package/dist/browser/modules/pdf/excel-bridge.js +9 -0
  153. package/dist/cjs/index.js +4 -0
  154. package/dist/cjs/modules/excel/cell.js +170 -22
  155. package/dist/cjs/modules/excel/defined-names.js +411 -21
  156. package/dist/cjs/modules/excel/image.js +24 -1
  157. package/dist/cjs/modules/excel/stream/workbook-reader.browser.js +14 -0
  158. package/dist/cjs/modules/excel/stream/workbook-writer.browser.js +48 -1
  159. package/dist/cjs/modules/excel/stream/worksheet-reader.js +17 -1
  160. package/dist/cjs/modules/excel/stream/worksheet-writer.js +45 -5
  161. package/dist/cjs/modules/excel/table.js +15 -2
  162. package/dist/cjs/modules/excel/utils/col-cache.js +15 -0
  163. package/dist/cjs/modules/excel/utils/drawing-utils.js +4 -0
  164. package/dist/cjs/modules/excel/utils/external-link-formula.js +212 -0
  165. package/dist/cjs/modules/excel/utils/iterate-stream.js +3 -1
  166. package/dist/cjs/modules/excel/utils/ooxml-paths.js +42 -2
  167. package/dist/cjs/modules/excel/utils/shared-strings.js +21 -2
  168. package/dist/cjs/modules/excel/utils/workbook-protection.js +33 -0
  169. package/dist/cjs/modules/excel/workbook.browser.js +318 -34
  170. package/dist/cjs/modules/excel/worksheet.js +20 -1
  171. package/dist/cjs/modules/excel/xlsx/rel-type.js +16 -1
  172. package/dist/cjs/modules/excel/xlsx/xform/book/defined-name-xform.js +21 -86
  173. package/dist/cjs/modules/excel/xlsx/xform/book/external-link-xform.js +333 -0
  174. package/dist/cjs/modules/excel/xlsx/xform/book/external-reference-xform.js +27 -0
  175. package/dist/cjs/modules/excel/xlsx/xform/book/workbook-calc-properties-xform.js +11 -2
  176. package/dist/cjs/modules/excel/xlsx/xform/book/workbook-protection-xform.js +69 -0
  177. package/dist/cjs/modules/excel/xlsx/xform/book/workbook-xform.js +38 -5
  178. package/dist/cjs/modules/excel/xlsx/xform/core/content-types-xform.js +18 -0
  179. package/dist/cjs/modules/excel/xlsx/xform/core/metadata-xform.js +161 -0
  180. package/dist/cjs/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.js +108 -0
  181. package/dist/cjs/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +3 -0
  182. package/dist/cjs/modules/excel/xlsx/xform/drawing/drawing-xform.js +10 -2
  183. package/dist/cjs/modules/excel/xlsx/xform/sheet/cell-xform.js +166 -8
  184. package/dist/cjs/modules/excel/xlsx/xform/sheet/data-validations-xform.js +1 -1
  185. package/dist/cjs/modules/excel/xlsx/xform/sheet/ignored-errors-xform.js +83 -0
  186. package/dist/cjs/modules/excel/xlsx/xform/sheet/worksheet-xform.js +9 -4
  187. package/dist/cjs/modules/excel/xlsx/xform/style/border-xform.js +4 -1
  188. package/dist/cjs/modules/excel/xlsx/xlsx.browser.js +408 -18
  189. package/dist/cjs/modules/excel/xlsx/xlsx.js +4 -5
  190. package/dist/cjs/modules/formula/compile/address-utils.js +89 -0
  191. package/dist/cjs/modules/formula/compile/binder.js +489 -0
  192. package/dist/cjs/modules/formula/compile/bound-ast.js +68 -0
  193. package/dist/cjs/modules/formula/compile/compiled-formula.js +387 -0
  194. package/dist/cjs/modules/formula/compile/dependency-analysis.js +437 -0
  195. package/dist/cjs/modules/formula/compile/structured-ref-utils.js +141 -0
  196. package/dist/cjs/modules/formula/default-syntax-probe.js +87 -0
  197. package/dist/cjs/modules/formula/functions/_date-context.js +33 -0
  198. package/dist/cjs/modules/formula/functions/_shared.js +396 -0
  199. package/dist/cjs/modules/formula/functions/conditional.js +354 -0
  200. package/dist/cjs/modules/formula/functions/database.js +288 -0
  201. package/dist/cjs/modules/formula/functions/date.js +883 -0
  202. package/dist/cjs/modules/formula/functions/dynamic-array.js +881 -0
  203. package/dist/cjs/modules/formula/functions/engineering.js +1183 -0
  204. package/dist/cjs/modules/formula/functions/financial.js +2348 -0
  205. package/dist/cjs/modules/formula/functions/lookup.js +902 -0
  206. package/dist/cjs/modules/formula/functions/math.js +1487 -0
  207. package/dist/cjs/modules/formula/functions/statistical.js +3488 -0
  208. package/dist/cjs/modules/formula/functions/text.js +1889 -0
  209. package/dist/cjs/modules/formula/host-registry.js +75 -0
  210. package/dist/cjs/modules/formula/index.js +58 -0
  211. package/dist/cjs/modules/formula/install.js +93 -0
  212. package/dist/cjs/modules/formula/integration/apply-writeback-plan.js +213 -0
  213. package/dist/cjs/modules/formula/integration/calculate-formulas-impl.js +619 -0
  214. package/dist/cjs/modules/formula/integration/calculate-formulas.js +71 -0
  215. package/dist/cjs/modules/formula/integration/formula-instance.js +82 -0
  216. package/dist/cjs/modules/formula/integration/workbook-adapter.js +327 -0
  217. package/dist/cjs/modules/formula/integration/workbook-snapshot.js +84 -0
  218. package/dist/cjs/modules/formula/materialize/build-writeback-plan.js +475 -0
  219. package/dist/cjs/modules/formula/materialize/spill-engine.js +42 -0
  220. package/dist/cjs/modules/formula/materialize/types.js +32 -0
  221. package/dist/cjs/modules/formula/materialize/writeback-plan.js +28 -0
  222. package/dist/cjs/modules/formula/runtime/evaluator.js +2298 -0
  223. package/dist/cjs/modules/formula/runtime/function-registry.js +846 -0
  224. package/dist/cjs/modules/formula/runtime/values.js +385 -0
  225. package/dist/cjs/modules/formula/syntax/ast.js +8 -0
  226. package/dist/cjs/modules/formula/syntax/parser.js +440 -0
  227. package/dist/cjs/modules/formula/syntax/token-types.js +32 -0
  228. package/dist/cjs/modules/formula/syntax/tokenizer.js +1076 -0
  229. package/dist/cjs/modules/pdf/excel-bridge.js +9 -0
  230. package/dist/esm/index.browser.js +4 -0
  231. package/dist/esm/index.js +4 -0
  232. package/dist/esm/modules/excel/cell.js +170 -22
  233. package/dist/esm/modules/excel/defined-names.js +411 -21
  234. package/dist/esm/modules/excel/image.js +24 -1
  235. package/dist/esm/modules/excel/stream/workbook-reader.browser.js +14 -0
  236. package/dist/esm/modules/excel/stream/workbook-writer.browser.js +48 -1
  237. package/dist/esm/modules/excel/stream/worksheet-reader.js +17 -1
  238. package/dist/esm/modules/excel/stream/worksheet-writer.js +45 -5
  239. package/dist/esm/modules/excel/table.js +15 -2
  240. package/dist/esm/modules/excel/utils/col-cache.js +15 -0
  241. package/dist/esm/modules/excel/utils/drawing-utils.js +4 -0
  242. package/dist/esm/modules/excel/utils/external-link-formula.js +208 -0
  243. package/dist/esm/modules/excel/utils/iterate-stream.js +3 -1
  244. package/dist/esm/modules/excel/utils/ooxml-paths.js +37 -2
  245. package/dist/esm/modules/excel/utils/shared-strings.js +21 -2
  246. package/dist/esm/modules/excel/utils/workbook-protection.js +30 -0
  247. package/dist/esm/modules/excel/workbook.browser.js +318 -34
  248. package/dist/esm/modules/excel/worksheet.js +21 -2
  249. package/dist/esm/modules/excel/xlsx/rel-type.js +16 -1
  250. package/dist/esm/modules/excel/xlsx/xform/book/defined-name-xform.js +21 -86
  251. package/dist/esm/modules/excel/xlsx/xform/book/external-link-xform.js +330 -0
  252. package/dist/esm/modules/excel/xlsx/xform/book/external-reference-xform.js +24 -0
  253. package/dist/esm/modules/excel/xlsx/xform/book/workbook-calc-properties-xform.js +11 -2
  254. package/dist/esm/modules/excel/xlsx/xform/book/workbook-protection-xform.js +66 -0
  255. package/dist/esm/modules/excel/xlsx/xform/book/workbook-xform.js +38 -5
  256. package/dist/esm/modules/excel/xlsx/xform/core/content-types-xform.js +19 -1
  257. package/dist/esm/modules/excel/xlsx/xform/core/metadata-xform.js +158 -0
  258. package/dist/esm/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.js +105 -0
  259. package/dist/esm/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +3 -0
  260. package/dist/esm/modules/excel/xlsx/xform/drawing/drawing-xform.js +10 -2
  261. package/dist/esm/modules/excel/xlsx/xform/sheet/cell-xform.js +166 -8
  262. package/dist/esm/modules/excel/xlsx/xform/sheet/data-validations-xform.js +1 -1
  263. package/dist/esm/modules/excel/xlsx/xform/sheet/ignored-errors-xform.js +80 -0
  264. package/dist/esm/modules/excel/xlsx/xform/sheet/worksheet-xform.js +9 -4
  265. package/dist/esm/modules/excel/xlsx/xform/style/border-xform.js +4 -1
  266. package/dist/esm/modules/excel/xlsx/xlsx.browser.js +410 -20
  267. package/dist/esm/modules/excel/xlsx/xlsx.js +4 -5
  268. package/dist/esm/modules/formula/compile/address-utils.js +83 -0
  269. package/dist/esm/modules/formula/compile/binder.js +487 -0
  270. package/dist/esm/modules/formula/compile/bound-ast.js +80 -0
  271. package/dist/esm/modules/formula/compile/compiled-formula.js +383 -0
  272. package/dist/esm/modules/formula/compile/dependency-analysis.js +432 -0
  273. package/dist/esm/modules/formula/compile/structured-ref-utils.js +136 -0
  274. package/dist/esm/modules/formula/default-syntax-probe.js +83 -0
  275. package/dist/esm/modules/formula/functions/_date-context.js +29 -0
  276. package/dist/esm/modules/formula/functions/_shared.js +381 -0
  277. package/dist/esm/modules/formula/functions/conditional.js +343 -0
  278. package/dist/esm/modules/formula/functions/database.js +274 -0
  279. package/dist/esm/modules/formula/functions/date.js +855 -0
  280. package/dist/esm/modules/formula/functions/dynamic-array.js +860 -0
  281. package/dist/esm/modules/formula/functions/engineering.js +1128 -0
  282. package/dist/esm/modules/formula/functions/financial.js +2296 -0
  283. package/dist/esm/modules/formula/functions/lookup.js +886 -0
  284. package/dist/esm/modules/formula/functions/math.js +1406 -0
  285. package/dist/esm/modules/formula/functions/statistical.js +3390 -0
  286. package/dist/esm/modules/formula/functions/text.js +1845 -0
  287. package/dist/esm/modules/formula/host-registry.js +69 -0
  288. package/dist/esm/modules/formula/index.js +49 -0
  289. package/dist/esm/modules/formula/install.js +88 -0
  290. package/dist/esm/modules/formula/integration/apply-writeback-plan.js +210 -0
  291. package/dist/esm/modules/formula/integration/calculate-formulas-impl.js +616 -0
  292. package/dist/esm/modules/formula/integration/calculate-formulas.js +68 -0
  293. package/dist/esm/modules/formula/integration/formula-instance.js +79 -0
  294. package/dist/esm/modules/formula/integration/workbook-adapter.js +324 -0
  295. package/dist/esm/modules/formula/integration/workbook-snapshot.js +77 -0
  296. package/dist/esm/modules/formula/materialize/build-writeback-plan.js +473 -0
  297. package/dist/esm/modules/formula/materialize/spill-engine.js +38 -0
  298. package/dist/esm/modules/formula/materialize/types.js +29 -0
  299. package/dist/esm/modules/formula/materialize/writeback-plan.js +27 -0
  300. package/dist/esm/modules/formula/runtime/evaluator.js +2291 -0
  301. package/dist/esm/modules/formula/runtime/function-registry.js +840 -0
  302. package/dist/esm/modules/formula/runtime/values.js +385 -0
  303. package/dist/esm/modules/formula/syntax/ast.js +28 -0
  304. package/dist/esm/modules/formula/syntax/parser.js +439 -0
  305. package/dist/esm/modules/formula/syntax/token-types.js +59 -0
  306. package/dist/esm/modules/formula/syntax/tokenizer.js +1074 -0
  307. package/dist/esm/modules/pdf/excel-bridge.js +9 -0
  308. package/dist/iife/excelts.iife.js +2302 -373
  309. package/dist/iife/excelts.iife.js.map +1 -1
  310. package/dist/iife/excelts.iife.min.js +34 -34
  311. package/dist/types/index.browser.d.ts +1 -1
  312. package/dist/types/index.d.ts +1 -1
  313. package/dist/types/modules/excel/cell.d.ts +17 -3
  314. package/dist/types/modules/excel/defined-names.d.ts +96 -1
  315. package/dist/types/modules/excel/image.d.ts +11 -0
  316. package/dist/types/modules/excel/stream/workbook-reader.browser.d.ts +9 -3
  317. package/dist/types/modules/excel/stream/workbook-reader.d.ts +2 -1
  318. package/dist/types/modules/excel/stream/workbook-writer.browser.d.ts +39 -5
  319. package/dist/types/modules/excel/stream/workbook-writer.d.ts +3 -2
  320. package/dist/types/modules/excel/stream/worksheet-writer.d.ts +39 -6
  321. package/dist/types/modules/excel/types.d.ts +133 -2
  322. package/dist/types/modules/excel/utils/col-cache.d.ts +1 -0
  323. package/dist/types/modules/excel/utils/drawing-utils.d.ts +3 -3
  324. package/dist/types/modules/excel/utils/external-link-formula.d.ts +76 -0
  325. package/dist/types/modules/excel/utils/iterate-stream.d.ts +9 -3
  326. package/dist/types/modules/excel/utils/ooxml-paths.d.ts +19 -0
  327. package/dist/types/modules/excel/utils/shared-strings.d.ts +8 -3
  328. package/dist/types/modules/excel/utils/workbook-protection.d.ts +30 -0
  329. package/dist/types/modules/excel/workbook.browser.d.ts +257 -6
  330. package/dist/types/modules/excel/workbook.d.ts +1 -1
  331. package/dist/types/modules/excel/worksheet.d.ts +3 -1
  332. package/dist/types/modules/excel/xlsx/rel-type.d.ts +15 -0
  333. package/dist/types/modules/excel/xlsx/xform/book/defined-name-xform.d.ts +6 -5
  334. package/dist/types/modules/excel/xlsx/xform/book/external-link-xform.d.ts +84 -0
  335. package/dist/types/modules/excel/xlsx/xform/book/external-reference-xform.d.ts +17 -0
  336. package/dist/types/modules/excel/xlsx/xform/book/workbook-calc-properties-xform.d.ts +3 -0
  337. package/dist/types/modules/excel/xlsx/xform/book/workbook-protection-xform.d.ts +20 -0
  338. package/dist/types/modules/excel/xlsx/xform/core/metadata-xform.d.ts +56 -0
  339. package/dist/types/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.d.ts +26 -0
  340. package/dist/types/modules/excel/xlsx/xform/sheet/cell-xform.d.ts +1 -1
  341. package/dist/types/modules/excel/xlsx/xform/sheet/ignored-errors-xform.d.ts +21 -0
  342. package/dist/types/modules/excel/xlsx/xlsx.browser.d.ts +172 -13
  343. package/dist/types/modules/excel/xlsx/xlsx.d.ts +7 -4
  344. package/dist/types/modules/formula/compile/address-utils.d.ts +62 -0
  345. package/dist/types/modules/formula/compile/binder.d.ts +42 -0
  346. package/dist/types/modules/formula/compile/bound-ast.d.ts +230 -0
  347. package/dist/types/modules/formula/compile/compiled-formula.d.ts +137 -0
  348. package/dist/types/modules/formula/compile/dependency-analysis.d.ts +93 -0
  349. package/dist/types/modules/formula/compile/structured-ref-utils.d.ts +93 -0
  350. package/dist/types/modules/formula/default-syntax-probe.d.ts +79 -0
  351. package/dist/types/modules/formula/functions/_date-context.d.ts +4 -0
  352. package/dist/types/modules/formula/functions/_shared.d.ts +121 -0
  353. package/dist/types/modules/formula/functions/conditional.d.ts +27 -0
  354. package/dist/types/modules/formula/functions/database.d.ts +37 -0
  355. package/dist/types/modules/formula/functions/date.d.ts +61 -0
  356. package/dist/types/modules/formula/functions/dynamic-array.d.ts +23 -0
  357. package/dist/types/modules/formula/functions/engineering.d.ts +57 -0
  358. package/dist/types/modules/formula/functions/financial.d.ts +202 -0
  359. package/dist/types/modules/formula/functions/lookup.d.ts +18 -0
  360. package/dist/types/modules/formula/functions/math.d.ts +114 -0
  361. package/dist/types/modules/formula/functions/statistical.d.ts +193 -0
  362. package/dist/types/modules/formula/functions/text.d.ts +86 -0
  363. package/dist/types/modules/formula/host-registry.d.ts +53 -0
  364. package/dist/types/modules/formula/index.d.ts +39 -0
  365. package/dist/types/modules/formula/install.d.ts +62 -0
  366. package/dist/types/modules/formula/integration/apply-writeback-plan.d.ts +26 -0
  367. package/dist/types/modules/formula/integration/calculate-formulas-impl.d.ts +30 -0
  368. package/dist/types/modules/formula/integration/calculate-formulas.d.ts +67 -0
  369. package/dist/types/modules/formula/integration/formula-instance.d.ts +64 -0
  370. package/dist/types/modules/formula/integration/workbook-adapter.d.ts +26 -0
  371. package/dist/types/modules/formula/integration/workbook-snapshot.d.ts +267 -0
  372. package/dist/types/modules/formula/materialize/build-writeback-plan.d.ts +34 -0
  373. package/dist/types/modules/formula/materialize/spill-engine.d.ts +9 -0
  374. package/dist/types/modules/formula/materialize/types.d.ts +179 -0
  375. package/dist/types/modules/formula/materialize/writeback-plan.d.ts +167 -0
  376. package/dist/types/modules/formula/runtime/evaluator.d.ts +151 -0
  377. package/dist/types/modules/formula/runtime/function-registry.d.ts +47 -0
  378. package/dist/types/modules/formula/runtime/values.d.ts +211 -0
  379. package/dist/types/modules/formula/syntax/ast.d.ts +129 -0
  380. package/dist/types/modules/formula/syntax/parser.d.ts +18 -0
  381. package/dist/types/modules/formula/syntax/token-types.d.ts +153 -0
  382. package/dist/types/modules/formula/syntax/tokenizer.d.ts +10 -0
  383. package/package.json +28 -28
@@ -0,0 +1,3488 @@
1
+ "use strict";
2
+ /**
3
+ * Statistical Functions
4
+ *
5
+ * Native RuntimeValue implementations.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.fnNEGBINOM_DIST = exports.fnHYPGEOM_DIST = exports.fnBINOM_INV = exports.fnBINOM_DIST_RANGE = exports.fnBINOM_DIST = exports.fnPOISSON_DIST = exports.fnMINA = exports.fnMAXA = exports.fnAVERAGEA = exports.fnFISHERINV = exports.fnFISHER = exports.fnRANK_AVG = exports.fnCOVARIANCE_S = exports.fnCOVARIANCE_P = exports.fnCONFIDENCE_T = exports.fnCONFIDENCENORM = exports.fnAVEDEV = exports.fnDEVSQ = exports.fnTRIMMEAN = exports.fnHARMEAN = exports.fnGEOMEAN = exports.fnPERMUT = exports.fnCOMBINA = exports.fnCOMBIN = exports.fnFACTDOUBLE = exports.fnFACT = exports.fnFORECAST = exports.fnSTEYX = exports.fnRSQ = exports.fnINTERCEPT = exports.fnSLOPE = exports.fnCORREL = exports.fnMODE_MULT = exports.fnMODE = exports.fnQUARTILEEXC = exports.fnQUARTILE = exports.fnPERCENTILEEXC = exports.fnPERCENTILE = exports.fnNORMINV = exports.fnNORMSINV = exports.fnNORMDIST = exports.fnNORMSDIST = exports.fnVARP = exports.fnVAR = exports.fnSTDEVP = exports.fnSTDEV = exports.fnRANK = exports.fnSMALL = exports.fnLARGE = exports.fnMEDIAN = void 0;
9
+ exports.fnCHISQ_TEST = exports.fnT_TEST = exports.fnF_TEST = exports.fnZ_TEST = exports.fnPROB = exports.fnPERCENTRANK_EXC = exports.fnPERCENTRANK_INC = exports.fnPERCENTRANK = exports.fnKURT = exports.fnSKEW_P = exports.fnSKEW = exports.fnF_INV_RT = exports.fnF_DIST_RT = exports.fnLOGEST = exports.fnLINEST = exports.fnTREND = exports.fnGROWTH = exports.fnFREQUENCY = exports.fnSTANDARDIZE = exports.fnERFC = exports.fnERF = exports.fnGAUSS = exports.fnPHI = exports.fnLOGNORM_INV = exports.fnLOGNORM_DIST = exports.fnWEIBULL_DIST = exports.fnEXPON_DIST = exports.fnGAMMA_INV = exports.fnGAMMA_DIST = exports.fnGAMMALN = exports.fnGAMMA = exports.fnBETA_INV = exports.fnBETA_DIST = exports.fnT_INV_2T = exports.fnT_DIST_RT = exports.fnT_DIST_2T = exports.fnT_INV = exports.fnT_DIST = exports.fnF_INV = exports.fnF_DIST = exports.fnCHISQ_INV_RT = exports.fnCHISQ_DIST_RT = exports.fnCHISQ_INV = exports.fnCHISQ_DIST = void 0;
10
+ const values_1 = require("../runtime/values");
11
+ const _shared_1 = require("./_shared");
12
+ /**
13
+ * Extract a boolean from a single arg. Returns the boolean or ErrorValue.
14
+ */
15
+ function boolArg(args, idx) {
16
+ const rv = (0, values_1.toBooleanRV)((0, values_1.topLeft)(args[idx]));
17
+ if (rv.kind === 4 /* RVKind.Error */) {
18
+ return { ok: false, error: rv };
19
+ }
20
+ return { ok: true, value: rv.value };
21
+ }
22
+ /**
23
+ * Check if an arg is an array.
24
+ */
25
+ function isArrayArg(arg) {
26
+ return arg.kind === 5 /* RVKind.Array */;
27
+ }
28
+ // ============================================================================
29
+ // MEDIAN, LARGE, SMALL, RANK
30
+ // ============================================================================
31
+ /**
32
+ * Quickselect: returns the k-th smallest element (0-indexed) of `arr`
33
+ * in-place, in expected O(n) time.
34
+ *
35
+ * Uses Hoare partitioning with a "median of three" pivot choice for
36
+ * resilience against already-sorted and adversarial inputs. The input
37
+ * array is reorganised around the pivot — callers that need the original
38
+ * order must pass a copy.
39
+ */
40
+ function quickselect(arr, k) {
41
+ let lo = 0;
42
+ let hi = arr.length - 1;
43
+ while (lo < hi) {
44
+ // median-of-three pivot
45
+ const mid = (lo + hi) >> 1;
46
+ const a = arr[lo];
47
+ const b = arr[mid];
48
+ const c = arr[hi];
49
+ const pivot = a < b ? (b < c ? b : a < c ? c : a) : a < c ? a : b < c ? c : b;
50
+ let i = lo;
51
+ let j = hi;
52
+ while (i <= j) {
53
+ while (arr[i] < pivot) {
54
+ i++;
55
+ }
56
+ while (arr[j] > pivot) {
57
+ j--;
58
+ }
59
+ if (i <= j) {
60
+ const t = arr[i];
61
+ arr[i] = arr[j];
62
+ arr[j] = t;
63
+ i++;
64
+ j--;
65
+ }
66
+ }
67
+ if (k <= j) {
68
+ hi = j;
69
+ }
70
+ else if (k >= i) {
71
+ lo = i;
72
+ }
73
+ else {
74
+ // pivot settled at k
75
+ return arr[k];
76
+ }
77
+ }
78
+ return arr[k];
79
+ }
80
+ const fnMEDIAN = args => {
81
+ const nums = (0, _shared_1.flattenNumbers)(args);
82
+ const err = (0, _shared_1.firstError)(nums);
83
+ if (err) {
84
+ return err;
85
+ }
86
+ if (nums.length === 0) {
87
+ return values_1.ERRORS.NUM;
88
+ }
89
+ const values = nums.map(n => n.value);
90
+ const n = values.length;
91
+ const mid = n >> 1;
92
+ if (n % 2 !== 0) {
93
+ return (0, values_1.rvNumber)(quickselect(values, mid));
94
+ }
95
+ // Even count: average of (n/2 − 1)-th and (n/2)-th smallest. Use
96
+ // quickselect twice — but the second search can be limited to the upper
97
+ // half produced by the first call, since quickselect leaves that region
98
+ // sorted w.r.t. the pivot.
99
+ const hi = quickselect(values, mid);
100
+ // After selecting index `mid`, every element at position < mid is ≤ hi.
101
+ // The lower of the two middle values is the max of that prefix.
102
+ let lo = Number.NEGATIVE_INFINITY;
103
+ for (let i = 0; i < mid; i++) {
104
+ if (values[i] > lo) {
105
+ lo = values[i];
106
+ }
107
+ }
108
+ return (0, values_1.rvNumber)((lo + hi) / 2);
109
+ };
110
+ exports.fnMEDIAN = fnMEDIAN;
111
+ const fnLARGE = args => {
112
+ const nums = (0, _shared_1.flattenNumbers)([args[0]]);
113
+ const err = (0, _shared_1.firstError)(nums);
114
+ if (err) {
115
+ return err;
116
+ }
117
+ const values = nums.map(n => n.value);
118
+ // k can be an array (Excel broadcasts); when it is, return an array
119
+ // with the same shape where each cell holds LARGE at that k.
120
+ if (args[1].kind === 5 /* RVKind.Array */) {
121
+ const kArr = args[1];
122
+ const outRows = [];
123
+ for (const row of kArr.rows) {
124
+ const outRow = [];
125
+ for (const cell of row) {
126
+ if (cell.kind === 4 /* RVKind.Error */) {
127
+ outRow.push(cell);
128
+ continue;
129
+ }
130
+ const kn = (0, values_1.toNumberRV)(cell);
131
+ if (kn.kind === 4 /* RVKind.Error */) {
132
+ outRow.push(kn);
133
+ continue;
134
+ }
135
+ const kInt = Math.floor(kn.value);
136
+ if (kInt < 1 || kInt > values.length) {
137
+ outRow.push(values_1.ERRORS.NUM);
138
+ continue;
139
+ }
140
+ // k-th largest == (n − k)-th smallest. Use a copy — quickselect
141
+ // mutates the array it works on, and we need a fresh view for
142
+ // every cell in the output.
143
+ outRow.push((0, values_1.rvNumber)(quickselect(values.slice(), values.length - kInt)));
144
+ }
145
+ outRows.push(outRow);
146
+ }
147
+ return (0, values_1.rvArray)(outRows);
148
+ }
149
+ const k = (0, _shared_1.argToNumber)(args[1]);
150
+ if (k.kind === 4 /* RVKind.Error */) {
151
+ return k;
152
+ }
153
+ const kInt = Math.floor(k.value);
154
+ if (kInt < 1 || kInt > values.length) {
155
+ return values_1.ERRORS.NUM;
156
+ }
157
+ return (0, values_1.rvNumber)(quickselect(values, values.length - kInt));
158
+ };
159
+ exports.fnLARGE = fnLARGE;
160
+ const fnSMALL = args => {
161
+ const nums = (0, _shared_1.flattenNumbers)([args[0]]);
162
+ const err = (0, _shared_1.firstError)(nums);
163
+ if (err) {
164
+ return err;
165
+ }
166
+ const values = nums.map(n => n.value);
167
+ if (args[1].kind === 5 /* RVKind.Array */) {
168
+ const kArr = args[1];
169
+ const outRows = [];
170
+ for (const row of kArr.rows) {
171
+ const outRow = [];
172
+ for (const cell of row) {
173
+ if (cell.kind === 4 /* RVKind.Error */) {
174
+ outRow.push(cell);
175
+ continue;
176
+ }
177
+ const kn = (0, values_1.toNumberRV)(cell);
178
+ if (kn.kind === 4 /* RVKind.Error */) {
179
+ outRow.push(kn);
180
+ continue;
181
+ }
182
+ const kInt = Math.floor(kn.value);
183
+ if (kInt < 1 || kInt > values.length) {
184
+ outRow.push(values_1.ERRORS.NUM);
185
+ continue;
186
+ }
187
+ outRow.push((0, values_1.rvNumber)(quickselect(values.slice(), kInt - 1)));
188
+ }
189
+ outRows.push(outRow);
190
+ }
191
+ return (0, values_1.rvArray)(outRows);
192
+ }
193
+ const k = (0, _shared_1.argToNumber)(args[1]);
194
+ if (k.kind === 4 /* RVKind.Error */) {
195
+ return k;
196
+ }
197
+ const kInt = Math.floor(k.value);
198
+ if (kInt < 1 || kInt > values.length) {
199
+ return values_1.ERRORS.NUM;
200
+ }
201
+ return (0, values_1.rvNumber)(quickselect(values, kInt - 1));
202
+ };
203
+ exports.fnSMALL = fnSMALL;
204
+ const fnRANK = args => {
205
+ const num = (0, _shared_1.argToNumber)(args[0]);
206
+ if (num.kind === 4 /* RVKind.Error */) {
207
+ return num;
208
+ }
209
+ const nums = (0, _shared_1.flattenNumbers)([args[1]]);
210
+ const err = (0, _shared_1.firstError)(nums);
211
+ if (err) {
212
+ return err;
213
+ }
214
+ const orderRV = args.length > 2 ? (0, _shared_1.argToNumber)(args[2]) : (0, values_1.rvNumber)(0);
215
+ if (orderRV.kind === 4 /* RVKind.Error */) {
216
+ return orderRV;
217
+ }
218
+ const order = orderRV.value;
219
+ const sorted = order === 0
220
+ ? nums
221
+ .map(n => n.value)
222
+ .slice()
223
+ .sort((a, b) => b - a)
224
+ : nums
225
+ .map(n => n.value)
226
+ .slice()
227
+ .sort((a, b) => a - b);
228
+ const idx = sorted.indexOf(num.value);
229
+ return idx === -1 ? values_1.ERRORS.NA : (0, values_1.rvNumber)(idx + 1);
230
+ };
231
+ exports.fnRANK = fnRANK;
232
+ // ============================================================================
233
+ // STDEV, STDEVP, VAR, VARP
234
+ // ============================================================================
235
+ /**
236
+ * Compute mean and sum of squared deviations from mean. Used by the
237
+ * STDEV/STDEVP/VAR/VARP family to share a single pass through the data.
238
+ * Returns `null` when there is no data at all (callers decide whether that
239
+ * should be `#DIV/0!` or zero given the sample/population convention).
240
+ */
241
+ function computeMeanAndSumSq(nums) {
242
+ const n = nums.length;
243
+ if (n === 0) {
244
+ return null;
245
+ }
246
+ let sum = 0;
247
+ for (const v of nums) {
248
+ sum += v;
249
+ }
250
+ const mean = sum / n;
251
+ let sumSq = 0;
252
+ for (const v of nums) {
253
+ sumSq += (v - mean) ** 2;
254
+ }
255
+ return { n, mean, sumSq };
256
+ }
257
+ /** Resolve {args} to `number[]` or an error. Shared by STDEV/VAR family. */
258
+ function toNumberArray(args) {
259
+ const rawNums = (0, _shared_1.flattenNumbers)(args);
260
+ const err = (0, _shared_1.firstError)(rawNums);
261
+ if (err) {
262
+ return err;
263
+ }
264
+ return rawNums.map(n => n.value);
265
+ }
266
+ const fnSTDEV = args => {
267
+ const nums = toNumberArray(args);
268
+ if (!Array.isArray(nums)) {
269
+ return nums;
270
+ }
271
+ const stats = computeMeanAndSumSq(nums);
272
+ if (!stats || stats.n < 2) {
273
+ return values_1.ERRORS.DIV0;
274
+ }
275
+ return (0, values_1.rvNumber)(Math.sqrt(stats.sumSq / (stats.n - 1)));
276
+ };
277
+ exports.fnSTDEV = fnSTDEV;
278
+ const fnSTDEVP = args => {
279
+ const nums = toNumberArray(args);
280
+ if (!Array.isArray(nums)) {
281
+ return nums;
282
+ }
283
+ const stats = computeMeanAndSumSq(nums);
284
+ if (!stats) {
285
+ return values_1.ERRORS.DIV0;
286
+ }
287
+ return (0, values_1.rvNumber)(Math.sqrt(stats.sumSq / stats.n));
288
+ };
289
+ exports.fnSTDEVP = fnSTDEVP;
290
+ const fnVAR = args => {
291
+ const nums = toNumberArray(args);
292
+ if (!Array.isArray(nums)) {
293
+ return nums;
294
+ }
295
+ const stats = computeMeanAndSumSq(nums);
296
+ if (!stats || stats.n < 2) {
297
+ return values_1.ERRORS.DIV0;
298
+ }
299
+ return (0, values_1.rvNumber)(stats.sumSq / (stats.n - 1));
300
+ };
301
+ exports.fnVAR = fnVAR;
302
+ const fnVARP = args => {
303
+ const nums = toNumberArray(args);
304
+ if (!Array.isArray(nums)) {
305
+ return nums;
306
+ }
307
+ const stats = computeMeanAndSumSq(nums);
308
+ if (!stats) {
309
+ return values_1.ERRORS.DIV0;
310
+ }
311
+ return (0, values_1.rvNumber)(stats.sumSq / stats.n);
312
+ };
313
+ exports.fnVARP = fnVARP;
314
+ // ============================================================================
315
+ // Advanced Statistical Functions — private math helpers
316
+ // ============================================================================
317
+ // Peter Acklam's rational approximation for the standard normal inverse CDF.
318
+ // Accuracy: |error| < 1.15e-9 across the full range (0, 1).
319
+ function normSInv(p) {
320
+ if (p <= 0 || p >= 1) {
321
+ return NaN;
322
+ }
323
+ if (p < 0.5) {
324
+ return -normSInv(1 - p);
325
+ }
326
+ // Coefficients for rational approximation
327
+ const a1 = -3.969683028665376e1;
328
+ const a2 = 2.209460984245205e2;
329
+ const a3 = -2.759285104469687e2;
330
+ const a4 = 1.38357751867269e2;
331
+ const a5 = -3.066479806614716e1;
332
+ const a6 = 2.506628277459239;
333
+ const b1 = -5.447609879822406e1;
334
+ const b2 = 1.615858368580409e2;
335
+ const b3 = -1.556989798598866e2;
336
+ const b4 = 6.680131188771972e1;
337
+ const b5 = -1.328068155288572e1;
338
+ const c1 = -7.784894002430293e-3;
339
+ const c2 = -3.223964580411365e-1;
340
+ const c3 = -2.400758277161838;
341
+ const c4 = -2.549732539343734;
342
+ const c5 = 4.374664141464968;
343
+ const c6 = 2.938163982698783;
344
+ const d1 = 7.784695709041462e-3;
345
+ const d2 = 3.224671290700398e-1;
346
+ const d3 = 2.445134137142996;
347
+ const d4 = 3.754408661907416;
348
+ const pLow = 0.02425;
349
+ const pHigh = 1 - pLow;
350
+ if (p < pLow) {
351
+ // Rational approximation for lower region
352
+ const q = Math.sqrt(-2 * Math.log(p));
353
+ return ((((((c1 * q + c2) * q + c3) * q + c4) * q + c5) * q + c6) /
354
+ ((((d1 * q + d2) * q + d3) * q + d4) * q + 1));
355
+ }
356
+ if (p <= pHigh) {
357
+ // Rational approximation for central region
358
+ const q = p - 0.5;
359
+ const r = q * q;
360
+ return (((((((a1 * r + a2) * r + a3) * r + a4) * r + a5) * r + a6) * q) /
361
+ (((((b1 * r + b2) * r + b3) * r + b4) * r + b5) * r + 1));
362
+ }
363
+ // Upper region — use symmetry
364
+ const q = Math.sqrt(-2 * Math.log(1 - p));
365
+ return -((((((c1 * q + c2) * q + c3) * q + c4) * q + c5) * q + c6) /
366
+ ((((d1 * q + d2) * q + d3) * q + d4) * q + 1));
367
+ }
368
+ // Standard normal CDF approximation (Abramowitz & Stegun 7.1.26). The
369
+ // approximation has max error ~7.5e-8 — good enough for GAUSS/NORM.S.DIST
370
+ // but it does NOT evaluate to exactly 0.5 at x = 0 (the erf kernel leaves
371
+ // a residual ≈ 5e-10). Excel-facing callers expect symmetry around 0, so
372
+ // we short-circuit that single point.
373
+ function normSDist(x) {
374
+ if (x === 0) {
375
+ return 0.5;
376
+ }
377
+ const a1 = 0.254829592;
378
+ const a2 = -0.284496736;
379
+ const a3 = 1.421413741;
380
+ const a4 = -1.453152027;
381
+ const a5 = 1.061405429;
382
+ const p = 0.3275911;
383
+ const sign = x < 0 ? -1 : 1;
384
+ x = Math.abs(x) / Math.SQRT2;
385
+ const t = 1.0 / (1.0 + p * x);
386
+ const y = 1.0 - ((((a5 * t + a4) * t + a3) * t + a2) * t + a1) * t * Math.exp(-x * x);
387
+ return 0.5 * (1.0 + sign * y);
388
+ }
389
+ // Standard normal PDF
390
+ function normSPdf(x) {
391
+ return Math.exp(-0.5 * x * x) / Math.sqrt(2 * Math.PI);
392
+ }
393
+ // ============================================================================
394
+ // Normal Distribution Functions
395
+ // ============================================================================
396
+ const fnNORMSDIST = args => {
397
+ const z = (0, _shared_1.argToNumber)(args[0]);
398
+ if (z.kind === 4 /* RVKind.Error */) {
399
+ return z;
400
+ }
401
+ // Legacy NORM.S.DIST compatibility: single arg = CDF
402
+ if (args.length > 1) {
403
+ const cum = boolArg(args, 1);
404
+ if (!cum.ok) {
405
+ return cum.error;
406
+ }
407
+ return (0, values_1.rvNumber)(cum.value ? normSDist(z.value) : normSPdf(z.value));
408
+ }
409
+ return (0, values_1.rvNumber)(normSDist(z.value));
410
+ };
411
+ exports.fnNORMSDIST = fnNORMSDIST;
412
+ const fnNORMDIST = args => {
413
+ const x = (0, _shared_1.argToNumber)(args[0]);
414
+ if (x.kind === 4 /* RVKind.Error */) {
415
+ return x;
416
+ }
417
+ const mean = (0, _shared_1.argToNumber)(args[1]);
418
+ if (mean.kind === 4 /* RVKind.Error */) {
419
+ return mean;
420
+ }
421
+ const stddev = (0, _shared_1.argToNumber)(args[2]);
422
+ if (stddev.kind === 4 /* RVKind.Error */) {
423
+ return stddev;
424
+ }
425
+ if (stddev.value <= 0) {
426
+ return values_1.ERRORS.NUM;
427
+ }
428
+ const cum = boolArg(args, 3);
429
+ if (!cum.ok) {
430
+ return cum.error;
431
+ }
432
+ const zVal = (x.value - mean.value) / stddev.value;
433
+ if (cum.value) {
434
+ return (0, values_1.rvNumber)(normSDist(zVal));
435
+ }
436
+ return (0, values_1.rvNumber)(normSPdf(zVal) / stddev.value);
437
+ };
438
+ exports.fnNORMDIST = fnNORMDIST;
439
+ const fnNORMSINV = args => {
440
+ const p = (0, _shared_1.argToNumber)(args[0]);
441
+ if (p.kind === 4 /* RVKind.Error */) {
442
+ return p;
443
+ }
444
+ if (p.value <= 0 || p.value >= 1) {
445
+ return values_1.ERRORS.NUM;
446
+ }
447
+ return (0, values_1.rvNumber)(normSInv(p.value));
448
+ };
449
+ exports.fnNORMSINV = fnNORMSINV;
450
+ const fnNORMINV = args => {
451
+ const p = (0, _shared_1.argToNumber)(args[0]);
452
+ if (p.kind === 4 /* RVKind.Error */) {
453
+ return p;
454
+ }
455
+ const mean = (0, _shared_1.argToNumber)(args[1]);
456
+ if (mean.kind === 4 /* RVKind.Error */) {
457
+ return mean;
458
+ }
459
+ const stddev = (0, _shared_1.argToNumber)(args[2]);
460
+ if (stddev.kind === 4 /* RVKind.Error */) {
461
+ return stddev;
462
+ }
463
+ if (p.value <= 0 || p.value >= 1 || stddev.value <= 0) {
464
+ return values_1.ERRORS.NUM;
465
+ }
466
+ return (0, values_1.rvNumber)(mean.value + stddev.value * normSInv(p.value));
467
+ };
468
+ exports.fnNORMINV = fnNORMINV;
469
+ // ============================================================================
470
+ // PERCENTILE, QUARTILE, MODE
471
+ // ============================================================================
472
+ const fnPERCENTILE = args => {
473
+ const nums = (0, _shared_1.flattenNumbers)([args[0]])
474
+ .filter((v) => v.kind === 1 /* RVKind.Number */)
475
+ .map(n => n.value);
476
+ const k = (0, _shared_1.argToNumber)(args[1]);
477
+ if (k.kind === 4 /* RVKind.Error */) {
478
+ return k;
479
+ }
480
+ if (k.value < 0 || k.value > 1 || nums.length === 0) {
481
+ return values_1.ERRORS.NUM;
482
+ }
483
+ nums.sort((a, b) => a - b);
484
+ const n = nums.length;
485
+ if (n === 1) {
486
+ return (0, values_1.rvNumber)(nums[0]);
487
+ }
488
+ const rank = k.value * (n - 1);
489
+ const lower = Math.floor(rank);
490
+ const upper = Math.ceil(rank);
491
+ const frac = rank - lower;
492
+ return (0, values_1.rvNumber)(nums[lower] + frac * (nums[upper] - nums[lower]));
493
+ };
494
+ exports.fnPERCENTILE = fnPERCENTILE;
495
+ const fnPERCENTILEEXC = args => {
496
+ const nums = (0, _shared_1.flattenNumbers)([args[0]])
497
+ .filter((v) => v.kind === 1 /* RVKind.Number */)
498
+ .map(n => n.value);
499
+ const k = (0, _shared_1.argToNumber)(args[1]);
500
+ if (k.kind === 4 /* RVKind.Error */) {
501
+ return k;
502
+ }
503
+ const n = nums.length;
504
+ if (k.value <= 0 || k.value >= 1 || n === 0) {
505
+ return values_1.ERRORS.NUM;
506
+ }
507
+ if (k.value < 1 / (n + 1) || k.value > n / (n + 1)) {
508
+ return values_1.ERRORS.NUM;
509
+ }
510
+ nums.sort((a, b) => a - b);
511
+ const rank = k.value * (n + 1) - 1;
512
+ const lower = Math.floor(rank);
513
+ const upper = Math.ceil(rank);
514
+ const frac = rank - lower;
515
+ return (0, values_1.rvNumber)(nums[Math.max(0, lower)] + frac * (nums[Math.min(n - 1, upper)] - nums[Math.max(0, lower)]));
516
+ };
517
+ exports.fnPERCENTILEEXC = fnPERCENTILEEXC;
518
+ const fnQUARTILE = args => {
519
+ const quart = (0, _shared_1.argToNumber)(args[1]);
520
+ if (quart.kind === 4 /* RVKind.Error */) {
521
+ return quart;
522
+ }
523
+ if (quart.value < 0 || quart.value > 4) {
524
+ return values_1.ERRORS.NUM;
525
+ }
526
+ return (0, exports.fnPERCENTILE)([args[0], (0, values_1.rvNumber)(quart.value / 4)]);
527
+ };
528
+ exports.fnQUARTILE = fnQUARTILE;
529
+ const fnQUARTILEEXC = args => {
530
+ const quart = (0, _shared_1.argToNumber)(args[1]);
531
+ if (quart.kind === 4 /* RVKind.Error */) {
532
+ return quart;
533
+ }
534
+ if (quart.value < 1 || quart.value > 3) {
535
+ return values_1.ERRORS.NUM;
536
+ }
537
+ return (0, exports.fnPERCENTILEEXC)([args[0], (0, values_1.rvNumber)(quart.value / 4)]);
538
+ };
539
+ exports.fnQUARTILEEXC = fnQUARTILEEXC;
540
+ const fnMODE = args => {
541
+ const all = (0, _shared_1.flattenNumbers)(args);
542
+ const err = (0, _shared_1.firstError)(all);
543
+ if (err) {
544
+ return err;
545
+ }
546
+ const nums = all.map(n => n.value);
547
+ if (nums.length === 0) {
548
+ return values_1.ERRORS.NA;
549
+ }
550
+ const counts = new Map();
551
+ let maxCount = 0;
552
+ let mode = nums[0];
553
+ for (const n of nums) {
554
+ const c = (counts.get(n) ?? 0) + 1;
555
+ counts.set(n, c);
556
+ if (c > maxCount) {
557
+ maxCount = c;
558
+ mode = n;
559
+ }
560
+ }
561
+ return maxCount > 1 ? (0, values_1.rvNumber)(mode) : values_1.ERRORS.NA;
562
+ };
563
+ exports.fnMODE = fnMODE;
564
+ /**
565
+ * MODE.MULT — returns a vertical array of every mode (dynamic array).
566
+ * When the dataset is multimodal Excel spills all of them; for a single
567
+ * mode it behaves like MODE.SNGL.
568
+ */
569
+ const fnMODE_MULT = args => {
570
+ const all = (0, _shared_1.flattenNumbers)(args);
571
+ const err = (0, _shared_1.firstError)(all);
572
+ if (err) {
573
+ return err;
574
+ }
575
+ const nums = all.map(n => n.value);
576
+ if (nums.length === 0) {
577
+ return values_1.ERRORS.NA;
578
+ }
579
+ const counts = new Map();
580
+ for (const n of nums) {
581
+ counts.set(n, (counts.get(n) ?? 0) + 1);
582
+ }
583
+ let maxCount = 0;
584
+ for (const c of counts.values()) {
585
+ if (c > maxCount) {
586
+ maxCount = c;
587
+ }
588
+ }
589
+ if (maxCount < 2) {
590
+ return values_1.ERRORS.NA;
591
+ }
592
+ // Preserve first-occurrence order as Excel does (not sorted).
593
+ const seen = new Set();
594
+ const modes = [];
595
+ for (const n of nums) {
596
+ if (!seen.has(n) && counts.get(n) === maxCount) {
597
+ seen.add(n);
598
+ modes.push(n);
599
+ }
600
+ }
601
+ return (0, values_1.rvArray)(modes.map(m => [(0, values_1.rvNumber)(m)]));
602
+ };
603
+ exports.fnMODE_MULT = fnMODE_MULT;
604
+ // ============================================================================
605
+ // Paired-array functions: CORREL, SLOPE, INTERCEPT, RSQ, FORECAST
606
+ // ============================================================================
607
+ /**
608
+ * Extract matching pairs of numbers from two array arguments, filtering to
609
+ * numeric cells only (matching Excel's CORREL/SLOPE/INTERCEPT conventions).
610
+ * Returns the shorter prefix-length pair aligned by position.
611
+ */
612
+ function pairedNumbers(args, aIdx, bIdx) {
613
+ const flatA = (0, _shared_1.flattenNumbers)([args[aIdx]]);
614
+ const errA = (0, _shared_1.firstError)(flatA);
615
+ if (errA) {
616
+ return errA;
617
+ }
618
+ const flatB = (0, _shared_1.flattenNumbers)([args[bIdx]]);
619
+ const errB = (0, _shared_1.firstError)(flatB);
620
+ if (errB) {
621
+ return errB;
622
+ }
623
+ const xs = flatA.filter((v) => v.kind === 1 /* RVKind.Number */).map(n => n.value);
624
+ const ys = flatB.filter((v) => v.kind === 1 /* RVKind.Number */).map(n => n.value);
625
+ const n = Math.min(xs.length, ys.length);
626
+ return { xs: xs.slice(0, n), ys: ys.slice(0, n) };
627
+ }
628
+ function pairedSums(xs, ys) {
629
+ const n = xs.length;
630
+ if (n === 0) {
631
+ return null;
632
+ }
633
+ let sumX = 0;
634
+ let sumY = 0;
635
+ for (let i = 0; i < n; i++) {
636
+ sumX += xs[i];
637
+ sumY += ys[i];
638
+ }
639
+ const meanX = sumX / n;
640
+ const meanY = sumY / n;
641
+ let sxy = 0;
642
+ let sxx = 0;
643
+ let syy = 0;
644
+ for (let i = 0; i < n; i++) {
645
+ const dx = xs[i] - meanX;
646
+ const dy = ys[i] - meanY;
647
+ sxy += dx * dy;
648
+ sxx += dx * dx;
649
+ syy += dy * dy;
650
+ }
651
+ return { n, meanX, meanY, sxy, sxx, syy };
652
+ }
653
+ const fnCORREL = args => {
654
+ const paired = pairedNumbers(args, 0, 1);
655
+ if ("code" in paired) {
656
+ return paired;
657
+ }
658
+ const { xs, ys } = paired;
659
+ const s = pairedSums(xs, ys);
660
+ if (!s || s.n < 2) {
661
+ return values_1.ERRORS.DIV0;
662
+ }
663
+ const denom = Math.sqrt(s.sxx * s.syy);
664
+ return denom === 0 ? values_1.ERRORS.DIV0 : (0, values_1.rvNumber)(s.sxy / denom);
665
+ };
666
+ exports.fnCORREL = fnCORREL;
667
+ const fnSLOPE = args => {
668
+ // SLOPE(known_y, known_x) — note the argument order (y first, x second).
669
+ const paired = pairedNumbers(args, 0, 1);
670
+ if ("code" in paired) {
671
+ return paired;
672
+ }
673
+ const { xs: ys, ys: xs } = paired;
674
+ const s = pairedSums(xs, ys);
675
+ if (!s || s.n < 2) {
676
+ return values_1.ERRORS.DIV0;
677
+ }
678
+ return s.sxx === 0 ? values_1.ERRORS.DIV0 : (0, values_1.rvNumber)(s.sxy / s.sxx);
679
+ };
680
+ exports.fnSLOPE = fnSLOPE;
681
+ const fnINTERCEPT = args => {
682
+ const paired = pairedNumbers(args, 0, 1);
683
+ if ("code" in paired) {
684
+ return paired;
685
+ }
686
+ const { xs: ys, ys: xs } = paired;
687
+ const s = pairedSums(xs, ys);
688
+ if (!s || s.n < 2) {
689
+ return values_1.ERRORS.DIV0;
690
+ }
691
+ if (s.sxx === 0) {
692
+ return values_1.ERRORS.DIV0;
693
+ }
694
+ const slope = s.sxy / s.sxx;
695
+ return (0, values_1.rvNumber)(s.meanY - slope * s.meanX);
696
+ };
697
+ exports.fnINTERCEPT = fnINTERCEPT;
698
+ const fnRSQ = args => {
699
+ const r = (0, exports.fnCORREL)(args);
700
+ if ((0, values_1.isError)(r)) {
701
+ return r;
702
+ }
703
+ return (0, values_1.rvNumber)(r.value ** 2);
704
+ };
705
+ exports.fnRSQ = fnRSQ;
706
+ /**
707
+ * STEYX(known_y, known_x) — standard error of the predicted y-value for
708
+ * each x in a regression. Matches Excel's definition:
709
+ * SE = sqrt((1/(n-2)) × (S_yy − S_xy² / S_xx))
710
+ * where S_xx, S_yy, S_xy are centred sums of squares / cross-product.
711
+ */
712
+ const fnSTEYX = args => {
713
+ // STEYX(known_y, known_x) — y-first ordering, like SLOPE/INTERCEPT.
714
+ const paired = pairedNumbers(args, 0, 1);
715
+ if ("code" in paired) {
716
+ return paired;
717
+ }
718
+ const { xs: ys, ys: xs } = paired;
719
+ const s = pairedSums(xs, ys);
720
+ if (!s || s.n < 3) {
721
+ return values_1.ERRORS.DIV0;
722
+ }
723
+ if (s.sxx === 0) {
724
+ return values_1.ERRORS.DIV0;
725
+ }
726
+ const numer = s.syy - (s.sxy * s.sxy) / s.sxx;
727
+ if (numer < 0) {
728
+ // Floating-point noise when the regression is essentially perfect.
729
+ return (0, values_1.rvNumber)(0);
730
+ }
731
+ return (0, values_1.rvNumber)(Math.sqrt(numer / (s.n - 2)));
732
+ };
733
+ exports.fnSTEYX = fnSTEYX;
734
+ const fnFORECAST = args => {
735
+ const x = (0, _shared_1.argToNumber)(args[0]);
736
+ if (x.kind === 4 /* RVKind.Error */) {
737
+ return x;
738
+ }
739
+ // FORECAST(x, known_y, known_x) — same y-first argument order as SLOPE.
740
+ const paired = pairedNumbers(args, 1, 2);
741
+ if ("code" in paired) {
742
+ return paired;
743
+ }
744
+ const { xs: ys, ys: xs } = paired;
745
+ const s = pairedSums(xs, ys);
746
+ if (!s || s.n < 2) {
747
+ return values_1.ERRORS.DIV0;
748
+ }
749
+ if (s.sxx === 0) {
750
+ return values_1.ERRORS.DIV0;
751
+ }
752
+ const slope = s.sxy / s.sxx;
753
+ const intercept = s.meanY - slope * s.meanX;
754
+ return (0, values_1.rvNumber)(intercept + slope * x.value);
755
+ };
756
+ exports.fnFORECAST = fnFORECAST;
757
+ // ============================================================================
758
+ // FACT, FACTDOUBLE, COMBIN, COMBINA, PERMUT
759
+ // Re-exported from math.ts — canonical definitions live there.
760
+ // ============================================================================
761
+ var math_1 = require("./math");
762
+ Object.defineProperty(exports, "fnFACT", { enumerable: true, get: function () { return math_1.fnFACT; } });
763
+ Object.defineProperty(exports, "fnFACTDOUBLE", { enumerable: true, get: function () { return math_1.fnFACTDOUBLE; } });
764
+ Object.defineProperty(exports, "fnCOMBIN", { enumerable: true, get: function () { return math_1.fnCOMBIN; } });
765
+ Object.defineProperty(exports, "fnCOMBINA", { enumerable: true, get: function () { return math_1.fnCOMBINA; } });
766
+ Object.defineProperty(exports, "fnPERMUT", { enumerable: true, get: function () { return math_1.fnPERMUT; } });
767
+ // ============================================================================
768
+ // GEOMEAN, HARMEAN, TRIMMEAN, DEVSQ, AVEDEV
769
+ // ============================================================================
770
+ const fnGEOMEAN = args => {
771
+ const rawNums = (0, _shared_1.flattenNumbers)(args);
772
+ const err = (0, _shared_1.firstError)(rawNums);
773
+ if (err) {
774
+ return err;
775
+ }
776
+ const nums = rawNums;
777
+ if (nums.length === 0) {
778
+ return values_1.ERRORS.NUM;
779
+ }
780
+ let logSum = 0;
781
+ for (const n of nums) {
782
+ if (n.value <= 0) {
783
+ return values_1.ERRORS.NUM;
784
+ }
785
+ logSum += Math.log(n.value);
786
+ }
787
+ return (0, values_1.rvNumber)(Math.exp(logSum / nums.length));
788
+ };
789
+ exports.fnGEOMEAN = fnGEOMEAN;
790
+ const fnHARMEAN = args => {
791
+ const rawNums = (0, _shared_1.flattenNumbers)(args);
792
+ const err = (0, _shared_1.firstError)(rawNums);
793
+ if (err) {
794
+ return err;
795
+ }
796
+ const nums = rawNums;
797
+ if (nums.length === 0) {
798
+ return values_1.ERRORS.NUM;
799
+ }
800
+ let recipSum = 0;
801
+ for (const n of nums) {
802
+ if (n.value <= 0) {
803
+ return values_1.ERRORS.NUM;
804
+ }
805
+ recipSum += 1 / n.value;
806
+ }
807
+ return (0, values_1.rvNumber)(nums.length / recipSum);
808
+ };
809
+ exports.fnHARMEAN = fnHARMEAN;
810
+ const fnTRIMMEAN = args => {
811
+ const all = (0, _shared_1.flattenNumbers)([args[0]]);
812
+ const err = (0, _shared_1.firstError)(all);
813
+ if (err) {
814
+ return err;
815
+ }
816
+ const nums = all.map(n => n.value);
817
+ const pct = (0, _shared_1.argToNumber)(args[1]);
818
+ if (pct.kind === 4 /* RVKind.Error */) {
819
+ return pct;
820
+ }
821
+ if (pct.value < 0 || pct.value >= 1) {
822
+ return values_1.ERRORS.NUM;
823
+ }
824
+ nums.sort((a, b) => a - b);
825
+ const trimCount = Math.floor((nums.length * pct.value) / 2);
826
+ const trimmed = nums.slice(trimCount, nums.length - trimCount);
827
+ if (trimmed.length === 0) {
828
+ return values_1.ERRORS.DIV0;
829
+ }
830
+ return (0, values_1.rvNumber)(trimmed.reduce((a, b) => a + b, 0) / trimmed.length);
831
+ };
832
+ exports.fnTRIMMEAN = fnTRIMMEAN;
833
+ const fnDEVSQ = args => {
834
+ const rawNums = (0, _shared_1.flattenNumbers)(args);
835
+ const err = (0, _shared_1.firstError)(rawNums);
836
+ if (err) {
837
+ return err;
838
+ }
839
+ const nums = rawNums;
840
+ if (nums.length === 0) {
841
+ return (0, values_1.rvNumber)(0);
842
+ }
843
+ let sum = 0;
844
+ for (const n of nums) {
845
+ sum += n.value;
846
+ }
847
+ const mean = sum / nums.length;
848
+ let result = 0;
849
+ for (const n of nums) {
850
+ result += (n.value - mean) ** 2;
851
+ }
852
+ return (0, values_1.rvNumber)(result);
853
+ };
854
+ exports.fnDEVSQ = fnDEVSQ;
855
+ const fnAVEDEV = args => {
856
+ const rawNums = (0, _shared_1.flattenNumbers)(args);
857
+ const err = (0, _shared_1.firstError)(rawNums);
858
+ if (err) {
859
+ return err;
860
+ }
861
+ const nums = rawNums;
862
+ if (nums.length === 0) {
863
+ return values_1.ERRORS.NUM;
864
+ }
865
+ let sum = 0;
866
+ for (const n of nums) {
867
+ sum += n.value;
868
+ }
869
+ const mean = sum / nums.length;
870
+ let result = 0;
871
+ for (const n of nums) {
872
+ result += Math.abs(n.value - mean);
873
+ }
874
+ return (0, values_1.rvNumber)(result / nums.length);
875
+ };
876
+ exports.fnAVEDEV = fnAVEDEV;
877
+ // ============================================================================
878
+ // CONFIDENCE, FISHER, AVERAGEA, MAXA, MINA
879
+ // ============================================================================
880
+ const fnCONFIDENCENORM = args => {
881
+ const alpha = (0, _shared_1.argToNumber)(args[0]);
882
+ if (alpha.kind === 4 /* RVKind.Error */) {
883
+ return alpha;
884
+ }
885
+ const stddev = (0, _shared_1.argToNumber)(args[1]);
886
+ if (stddev.kind === 4 /* RVKind.Error */) {
887
+ return stddev;
888
+ }
889
+ const size = (0, _shared_1.argToNumber)(args[2]);
890
+ if (size.kind === 4 /* RVKind.Error */) {
891
+ return size;
892
+ }
893
+ if (alpha.value <= 0 || alpha.value >= 1 || stddev.value <= 0 || size.value < 1) {
894
+ return values_1.ERRORS.NUM;
895
+ }
896
+ return (0, values_1.rvNumber)((normSInv(1 - alpha.value / 2) * stddev.value) / Math.sqrt(size.value));
897
+ };
898
+ exports.fnCONFIDENCENORM = fnCONFIDENCENORM;
899
+ /**
900
+ * CONFIDENCE.T — confidence interval half-width for the mean using the
901
+ * Student's t distribution (small sample / unknown population variance).
902
+ */
903
+ const fnCONFIDENCE_T = args => {
904
+ const alpha = (0, _shared_1.argToNumber)(args[0]);
905
+ if (alpha.kind === 4 /* RVKind.Error */) {
906
+ return alpha;
907
+ }
908
+ const stddev = (0, _shared_1.argToNumber)(args[1]);
909
+ if (stddev.kind === 4 /* RVKind.Error */) {
910
+ return stddev;
911
+ }
912
+ const size = (0, _shared_1.argToNumber)(args[2]);
913
+ if (size.kind === 4 /* RVKind.Error */) {
914
+ return size;
915
+ }
916
+ if (alpha.value <= 0 || alpha.value >= 1 || stddev.value <= 0 || size.value < 2) {
917
+ return values_1.ERRORS.NUM;
918
+ }
919
+ // Reuse the engine's existing T.INV.2T to pull the two-tailed critical
920
+ // value; avoids duplicating the Newton search. Excel uses df = n − 1.
921
+ const tCrit = (0, exports.fnT_INV_2T)([(0, values_1.rvNumber)(alpha.value), (0, values_1.rvNumber)(size.value - 1)]);
922
+ if ((0, values_1.isError)(tCrit)) {
923
+ return tCrit;
924
+ }
925
+ const t = tCrit.value;
926
+ return (0, values_1.rvNumber)((t * stddev.value) / Math.sqrt(size.value));
927
+ };
928
+ exports.fnCONFIDENCE_T = fnCONFIDENCE_T;
929
+ /**
930
+ * Shared helper: walk two numeric arrays element-wise, filtering to
931
+ * matching-position numeric pairs only (Excel skips rows where either
932
+ * side is non-numeric).
933
+ */
934
+ function pairedNumericValues(a, b) {
935
+ const xsAll = (0, _shared_1.flattenNumbers)([a]);
936
+ const xsErr = (0, _shared_1.firstError)(xsAll);
937
+ if (xsErr) {
938
+ return xsErr;
939
+ }
940
+ const ysAll = (0, _shared_1.flattenNumbers)([b]);
941
+ const ysErr = (0, _shared_1.firstError)(ysAll);
942
+ if (ysErr) {
943
+ return ysErr;
944
+ }
945
+ const n = Math.min(xsAll.length, ysAll.length);
946
+ const xs = [];
947
+ const ys = [];
948
+ for (let i = 0; i < n; i++) {
949
+ const x = xsAll[i];
950
+ const y = ysAll[i];
951
+ if (x.kind === 1 /* RVKind.Number */ && y.kind === 1 /* RVKind.Number */) {
952
+ xs.push(x.value);
953
+ ys.push(y.value);
954
+ }
955
+ }
956
+ return { xs, ys };
957
+ }
958
+ /** COVARIANCE.P — population covariance. */
959
+ const fnCOVARIANCE_P = args => {
960
+ const pairs = pairedNumericValues(args[0], args[1]);
961
+ if (pairs.kind === 4 /* RVKind.Error */) {
962
+ return pairs;
963
+ }
964
+ const { xs, ys } = pairs;
965
+ const n = xs.length;
966
+ if (n === 0) {
967
+ return values_1.ERRORS.DIV0;
968
+ }
969
+ let mx = 0;
970
+ let my = 0;
971
+ for (let i = 0; i < n; i++) {
972
+ mx += xs[i];
973
+ my += ys[i];
974
+ }
975
+ mx /= n;
976
+ my /= n;
977
+ let s = 0;
978
+ for (let i = 0; i < n; i++) {
979
+ s += (xs[i] - mx) * (ys[i] - my);
980
+ }
981
+ return (0, values_1.rvNumber)(s / n);
982
+ };
983
+ exports.fnCOVARIANCE_P = fnCOVARIANCE_P;
984
+ /** COVARIANCE.S — sample covariance (divide by n-1). */
985
+ const fnCOVARIANCE_S = args => {
986
+ const pairs = pairedNumericValues(args[0], args[1]);
987
+ if (pairs.kind === 4 /* RVKind.Error */) {
988
+ return pairs;
989
+ }
990
+ const { xs, ys } = pairs;
991
+ const n = xs.length;
992
+ if (n < 2) {
993
+ return values_1.ERRORS.DIV0;
994
+ }
995
+ let mx = 0;
996
+ let my = 0;
997
+ for (let i = 0; i < n; i++) {
998
+ mx += xs[i];
999
+ my += ys[i];
1000
+ }
1001
+ mx /= n;
1002
+ my /= n;
1003
+ let s = 0;
1004
+ for (let i = 0; i < n; i++) {
1005
+ s += (xs[i] - mx) * (ys[i] - my);
1006
+ }
1007
+ return (0, values_1.rvNumber)(s / (n - 1));
1008
+ };
1009
+ exports.fnCOVARIANCE_S = fnCOVARIANCE_S;
1010
+ /**
1011
+ * RANK.AVG — average-tie rank. Identical to RANK.EQ except that tied
1012
+ * positions return the average of the ranks they would otherwise span.
1013
+ */
1014
+ const fnRANK_AVG = args => {
1015
+ const numberRV = (0, _shared_1.argToNumber)(args[0]);
1016
+ if (numberRV.kind === 4 /* RVKind.Error */) {
1017
+ return numberRV;
1018
+ }
1019
+ const rawArr = (0, _shared_1.flattenNumbers)([args[1]]);
1020
+ const arrErr = (0, _shared_1.firstError)(rawArr);
1021
+ if (arrErr) {
1022
+ return arrErr;
1023
+ }
1024
+ const nums = rawArr.map(n => n.value);
1025
+ const orderRV = args.length > 2 ? (0, _shared_1.argToNumber)(args[2]) : (0, values_1.rvNumber)(0);
1026
+ if (orderRV.kind === 4 /* RVKind.Error */) {
1027
+ return orderRV;
1028
+ }
1029
+ const ascending = orderRV.value !== 0;
1030
+ const sorted = nums.slice().sort((a, b) => (ascending ? a - b : b - a));
1031
+ // Find the range of indices that equal `number`; RANK.AVG returns the
1032
+ // average rank over that range.
1033
+ const target = numberRV.value;
1034
+ let first = -1;
1035
+ let last = -1;
1036
+ for (let i = 0; i < sorted.length; i++) {
1037
+ if (sorted[i] === target) {
1038
+ if (first === -1) {
1039
+ first = i;
1040
+ }
1041
+ last = i;
1042
+ }
1043
+ }
1044
+ if (first === -1) {
1045
+ return values_1.ERRORS.NA;
1046
+ }
1047
+ // Ranks are 1-based; average of first+1 .. last+1.
1048
+ return (0, values_1.rvNumber)((first + last + 2) / 2);
1049
+ };
1050
+ exports.fnRANK_AVG = fnRANK_AVG;
1051
+ const fnFISHER = args => {
1052
+ const x = (0, _shared_1.argToNumber)(args[0]);
1053
+ if (x.kind === 4 /* RVKind.Error */) {
1054
+ return x;
1055
+ }
1056
+ if (x.value <= -1 || x.value >= 1) {
1057
+ return values_1.ERRORS.NUM;
1058
+ }
1059
+ return (0, values_1.rvNumber)(0.5 * Math.log((1 + x.value) / (1 - x.value)));
1060
+ };
1061
+ exports.fnFISHER = fnFISHER;
1062
+ const fnFISHERINV = args => {
1063
+ const y = (0, _shared_1.argToNumber)(args[0]);
1064
+ if (y.kind === 4 /* RVKind.Error */) {
1065
+ return y;
1066
+ }
1067
+ const e2y = Math.exp(2 * y.value);
1068
+ return (0, values_1.rvNumber)((e2y - 1) / (e2y + 1));
1069
+ };
1070
+ exports.fnFISHERINV = fnFISHERINV;
1071
+ const fnAVERAGEA = args => {
1072
+ const all = (0, _shared_1.flattenAll)(args);
1073
+ if (all.length === 0) {
1074
+ return values_1.ERRORS.DIV0;
1075
+ }
1076
+ let sum = 0;
1077
+ let count = 0;
1078
+ for (const v of all) {
1079
+ if (v.kind === 0 /* RVKind.Blank */) {
1080
+ continue;
1081
+ }
1082
+ if (v.kind === 4 /* RVKind.Error */) {
1083
+ return v;
1084
+ }
1085
+ if (v.kind === 1 /* RVKind.Number */) {
1086
+ sum += v.value;
1087
+ }
1088
+ else if (v.kind === 3 /* RVKind.Boolean */) {
1089
+ sum += v.value ? 1 : 0;
1090
+ }
1091
+ // Text = 0 for AVERAGEA (no addition needed)
1092
+ count++;
1093
+ }
1094
+ return count === 0 ? values_1.ERRORS.DIV0 : (0, values_1.rvNumber)(sum / count);
1095
+ };
1096
+ exports.fnAVERAGEA = fnAVERAGEA;
1097
+ const fnMAXA = args => {
1098
+ const all = (0, _shared_1.flattenAll)(args);
1099
+ let max = -Infinity;
1100
+ let found = false;
1101
+ for (const v of all) {
1102
+ if (v.kind === 0 /* RVKind.Blank */) {
1103
+ continue;
1104
+ }
1105
+ if (v.kind === 4 /* RVKind.Error */) {
1106
+ return v;
1107
+ }
1108
+ let n;
1109
+ if (v.kind === 1 /* RVKind.Number */) {
1110
+ n = v.value;
1111
+ }
1112
+ else if (v.kind === 3 /* RVKind.Boolean */) {
1113
+ n = v.value ? 1 : 0;
1114
+ }
1115
+ else {
1116
+ n = 0;
1117
+ }
1118
+ if (n > max) {
1119
+ max = n;
1120
+ }
1121
+ found = true;
1122
+ }
1123
+ return (0, values_1.rvNumber)(found ? max : 0);
1124
+ };
1125
+ exports.fnMAXA = fnMAXA;
1126
+ const fnMINA = args => {
1127
+ const all = (0, _shared_1.flattenAll)(args);
1128
+ let min = Infinity;
1129
+ let found = false;
1130
+ for (const v of all) {
1131
+ if (v.kind === 0 /* RVKind.Blank */) {
1132
+ continue;
1133
+ }
1134
+ if (v.kind === 4 /* RVKind.Error */) {
1135
+ return v;
1136
+ }
1137
+ let n;
1138
+ if (v.kind === 1 /* RVKind.Number */) {
1139
+ n = v.value;
1140
+ }
1141
+ else if (v.kind === 3 /* RVKind.Boolean */) {
1142
+ n = v.value ? 1 : 0;
1143
+ }
1144
+ else {
1145
+ n = 0;
1146
+ }
1147
+ if (n < min) {
1148
+ min = n;
1149
+ }
1150
+ found = true;
1151
+ }
1152
+ return (0, values_1.rvNumber)(found ? min : 0);
1153
+ };
1154
+ exports.fnMINA = fnMINA;
1155
+ // ============================================================================
1156
+ // Private helpers for distributions (pure number → number, unchanged)
1157
+ // ============================================================================
1158
+ function gammaFn(z) {
1159
+ if (z < 0.5) {
1160
+ return Math.PI / (Math.sin(Math.PI * z) * gammaFn(1 - z));
1161
+ }
1162
+ z -= 1;
1163
+ const g = 7;
1164
+ const c = [
1165
+ 0.99999999999980993, 676.5203681218851, -1259.1392167224028, 771.32342877765313,
1166
+ -176.61502916214059, 12.507343278686905, -0.13857109526572012, 9.9843695780195716e-6,
1167
+ 1.5056327351493116e-7
1168
+ ];
1169
+ let x = c[0];
1170
+ for (let i = 1; i < g + 2; i++) {
1171
+ x += c[i] / (z + i);
1172
+ }
1173
+ const t = z + g + 0.5;
1174
+ return Math.sqrt(2 * Math.PI) * Math.pow(t, z + 0.5) * Math.exp(-t) * x;
1175
+ }
1176
+ function lnGamma(x) {
1177
+ return Math.log(gammaFn(x));
1178
+ }
1179
+ function betaIncomplete(x, a, b) {
1180
+ if (x <= 0) {
1181
+ return 0;
1182
+ }
1183
+ if (x >= 1) {
1184
+ return 1;
1185
+ }
1186
+ if (x > (a + 1) / (a + b + 2)) {
1187
+ return 1 - betaIncomplete(1 - x, b, a);
1188
+ }
1189
+ const lbeta = lnGamma(a) + lnGamma(b) - lnGamma(a + b);
1190
+ const front = Math.exp(Math.log(x) * a + Math.log(1 - x) * b - lbeta) / a;
1191
+ // For extreme (a, b) the front factor underflows to 0 or overflows to
1192
+ // Infinity (e.g. T.DIST.2T at df >= 300 computes betaIncomplete with
1193
+ // a around 150 and x near 0.004; Math.log(x)*a dips below -650, so
1194
+ // Math.exp returns 0 and subsequent `f *= c * d` multiplications can
1195
+ // produce 0 * Infinity = NaN in the continued-fraction loop). Short-
1196
+ // circuit those pathological inputs: a zero front dominates the
1197
+ // series, so the integrated value is effectively 0.
1198
+ if (!Number.isFinite(front) || front === 0) {
1199
+ return 0;
1200
+ }
1201
+ let f = 1;
1202
+ let c = 1;
1203
+ let d = 1 - ((a + b) * x) / (a + 1);
1204
+ if (Math.abs(d) < 1e-30) {
1205
+ d = 1e-30;
1206
+ }
1207
+ d = 1 / d;
1208
+ f = d;
1209
+ for (let m = 1; m <= 200; m++) {
1210
+ let num = (m * (b - m) * x) / ((a + 2 * m - 1) * (a + 2 * m));
1211
+ d = 1 + num * d;
1212
+ if (Math.abs(d) < 1e-30) {
1213
+ d = 1e-30;
1214
+ }
1215
+ c = 1 + num / c;
1216
+ if (Math.abs(c) < 1e-30) {
1217
+ c = 1e-30;
1218
+ }
1219
+ d = 1 / d;
1220
+ f *= c * d;
1221
+ num = -((a + m) * (a + b + m) * x) / ((a + 2 * m) * (a + 2 * m + 1));
1222
+ d = 1 + num * d;
1223
+ if (Math.abs(d) < 1e-30) {
1224
+ d = 1e-30;
1225
+ }
1226
+ c = 1 + num / c;
1227
+ if (Math.abs(c) < 1e-30) {
1228
+ c = 1e-30;
1229
+ }
1230
+ d = 1 / d;
1231
+ const delta = c * d;
1232
+ f *= delta;
1233
+ if (Math.abs(delta - 1) < 1e-10) {
1234
+ break;
1235
+ }
1236
+ }
1237
+ return front * f;
1238
+ }
1239
+ function gammaIncomplete(a, x) {
1240
+ if (x < 0) {
1241
+ return 0;
1242
+ }
1243
+ if (x === 0) {
1244
+ return 0;
1245
+ }
1246
+ if (x < a + 1) {
1247
+ let sum = 1 / a;
1248
+ let term = 1 / a;
1249
+ for (let n = 1; n <= 200; n++) {
1250
+ term *= x / (a + n);
1251
+ sum += term;
1252
+ if (Math.abs(term) < Math.abs(sum) * 1e-14) {
1253
+ break;
1254
+ }
1255
+ }
1256
+ return sum * Math.exp(-x + a * Math.log(x) - lnGamma(a));
1257
+ }
1258
+ let f = 1;
1259
+ const b0 = x + 1 - a;
1260
+ let ci = 1e30;
1261
+ let d = 1 / b0;
1262
+ f = d;
1263
+ for (let i = 1; i <= 200; i++) {
1264
+ const an = -i * (i - a);
1265
+ const bn = x + 2 * i + 1 - a;
1266
+ d = bn + an * d;
1267
+ if (Math.abs(d) < 1e-30) {
1268
+ d = 1e-30;
1269
+ }
1270
+ ci = bn + an / ci;
1271
+ if (Math.abs(ci) < 1e-30) {
1272
+ ci = 1e-30;
1273
+ }
1274
+ d = 1 / d;
1275
+ const delta = d * ci;
1276
+ f *= delta;
1277
+ if (Math.abs(delta - 1) < 1e-10) {
1278
+ break;
1279
+ }
1280
+ }
1281
+ return 1 - f * Math.exp(-x + a * Math.log(x) - lnGamma(a));
1282
+ }
1283
+ // ============================================================================
1284
+ // More Statistical Distribution Functions
1285
+ // ============================================================================
1286
+ const fnPOISSON_DIST = args => {
1287
+ const x = (0, _shared_1.argToNumber)(args[0]);
1288
+ if (x.kind === 4 /* RVKind.Error */) {
1289
+ return x;
1290
+ }
1291
+ const mean = (0, _shared_1.argToNumber)(args[1]);
1292
+ if (mean.kind === 4 /* RVKind.Error */) {
1293
+ return mean;
1294
+ }
1295
+ const cum = boolArg(args, 2);
1296
+ if (!cum.ok) {
1297
+ return cum.error;
1298
+ }
1299
+ const k = Math.floor(x.value);
1300
+ if (k < 0 || mean.value < 0) {
1301
+ return values_1.ERRORS.NUM;
1302
+ }
1303
+ // Degenerate mean = 0: the Poisson distribution concentrates all mass at
1304
+ // k = 0. The textbook PMF formula evaluates `k * log(0) = -Infinity`
1305
+ // multiplied by `k = 0`, yielding `NaN`, so we short-circuit.
1306
+ if (mean.value === 0) {
1307
+ if (!cum.value) {
1308
+ return (0, values_1.rvNumber)(k === 0 ? 1 : 0);
1309
+ }
1310
+ return (0, values_1.rvNumber)(1); // CDF is 1 at every k >= 0
1311
+ }
1312
+ if (!cum.value) {
1313
+ return (0, values_1.rvNumber)(Math.exp(-mean.value + k * Math.log(mean.value) - lnGamma(k + 1)));
1314
+ }
1315
+ return (0, values_1.rvNumber)(1 - gammaIncomplete(k + 1, mean.value));
1316
+ };
1317
+ exports.fnPOISSON_DIST = fnPOISSON_DIST;
1318
+ const fnBINOM_DIST = args => {
1319
+ const numS = (0, _shared_1.argToNumber)(args[0]);
1320
+ if (numS.kind === 4 /* RVKind.Error */) {
1321
+ return numS;
1322
+ }
1323
+ const trials = (0, _shared_1.argToNumber)(args[1]);
1324
+ if (trials.kind === 4 /* RVKind.Error */) {
1325
+ return trials;
1326
+ }
1327
+ const probS = (0, _shared_1.argToNumber)(args[2]);
1328
+ if (probS.kind === 4 /* RVKind.Error */) {
1329
+ return probS;
1330
+ }
1331
+ const cum = boolArg(args, 3);
1332
+ if (!cum.ok) {
1333
+ return cum.error;
1334
+ }
1335
+ const k = Math.floor(numS.value);
1336
+ const n = Math.floor(trials.value);
1337
+ if (k < 0 || n < 0 || k > n || probS.value < 0 || probS.value > 1) {
1338
+ return values_1.ERRORS.NUM;
1339
+ }
1340
+ const pmf = (ki) => {
1341
+ // Degenerate p = 0 or p = 1 edges: the textbook formula multiplies
1342
+ // the log of 0 by 0 (for the absent term), producing NaN. Handle
1343
+ // these analytically — all mass is at k = 0 when p = 0, or at k = n
1344
+ // when p = 1.
1345
+ if (probS.value === 0) {
1346
+ return ki === 0 ? 1 : 0;
1347
+ }
1348
+ if (probS.value === 1) {
1349
+ return ki === n ? 1 : 0;
1350
+ }
1351
+ const lnC = lnGamma(n + 1) - lnGamma(ki + 1) - lnGamma(n - ki + 1);
1352
+ return Math.exp(lnC + ki * Math.log(probS.value) + (n - ki) * Math.log(1 - probS.value));
1353
+ };
1354
+ if (!cum.value) {
1355
+ return (0, values_1.rvNumber)(pmf(k));
1356
+ }
1357
+ let sum = 0;
1358
+ for (let i = 0; i <= k; i++) {
1359
+ sum += pmf(i);
1360
+ }
1361
+ return (0, values_1.rvNumber)(sum);
1362
+ };
1363
+ exports.fnBINOM_DIST = fnBINOM_DIST;
1364
+ /**
1365
+ * BINOM.DIST.RANGE(trials, probability, number_s, [number_s2]) —
1366
+ * probability of a binomial trial outcome between `number_s` and
1367
+ * `number_s2` (inclusive). When `number_s2` is omitted, returns the
1368
+ * probability of exactly `number_s` successes.
1369
+ */
1370
+ const fnBINOM_DIST_RANGE = args => {
1371
+ const trialsV = (0, _shared_1.argToNumber)(args[0]);
1372
+ if (trialsV.kind === 4 /* RVKind.Error */) {
1373
+ return trialsV;
1374
+ }
1375
+ const probV = (0, _shared_1.argToNumber)(args[1]);
1376
+ if (probV.kind === 4 /* RVKind.Error */) {
1377
+ return probV;
1378
+ }
1379
+ const s1V = (0, _shared_1.argToNumber)(args[2]);
1380
+ if (s1V.kind === 4 /* RVKind.Error */) {
1381
+ return s1V;
1382
+ }
1383
+ const s2V = args.length > 3 ? (0, _shared_1.argToNumber)(args[3]) : s1V;
1384
+ if (s2V.kind === 4 /* RVKind.Error */) {
1385
+ return s2V;
1386
+ }
1387
+ const n = Math.floor(trialsV.value);
1388
+ const s1 = Math.floor(s1V.value);
1389
+ const s2 = Math.floor(s2V.value);
1390
+ const p = probV.value;
1391
+ if (n < 0 || p < 0 || p > 1) {
1392
+ return values_1.ERRORS.NUM;
1393
+ }
1394
+ if (s1 < 0 || s1 > n) {
1395
+ return values_1.ERRORS.NUM;
1396
+ }
1397
+ if (s2 < s1 || s2 > n) {
1398
+ return values_1.ERRORS.NUM;
1399
+ }
1400
+ const pmf = (ki) => {
1401
+ if (p === 0) {
1402
+ return ki === 0 ? 1 : 0;
1403
+ }
1404
+ if (p === 1) {
1405
+ return ki === n ? 1 : 0;
1406
+ }
1407
+ const lnC = lnGamma(n + 1) - lnGamma(ki + 1) - lnGamma(n - ki + 1);
1408
+ return Math.exp(lnC + ki * Math.log(p) + (n - ki) * Math.log(1 - p));
1409
+ };
1410
+ let sum = 0;
1411
+ for (let i = s1; i <= s2; i++) {
1412
+ sum += pmf(i);
1413
+ }
1414
+ return (0, values_1.rvNumber)(sum);
1415
+ };
1416
+ exports.fnBINOM_DIST_RANGE = fnBINOM_DIST_RANGE;
1417
+ const fnBINOM_INV = args => {
1418
+ const trials = (0, _shared_1.argToNumber)(args[0]);
1419
+ if (trials.kind === 4 /* RVKind.Error */) {
1420
+ return trials;
1421
+ }
1422
+ const probS = (0, _shared_1.argToNumber)(args[1]);
1423
+ if (probS.kind === 4 /* RVKind.Error */) {
1424
+ return probS;
1425
+ }
1426
+ const alpha = (0, _shared_1.argToNumber)(args[2]);
1427
+ if (alpha.kind === 4 /* RVKind.Error */) {
1428
+ return alpha;
1429
+ }
1430
+ const n = Math.floor(trials.value);
1431
+ if (n < 0 || probS.value < 0 || probS.value > 1 || alpha.value < 0 || alpha.value > 1) {
1432
+ return values_1.ERRORS.NUM;
1433
+ }
1434
+ let cdf = 0;
1435
+ for (let k = 0; k <= n; k++) {
1436
+ const lnC = lnGamma(n + 1) - lnGamma(k + 1) - lnGamma(n - k + 1);
1437
+ cdf += Math.exp(lnC + k * Math.log(probS.value) + (n - k) * Math.log(1 - probS.value));
1438
+ if (cdf >= alpha.value) {
1439
+ return (0, values_1.rvNumber)(k);
1440
+ }
1441
+ }
1442
+ return (0, values_1.rvNumber)(n);
1443
+ };
1444
+ exports.fnBINOM_INV = fnBINOM_INV;
1445
+ const fnHYPGEOM_DIST = args => {
1446
+ const sampleS = (0, _shared_1.argToNumber)(args[0]);
1447
+ if (sampleS.kind === 4 /* RVKind.Error */) {
1448
+ return sampleS;
1449
+ }
1450
+ const numberSample = (0, _shared_1.argToNumber)(args[1]);
1451
+ if (numberSample.kind === 4 /* RVKind.Error */) {
1452
+ return numberSample;
1453
+ }
1454
+ const popS = (0, _shared_1.argToNumber)(args[2]);
1455
+ if (popS.kind === 4 /* RVKind.Error */) {
1456
+ return popS;
1457
+ }
1458
+ const numberPop = (0, _shared_1.argToNumber)(args[3]);
1459
+ if (numberPop.kind === 4 /* RVKind.Error */) {
1460
+ return numberPop;
1461
+ }
1462
+ const cum = boolArg(args, 4);
1463
+ if (!cum.ok) {
1464
+ return cum.error;
1465
+ }
1466
+ const ss = Math.floor(sampleS.value);
1467
+ const ns = Math.floor(numberSample.value);
1468
+ const ps = Math.floor(popS.value);
1469
+ const np = Math.floor(numberPop.value);
1470
+ const pmf = (k) => Math.exp(lnGamma(ps + 1) -
1471
+ lnGamma(k + 1) -
1472
+ lnGamma(ps - k + 1) +
1473
+ lnGamma(np - ps + 1) -
1474
+ lnGamma(ns - k + 1) -
1475
+ lnGamma(np - ps - ns + k + 1) -
1476
+ lnGamma(np + 1) +
1477
+ lnGamma(ns + 1) +
1478
+ lnGamma(np - ns + 1));
1479
+ if (!cum.value) {
1480
+ return (0, values_1.rvNumber)(pmf(ss));
1481
+ }
1482
+ let sum = 0;
1483
+ for (let k = 0; k <= ss; k++) {
1484
+ sum += pmf(k);
1485
+ }
1486
+ return (0, values_1.rvNumber)(sum);
1487
+ };
1488
+ exports.fnHYPGEOM_DIST = fnHYPGEOM_DIST;
1489
+ const fnNEGBINOM_DIST = args => {
1490
+ const numF = (0, _shared_1.argToNumber)(args[0]);
1491
+ if (numF.kind === 4 /* RVKind.Error */) {
1492
+ return numF;
1493
+ }
1494
+ const numS = (0, _shared_1.argToNumber)(args[1]);
1495
+ if (numS.kind === 4 /* RVKind.Error */) {
1496
+ return numS;
1497
+ }
1498
+ const probS = (0, _shared_1.argToNumber)(args[2]);
1499
+ if (probS.kind === 4 /* RVKind.Error */) {
1500
+ return probS;
1501
+ }
1502
+ const cum = boolArg(args, 3);
1503
+ if (!cum.ok) {
1504
+ return cum.error;
1505
+ }
1506
+ const f = Math.floor(numF.value);
1507
+ const s = Math.floor(numS.value);
1508
+ if (f < 0 || s < 1 || probS.value < 0 || probS.value > 1) {
1509
+ return values_1.ERRORS.NUM;
1510
+ }
1511
+ const pmf = (k) => {
1512
+ const lnC = lnGamma(k + s) - lnGamma(s) - lnGamma(k + 1);
1513
+ return Math.exp(lnC + s * Math.log(probS.value) + k * Math.log(1 - probS.value));
1514
+ };
1515
+ if (!cum.value) {
1516
+ return (0, values_1.rvNumber)(pmf(f));
1517
+ }
1518
+ let sum = 0;
1519
+ for (let k = 0; k <= f; k++) {
1520
+ sum += pmf(k);
1521
+ }
1522
+ return (0, values_1.rvNumber)(sum);
1523
+ };
1524
+ exports.fnNEGBINOM_DIST = fnNEGBINOM_DIST;
1525
+ const fnCHISQ_DIST = args => {
1526
+ const x = (0, _shared_1.argToNumber)(args[0]);
1527
+ if (x.kind === 4 /* RVKind.Error */) {
1528
+ return x;
1529
+ }
1530
+ const df = (0, _shared_1.argToNumber)(args[1]);
1531
+ if (df.kind === 4 /* RVKind.Error */) {
1532
+ return df;
1533
+ }
1534
+ const cum = boolArg(args, 2);
1535
+ if (!cum.ok) {
1536
+ return cum.error;
1537
+ }
1538
+ if (x.value < 0 || df.value < 1) {
1539
+ return values_1.ERRORS.NUM;
1540
+ }
1541
+ // Excel's CHISQ.DIST accepts non-integer degrees of freedom; the
1542
+ // incomplete-gamma formula is defined for any positive `df/2`. We used
1543
+ // to Math.floor() df, which silently returned the chi-square for the
1544
+ // nearest smaller integer df and produced visibly wrong densities for
1545
+ // fractional inputs.
1546
+ if (cum.value) {
1547
+ return (0, values_1.rvNumber)(gammaIncomplete(df.value / 2, x.value / 2));
1548
+ }
1549
+ const halfK = df.value / 2;
1550
+ return (0, values_1.rvNumber)(Math.exp((halfK - 1) * Math.log(x.value / 2) - x.value / 2 - lnGamma(halfK)) / 2);
1551
+ };
1552
+ exports.fnCHISQ_DIST = fnCHISQ_DIST;
1553
+ const fnCHISQ_INV = args => {
1554
+ const p = (0, _shared_1.argToNumber)(args[0]);
1555
+ if (p.kind === 4 /* RVKind.Error */) {
1556
+ return p;
1557
+ }
1558
+ const df = (0, _shared_1.argToNumber)(args[1]);
1559
+ if (df.kind === 4 /* RVKind.Error */) {
1560
+ return df;
1561
+ }
1562
+ if (p.value < 0 || p.value >= 1 || df.value < 1) {
1563
+ return values_1.ERRORS.NUM;
1564
+ }
1565
+ // P = 0 → x = 0 exactly. Without the short-circuit, Newton from x = df
1566
+ // would compute `(0 - 0) / pdf` = 0 on the first iteration (fine), but
1567
+ // rounding drift can push x negative, triggering the clamp to 0.001 and
1568
+ // returning a non-zero result.
1569
+ if (p.value === 0) {
1570
+ return (0, values_1.rvNumber)(0);
1571
+ }
1572
+ let x = df.value;
1573
+ for (let iter = 0; iter < 100; iter++) {
1574
+ const cdf = gammaIncomplete(df.value / 2, x / 2);
1575
+ const halfK = df.value / 2;
1576
+ const pdf = Math.exp((halfK - 1) * Math.log(x / 2) - x / 2 - lnGamma(halfK)) / 2;
1577
+ if (Math.abs(pdf) < 1e-15) {
1578
+ break;
1579
+ }
1580
+ const delta = (cdf - p.value) / pdf;
1581
+ x -= delta;
1582
+ if (x <= 0) {
1583
+ x = 0.001;
1584
+ }
1585
+ if (Math.abs(delta) < 1e-10) {
1586
+ break;
1587
+ }
1588
+ }
1589
+ return (0, values_1.rvNumber)(x);
1590
+ };
1591
+ exports.fnCHISQ_INV = fnCHISQ_INV;
1592
+ const fnCHISQ_DIST_RT = args => {
1593
+ const x = (0, _shared_1.argToNumber)(args[0]);
1594
+ if (x.kind === 4 /* RVKind.Error */) {
1595
+ return x;
1596
+ }
1597
+ const df = (0, _shared_1.argToNumber)(args[1]);
1598
+ if (df.kind === 4 /* RVKind.Error */) {
1599
+ return df;
1600
+ }
1601
+ if (x.value < 0 || df.value < 1) {
1602
+ return values_1.ERRORS.NUM;
1603
+ }
1604
+ return (0, values_1.rvNumber)(1 - gammaIncomplete(df.value / 2, x.value / 2));
1605
+ };
1606
+ exports.fnCHISQ_DIST_RT = fnCHISQ_DIST_RT;
1607
+ /**
1608
+ * CHISQ.INV.RT(probability, df) — right-tailed inverse of chi-square.
1609
+ * Equivalent to CHISQ.INV(1 - probability, df). Probabilities of 0 or 1
1610
+ * return +∞ or 0 respectively; values outside (0, 1] are #NUM!.
1611
+ */
1612
+ const fnCHISQ_INV_RT = args => {
1613
+ const p = (0, _shared_1.argToNumber)(args[0]);
1614
+ if (p.kind === 4 /* RVKind.Error */) {
1615
+ return p;
1616
+ }
1617
+ const df = (0, _shared_1.argToNumber)(args[1]);
1618
+ if (df.kind === 4 /* RVKind.Error */) {
1619
+ return df;
1620
+ }
1621
+ if (p.value <= 0 || p.value > 1 || df.value < 1) {
1622
+ return values_1.ERRORS.NUM;
1623
+ }
1624
+ // Re-use CHISQ.INV with the complementary probability.
1625
+ return (0, exports.fnCHISQ_INV)([(0, values_1.rvNumber)(1 - p.value), df]);
1626
+ };
1627
+ exports.fnCHISQ_INV_RT = fnCHISQ_INV_RT;
1628
+ const fnF_DIST = args => {
1629
+ const x = (0, _shared_1.argToNumber)(args[0]);
1630
+ if (x.kind === 4 /* RVKind.Error */) {
1631
+ return x;
1632
+ }
1633
+ const df1 = (0, _shared_1.argToNumber)(args[1]);
1634
+ if (df1.kind === 4 /* RVKind.Error */) {
1635
+ return df1;
1636
+ }
1637
+ const df2 = (0, _shared_1.argToNumber)(args[2]);
1638
+ if (df2.kind === 4 /* RVKind.Error */) {
1639
+ return df2;
1640
+ }
1641
+ const cum = boolArg(args, 3);
1642
+ if (!cum.ok) {
1643
+ return cum.error;
1644
+ }
1645
+ if (x.value < 0 || df1.value < 1 || df2.value < 1) {
1646
+ return values_1.ERRORS.NUM;
1647
+ }
1648
+ // Accept fractional df. See CHISQ.DIST comment — the betaIncomplete/lnGamma
1649
+ // formulas below are defined for any positive df, so there is no reason
1650
+ // to truncate.
1651
+ const d1 = df1.value;
1652
+ const d2 = df2.value;
1653
+ if (cum.value) {
1654
+ return (0, values_1.rvNumber)(betaIncomplete((d1 * x.value) / (d1 * x.value + d2), d1 / 2, d2 / 2));
1655
+ }
1656
+ const num = (Math.pow(d1 * x.value, d1 / 2) * Math.pow(d2, d2 / 2)) /
1657
+ Math.pow(d1 * x.value + d2, (d1 + d2) / 2);
1658
+ const denom = x.value * Math.exp(lnGamma(d1 / 2) + lnGamma(d2 / 2) - lnGamma((d1 + d2) / 2));
1659
+ return (0, values_1.rvNumber)(denom === 0 ? 0 : num / denom);
1660
+ };
1661
+ exports.fnF_DIST = fnF_DIST;
1662
+ const fnF_INV = args => {
1663
+ const p = (0, _shared_1.argToNumber)(args[0]);
1664
+ if (p.kind === 4 /* RVKind.Error */) {
1665
+ return p;
1666
+ }
1667
+ const df1 = (0, _shared_1.argToNumber)(args[1]);
1668
+ if (df1.kind === 4 /* RVKind.Error */) {
1669
+ return df1;
1670
+ }
1671
+ const df2 = (0, _shared_1.argToNumber)(args[2]);
1672
+ if (df2.kind === 4 /* RVKind.Error */) {
1673
+ return df2;
1674
+ }
1675
+ if (p.value < 0 || p.value >= 1 || df1.value < 1 || df2.value < 1) {
1676
+ return values_1.ERRORS.NUM;
1677
+ }
1678
+ const d1 = df1.value;
1679
+ const d2 = df2.value;
1680
+ let lo = 0;
1681
+ let hi = 1000;
1682
+ for (let i = 0; i < 100; i++) {
1683
+ const mid = (lo + hi) / 2;
1684
+ const cdf = betaIncomplete((d1 * mid) / (d1 * mid + d2), d1 / 2, d2 / 2);
1685
+ if (cdf < p.value) {
1686
+ lo = mid;
1687
+ }
1688
+ else {
1689
+ hi = mid;
1690
+ }
1691
+ if (hi - lo < 1e-10) {
1692
+ break;
1693
+ }
1694
+ }
1695
+ return (0, values_1.rvNumber)((lo + hi) / 2);
1696
+ };
1697
+ exports.fnF_INV = fnF_INV;
1698
+ const fnT_DIST = args => {
1699
+ const x = (0, _shared_1.argToNumber)(args[0]);
1700
+ if (x.kind === 4 /* RVKind.Error */) {
1701
+ return x;
1702
+ }
1703
+ const df = (0, _shared_1.argToNumber)(args[1]);
1704
+ if (df.kind === 4 /* RVKind.Error */) {
1705
+ return df;
1706
+ }
1707
+ const cum = boolArg(args, 2);
1708
+ if (!cum.ok) {
1709
+ return cum.error;
1710
+ }
1711
+ if (df.value < 1) {
1712
+ return values_1.ERRORS.NUM;
1713
+ }
1714
+ const v = df.value;
1715
+ if (cum.value) {
1716
+ const t = v / (v + x.value * x.value);
1717
+ const halfBeta = 0.5 * betaIncomplete(t, v / 2, 0.5);
1718
+ return (0, values_1.rvNumber)(x.value >= 0 ? 1 - halfBeta : halfBeta);
1719
+ }
1720
+ return (0, values_1.rvNumber)(Math.exp(lnGamma((v + 1) / 2) - lnGamma(v / 2)) /
1721
+ (Math.sqrt(v * Math.PI) * Math.pow(1 + (x.value * x.value) / v, (v + 1) / 2)));
1722
+ };
1723
+ exports.fnT_DIST = fnT_DIST;
1724
+ const fnT_INV = args => {
1725
+ const p = (0, _shared_1.argToNumber)(args[0]);
1726
+ if (p.kind === 4 /* RVKind.Error */) {
1727
+ return p;
1728
+ }
1729
+ const df = (0, _shared_1.argToNumber)(args[1]);
1730
+ if (df.kind === 4 /* RVKind.Error */) {
1731
+ return df;
1732
+ }
1733
+ if (p.value <= 0 || p.value >= 1 || df.value < 1) {
1734
+ return values_1.ERRORS.NUM;
1735
+ }
1736
+ let x = normSInv(p.value);
1737
+ const v = df.value;
1738
+ for (let iter = 0; iter < 100; iter++) {
1739
+ const t = v / (v + x * x);
1740
+ const halfBeta = 0.5 * betaIncomplete(t, v / 2, 0.5);
1741
+ const cdf = x >= 0 ? 1 - halfBeta : halfBeta;
1742
+ const pdf = Math.exp(lnGamma((v + 1) / 2) - lnGamma(v / 2)) /
1743
+ (Math.sqrt(v * Math.PI) * Math.pow(1 + (x * x) / v, (v + 1) / 2));
1744
+ if (Math.abs(pdf) < 1e-15) {
1745
+ break;
1746
+ }
1747
+ const delta = (cdf - p.value) / pdf;
1748
+ x -= delta;
1749
+ if (Math.abs(delta) < 1e-10) {
1750
+ break;
1751
+ }
1752
+ }
1753
+ return (0, values_1.rvNumber)(x);
1754
+ };
1755
+ exports.fnT_INV = fnT_INV;
1756
+ const fnT_DIST_2T = args => {
1757
+ const x = (0, _shared_1.argToNumber)(args[0]);
1758
+ if (x.kind === 4 /* RVKind.Error */) {
1759
+ return x;
1760
+ }
1761
+ const df = (0, _shared_1.argToNumber)(args[1]);
1762
+ if (df.kind === 4 /* RVKind.Error */) {
1763
+ return df;
1764
+ }
1765
+ if (x.value < 0 || df.value < 1) {
1766
+ return values_1.ERRORS.NUM;
1767
+ }
1768
+ const v = df.value;
1769
+ return (0, values_1.rvNumber)(betaIncomplete(v / (v + x.value * x.value), v / 2, 0.5));
1770
+ };
1771
+ exports.fnT_DIST_2T = fnT_DIST_2T;
1772
+ const fnT_DIST_RT = args => {
1773
+ const x = (0, _shared_1.argToNumber)(args[0]);
1774
+ if (x.kind === 4 /* RVKind.Error */) {
1775
+ return x;
1776
+ }
1777
+ const df = (0, _shared_1.argToNumber)(args[1]);
1778
+ if (df.kind === 4 /* RVKind.Error */) {
1779
+ return df;
1780
+ }
1781
+ if (df.value < 1) {
1782
+ return values_1.ERRORS.NUM;
1783
+ }
1784
+ const v = df.value;
1785
+ const halfBeta = 0.5 * betaIncomplete(v / (v + x.value * x.value), v / 2, 0.5);
1786
+ // T.DIST.RT(x, df) = right-tail = 1 - CDF(x)
1787
+ // For x >= 0: right-tail = halfBeta
1788
+ // For x < 0: right-tail = 1 - halfBeta
1789
+ return (0, values_1.rvNumber)(x.value >= 0 ? halfBeta : 1 - halfBeta);
1790
+ };
1791
+ exports.fnT_DIST_RT = fnT_DIST_RT;
1792
+ const fnT_INV_2T = args => {
1793
+ const p = (0, _shared_1.argToNumber)(args[0]);
1794
+ if (p.kind === 4 /* RVKind.Error */) {
1795
+ return p;
1796
+ }
1797
+ const df = (0, _shared_1.argToNumber)(args[1]);
1798
+ if (df.kind === 4 /* RVKind.Error */) {
1799
+ return df;
1800
+ }
1801
+ if (p.value <= 0 || p.value > 1 || df.value < 1) {
1802
+ return values_1.ERRORS.NUM;
1803
+ }
1804
+ const result = (0, exports.fnT_INV)([(0, values_1.rvNumber)(1 - p.value / 2), args[1]]);
1805
+ if ((0, values_1.isError)(result)) {
1806
+ return result;
1807
+ }
1808
+ return (0, values_1.rvNumber)(Math.abs(result.value));
1809
+ };
1810
+ exports.fnT_INV_2T = fnT_INV_2T;
1811
+ // ============================================================================
1812
+ // BETA, GAMMA, EXPON, WEIBULL, LOGNORM distributions
1813
+ // ============================================================================
1814
+ const fnBETA_DIST = args => {
1815
+ const x = (0, _shared_1.argToNumber)(args[0]);
1816
+ if (x.kind === 4 /* RVKind.Error */) {
1817
+ return x;
1818
+ }
1819
+ const alpha = (0, _shared_1.argToNumber)(args[1]);
1820
+ if (alpha.kind === 4 /* RVKind.Error */) {
1821
+ return alpha;
1822
+ }
1823
+ const beta = (0, _shared_1.argToNumber)(args[2]);
1824
+ if (beta.kind === 4 /* RVKind.Error */) {
1825
+ return beta;
1826
+ }
1827
+ let cumVal = true;
1828
+ if (args.length > 3) {
1829
+ const cum = boolArg(args, 3);
1830
+ if (!cum.ok) {
1831
+ return cum.error;
1832
+ }
1833
+ cumVal = cum.value;
1834
+ }
1835
+ let A = 0;
1836
+ if (args.length > 4) {
1837
+ const aRV = (0, _shared_1.argToNumber)(args[4]);
1838
+ if (aRV.kind === 4 /* RVKind.Error */) {
1839
+ return aRV;
1840
+ }
1841
+ A = aRV.value;
1842
+ }
1843
+ let B = 1;
1844
+ if (args.length > 5) {
1845
+ const bRV = (0, _shared_1.argToNumber)(args[5]);
1846
+ if (bRV.kind === 4 /* RVKind.Error */) {
1847
+ return bRV;
1848
+ }
1849
+ B = bRV.value;
1850
+ }
1851
+ if (alpha.value <= 0 || beta.value <= 0 || B <= A) {
1852
+ return values_1.ERRORS.NUM;
1853
+ }
1854
+ const xn = (x.value - A) / (B - A);
1855
+ if (xn < 0 || xn > 1) {
1856
+ return values_1.ERRORS.NUM;
1857
+ }
1858
+ if (cumVal) {
1859
+ return (0, values_1.rvNumber)(betaIncomplete(xn, alpha.value, beta.value));
1860
+ }
1861
+ return (0, values_1.rvNumber)(Math.exp((alpha.value - 1) * Math.log(xn) +
1862
+ (beta.value - 1) * Math.log(1 - xn) -
1863
+ lnGamma(alpha.value) -
1864
+ lnGamma(beta.value) +
1865
+ lnGamma(alpha.value + beta.value)) /
1866
+ (B - A));
1867
+ };
1868
+ exports.fnBETA_DIST = fnBETA_DIST;
1869
+ const fnBETA_INV = args => {
1870
+ const p = (0, _shared_1.argToNumber)(args[0]);
1871
+ if (p.kind === 4 /* RVKind.Error */) {
1872
+ return p;
1873
+ }
1874
+ const alpha = (0, _shared_1.argToNumber)(args[1]);
1875
+ if (alpha.kind === 4 /* RVKind.Error */) {
1876
+ return alpha;
1877
+ }
1878
+ const beta = (0, _shared_1.argToNumber)(args[2]);
1879
+ if (beta.kind === 4 /* RVKind.Error */) {
1880
+ return beta;
1881
+ }
1882
+ let A = 0;
1883
+ if (args.length > 3) {
1884
+ const aRV = (0, _shared_1.argToNumber)(args[3]);
1885
+ if (aRV.kind === 4 /* RVKind.Error */) {
1886
+ return aRV;
1887
+ }
1888
+ A = aRV.value;
1889
+ }
1890
+ let B = 1;
1891
+ if (args.length > 4) {
1892
+ const bRV = (0, _shared_1.argToNumber)(args[4]);
1893
+ if (bRV.kind === 4 /* RVKind.Error */) {
1894
+ return bRV;
1895
+ }
1896
+ B = bRV.value;
1897
+ }
1898
+ if (p.value < 0 || p.value > 1 || alpha.value <= 0 || beta.value <= 0) {
1899
+ return values_1.ERRORS.NUM;
1900
+ }
1901
+ let lo = 0;
1902
+ let hi = 1;
1903
+ for (let i = 0; i < 100; i++) {
1904
+ const mid = (lo + hi) / 2;
1905
+ if (betaIncomplete(mid, alpha.value, beta.value) < p.value) {
1906
+ lo = mid;
1907
+ }
1908
+ else {
1909
+ hi = mid;
1910
+ }
1911
+ if (hi - lo < 1e-12) {
1912
+ break;
1913
+ }
1914
+ }
1915
+ return (0, values_1.rvNumber)(A + ((lo + hi) / 2) * (B - A));
1916
+ };
1917
+ exports.fnBETA_INV = fnBETA_INV;
1918
+ const fnGAMMA = args => {
1919
+ const n = (0, _shared_1.argToNumber)(args[0]);
1920
+ if (n.kind === 4 /* RVKind.Error */) {
1921
+ return n;
1922
+ }
1923
+ if (n.value <= 0 && n.value === Math.floor(n.value)) {
1924
+ return values_1.ERRORS.NUM;
1925
+ }
1926
+ return (0, values_1.rvNumber)(gammaFn(n.value));
1927
+ };
1928
+ exports.fnGAMMA = fnGAMMA;
1929
+ const fnGAMMALN = args => {
1930
+ const n = (0, _shared_1.argToNumber)(args[0]);
1931
+ if (n.kind === 4 /* RVKind.Error */) {
1932
+ return n;
1933
+ }
1934
+ if (n.value <= 0) {
1935
+ return values_1.ERRORS.NUM;
1936
+ }
1937
+ return (0, values_1.rvNumber)(lnGamma(n.value));
1938
+ };
1939
+ exports.fnGAMMALN = fnGAMMALN;
1940
+ const fnGAMMA_DIST = args => {
1941
+ const x = (0, _shared_1.argToNumber)(args[0]);
1942
+ if (x.kind === 4 /* RVKind.Error */) {
1943
+ return x;
1944
+ }
1945
+ const alpha = (0, _shared_1.argToNumber)(args[1]);
1946
+ if (alpha.kind === 4 /* RVKind.Error */) {
1947
+ return alpha;
1948
+ }
1949
+ const beta = (0, _shared_1.argToNumber)(args[2]);
1950
+ if (beta.kind === 4 /* RVKind.Error */) {
1951
+ return beta;
1952
+ }
1953
+ const cum = boolArg(args, 3);
1954
+ if (!cum.ok) {
1955
+ return cum.error;
1956
+ }
1957
+ if (x.value < 0 || alpha.value <= 0 || beta.value <= 0) {
1958
+ return values_1.ERRORS.NUM;
1959
+ }
1960
+ if (cum.value) {
1961
+ return (0, values_1.rvNumber)(gammaIncomplete(alpha.value, x.value / beta.value));
1962
+ }
1963
+ return (0, values_1.rvNumber)(Math.exp((alpha.value - 1) * Math.log(x.value) -
1964
+ x.value / beta.value -
1965
+ alpha.value * Math.log(beta.value) -
1966
+ lnGamma(alpha.value)));
1967
+ };
1968
+ exports.fnGAMMA_DIST = fnGAMMA_DIST;
1969
+ const fnGAMMA_INV = args => {
1970
+ const p = (0, _shared_1.argToNumber)(args[0]);
1971
+ if (p.kind === 4 /* RVKind.Error */) {
1972
+ return p;
1973
+ }
1974
+ const alpha = (0, _shared_1.argToNumber)(args[1]);
1975
+ if (alpha.kind === 4 /* RVKind.Error */) {
1976
+ return alpha;
1977
+ }
1978
+ const beta = (0, _shared_1.argToNumber)(args[2]);
1979
+ if (beta.kind === 4 /* RVKind.Error */) {
1980
+ return beta;
1981
+ }
1982
+ if (p.value < 0 || p.value >= 1 || alpha.value <= 0 || beta.value <= 0) {
1983
+ return values_1.ERRORS.NUM;
1984
+ }
1985
+ let lo = 0;
1986
+ let hi = Math.max(alpha.value * beta.value * 10, 100);
1987
+ for (let i = 0; i < 100; i++) {
1988
+ const mid = (lo + hi) / 2;
1989
+ if (gammaIncomplete(alpha.value, mid / beta.value) < p.value) {
1990
+ lo = mid;
1991
+ }
1992
+ else {
1993
+ hi = mid;
1994
+ }
1995
+ if (hi - lo < 1e-10) {
1996
+ break;
1997
+ }
1998
+ }
1999
+ return (0, values_1.rvNumber)((lo + hi) / 2);
2000
+ };
2001
+ exports.fnGAMMA_INV = fnGAMMA_INV;
2002
+ const fnEXPON_DIST = args => {
2003
+ const x = (0, _shared_1.argToNumber)(args[0]);
2004
+ if (x.kind === 4 /* RVKind.Error */) {
2005
+ return x;
2006
+ }
2007
+ const lambda = (0, _shared_1.argToNumber)(args[1]);
2008
+ if (lambda.kind === 4 /* RVKind.Error */) {
2009
+ return lambda;
2010
+ }
2011
+ const cum = boolArg(args, 2);
2012
+ if (!cum.ok) {
2013
+ return cum.error;
2014
+ }
2015
+ if (x.value < 0 || lambda.value <= 0) {
2016
+ return values_1.ERRORS.NUM;
2017
+ }
2018
+ return (0, values_1.rvNumber)(cum.value
2019
+ ? 1 - Math.exp(-lambda.value * x.value)
2020
+ : lambda.value * Math.exp(-lambda.value * x.value));
2021
+ };
2022
+ exports.fnEXPON_DIST = fnEXPON_DIST;
2023
+ const fnWEIBULL_DIST = args => {
2024
+ const x = (0, _shared_1.argToNumber)(args[0]);
2025
+ if (x.kind === 4 /* RVKind.Error */) {
2026
+ return x;
2027
+ }
2028
+ const alpha = (0, _shared_1.argToNumber)(args[1]);
2029
+ if (alpha.kind === 4 /* RVKind.Error */) {
2030
+ return alpha;
2031
+ }
2032
+ const beta = (0, _shared_1.argToNumber)(args[2]);
2033
+ if (beta.kind === 4 /* RVKind.Error */) {
2034
+ return beta;
2035
+ }
2036
+ const cum = boolArg(args, 3);
2037
+ if (!cum.ok) {
2038
+ return cum.error;
2039
+ }
2040
+ if (x.value < 0 || alpha.value <= 0 || beta.value <= 0) {
2041
+ return values_1.ERRORS.NUM;
2042
+ }
2043
+ if (cum.value) {
2044
+ return (0, values_1.rvNumber)(1 - Math.exp(-Math.pow(x.value / beta.value, alpha.value)));
2045
+ }
2046
+ return (0, values_1.rvNumber)((alpha.value / beta.value) *
2047
+ Math.pow(x.value / beta.value, alpha.value - 1) *
2048
+ Math.exp(-Math.pow(x.value / beta.value, alpha.value)));
2049
+ };
2050
+ exports.fnWEIBULL_DIST = fnWEIBULL_DIST;
2051
+ const fnLOGNORM_DIST = args => {
2052
+ const x = (0, _shared_1.argToNumber)(args[0]);
2053
+ if (x.kind === 4 /* RVKind.Error */) {
2054
+ return x;
2055
+ }
2056
+ const mean = (0, _shared_1.argToNumber)(args[1]);
2057
+ if (mean.kind === 4 /* RVKind.Error */) {
2058
+ return mean;
2059
+ }
2060
+ const stddev = (0, _shared_1.argToNumber)(args[2]);
2061
+ if (stddev.kind === 4 /* RVKind.Error */) {
2062
+ return stddev;
2063
+ }
2064
+ const cum = boolArg(args, 3);
2065
+ if (!cum.ok) {
2066
+ return cum.error;
2067
+ }
2068
+ if (x.value <= 0 || stddev.value <= 0) {
2069
+ return values_1.ERRORS.NUM;
2070
+ }
2071
+ const z = (Math.log(x.value) - mean.value) / stddev.value;
2072
+ if (cum.value) {
2073
+ return (0, values_1.rvNumber)(normSDist(z));
2074
+ }
2075
+ return (0, values_1.rvNumber)(normSPdf(z) / (x.value * stddev.value));
2076
+ };
2077
+ exports.fnLOGNORM_DIST = fnLOGNORM_DIST;
2078
+ const fnLOGNORM_INV = args => {
2079
+ const p = (0, _shared_1.argToNumber)(args[0]);
2080
+ if (p.kind === 4 /* RVKind.Error */) {
2081
+ return p;
2082
+ }
2083
+ const mean = (0, _shared_1.argToNumber)(args[1]);
2084
+ if (mean.kind === 4 /* RVKind.Error */) {
2085
+ return mean;
2086
+ }
2087
+ const stddev = (0, _shared_1.argToNumber)(args[2]);
2088
+ if (stddev.kind === 4 /* RVKind.Error */) {
2089
+ return stddev;
2090
+ }
2091
+ if (p.value <= 0 || p.value >= 1 || stddev.value <= 0) {
2092
+ return values_1.ERRORS.NUM;
2093
+ }
2094
+ return (0, values_1.rvNumber)(Math.exp(mean.value + stddev.value * normSInv(p.value)));
2095
+ };
2096
+ exports.fnLOGNORM_INV = fnLOGNORM_INV;
2097
+ const fnPHI = args => {
2098
+ const x = (0, _shared_1.argToNumber)(args[0]);
2099
+ return x.kind === 4 /* RVKind.Error */ ? x : (0, values_1.rvNumber)(normSPdf(x.value));
2100
+ };
2101
+ exports.fnPHI = fnPHI;
2102
+ const fnGAUSS = args => {
2103
+ const z = (0, _shared_1.argToNumber)(args[0]);
2104
+ return z.kind === 4 /* RVKind.Error */ ? z : (0, values_1.rvNumber)(normSDist(z.value) - 0.5);
2105
+ };
2106
+ exports.fnGAUSS = fnGAUSS;
2107
+ // ============================================================================
2108
+ // ERF, ERFC, STANDARDIZE
2109
+ // ============================================================================
2110
+ function erfFn(x) {
2111
+ // Exact at 0 — the rational approximation below leaves a ~7e-10 drift at
2112
+ // t = 1 / (1 + p·0) = 1, which is visible to callers that expect
2113
+ // `ERF(0) === 0` (and especially to `ERFC(0) === 1`).
2114
+ if (x === 0) {
2115
+ return 0;
2116
+ }
2117
+ const a1 = 0.254829592;
2118
+ const a2 = -0.284496736;
2119
+ const a3 = 1.421413741;
2120
+ const a4 = -1.453152027;
2121
+ const a5 = 1.061405429;
2122
+ const p = 0.3275911;
2123
+ const sign = x < 0 ? -1 : 1;
2124
+ const ax = Math.abs(x);
2125
+ const t = 1.0 / (1.0 + p * ax);
2126
+ const y = 1.0 - ((((a5 * t + a4) * t + a3) * t + a2) * t + a1) * t * Math.exp(-ax * ax);
2127
+ return sign * y;
2128
+ }
2129
+ const fnERF = args => {
2130
+ const lower = (0, _shared_1.argToNumber)(args[0]);
2131
+ if (lower.kind === 4 /* RVKind.Error */) {
2132
+ return lower;
2133
+ }
2134
+ if (args.length > 1) {
2135
+ const upper = (0, _shared_1.argToNumber)(args[1]);
2136
+ if (upper.kind === 4 /* RVKind.Error */) {
2137
+ return upper;
2138
+ }
2139
+ return (0, values_1.rvNumber)(erfFn(upper.value) - erfFn(lower.value));
2140
+ }
2141
+ return (0, values_1.rvNumber)(erfFn(lower.value));
2142
+ };
2143
+ exports.fnERF = fnERF;
2144
+ const fnERFC = args => {
2145
+ const x = (0, _shared_1.argToNumber)(args[0]);
2146
+ return x.kind === 4 /* RVKind.Error */ ? x : (0, values_1.rvNumber)(1 - erfFn(x.value));
2147
+ };
2148
+ exports.fnERFC = fnERFC;
2149
+ const fnSTANDARDIZE = args => {
2150
+ const x = (0, _shared_1.argToNumber)(args[0]);
2151
+ if (x.kind === 4 /* RVKind.Error */) {
2152
+ return x;
2153
+ }
2154
+ const mean = (0, _shared_1.argToNumber)(args[1]);
2155
+ if (mean.kind === 4 /* RVKind.Error */) {
2156
+ return mean;
2157
+ }
2158
+ const stddev = (0, _shared_1.argToNumber)(args[2]);
2159
+ if (stddev.kind === 4 /* RVKind.Error */) {
2160
+ return stddev;
2161
+ }
2162
+ if (stddev.value <= 0) {
2163
+ return values_1.ERRORS.NUM;
2164
+ }
2165
+ return (0, values_1.rvNumber)((x.value - mean.value) / stddev.value);
2166
+ };
2167
+ exports.fnSTANDARDIZE = fnSTANDARDIZE;
2168
+ // ============================================================================
2169
+ // Array-returning functions: FREQUENCY, GROWTH, TREND, LINEST, LOGEST
2170
+ // ============================================================================
2171
+ const fnFREQUENCY = args => {
2172
+ if (!isArrayArg(args[0]) || !isArrayArg(args[1])) {
2173
+ return values_1.ERRORS.VALUE;
2174
+ }
2175
+ const rawData = (0, _shared_1.flattenNumbers)([args[0]]);
2176
+ const dataErr = (0, _shared_1.firstError)(rawData);
2177
+ if (dataErr) {
2178
+ return dataErr;
2179
+ }
2180
+ const data = rawData.map(n => n.value);
2181
+ const rawBins = (0, _shared_1.flattenNumbers)([args[1]]);
2182
+ const binsErr = (0, _shared_1.firstError)(rawBins);
2183
+ if (binsErr) {
2184
+ return binsErr;
2185
+ }
2186
+ const bins = rawBins.map(n => n.value);
2187
+ // IMPORTANT: do NOT sort `bins`. Excel's FREQUENCY bucketises data into
2188
+ // the bins as the user supplied them — both the output count order and
2189
+ // the bucket boundaries follow the original sequence. Sorting would
2190
+ // silently reshuffle the result array, which is a common historical
2191
+ // implementation mistake.
2192
+ //
2193
+ // For each datum we assign it to the first bin `i` whose upper bound
2194
+ // satisfies `data <= bins[i]`; if no such bin exists the datum falls
2195
+ // into the overflow bucket at index `bins.length`. This matches Excel's
2196
+ // semantics for any bin order (monotonic or not).
2197
+ const result = [];
2198
+ const counts = new Array(bins.length + 1).fill(0);
2199
+ for (const d of data) {
2200
+ let assigned = false;
2201
+ for (let i = 0; i < bins.length; i++) {
2202
+ if (d <= bins[i]) {
2203
+ counts[i]++;
2204
+ assigned = true;
2205
+ break;
2206
+ }
2207
+ }
2208
+ if (!assigned) {
2209
+ counts[bins.length]++;
2210
+ }
2211
+ }
2212
+ for (const c of counts) {
2213
+ result.push([(0, values_1.rvNumber)(c)]);
2214
+ }
2215
+ return (0, values_1.rvArray)(result);
2216
+ };
2217
+ exports.fnFREQUENCY = fnFREQUENCY;
2218
+ /** Narrow `T | ErrorValue` to `ErrorValue`. */
2219
+ function isErr(v) {
2220
+ return v.kind === 4 /* RVKind.Error */;
2221
+ }
2222
+ function extractMatrix(arg) {
2223
+ if (arg.kind !== 5 /* RVKind.Array */) {
2224
+ const sv = (0, values_1.topLeft)(arg);
2225
+ if (sv.kind === 4 /* RVKind.Error */) {
2226
+ return sv;
2227
+ }
2228
+ const n = (0, values_1.toNumberRV)(sv);
2229
+ if (n.kind === 4 /* RVKind.Error */) {
2230
+ return n;
2231
+ }
2232
+ return { m: { data: [[n.value]], rows: 1, cols: 1 }, orient: "row" };
2233
+ }
2234
+ const data = [];
2235
+ for (const row of arg.rows) {
2236
+ const out = [];
2237
+ for (const cell of row) {
2238
+ if (cell.kind === 4 /* RVKind.Error */) {
2239
+ return cell;
2240
+ }
2241
+ if (cell.kind === 1 /* RVKind.Number */) {
2242
+ out.push(cell.value);
2243
+ }
2244
+ else if (cell.kind === 0 /* RVKind.Blank */) {
2245
+ return values_1.ERRORS.VALUE;
2246
+ }
2247
+ else {
2248
+ const n = (0, values_1.toNumberRV)(cell);
2249
+ if (n.kind === 4 /* RVKind.Error */) {
2250
+ return n;
2251
+ }
2252
+ out.push(n.value);
2253
+ }
2254
+ }
2255
+ data.push(out);
2256
+ }
2257
+ const rows = arg.height;
2258
+ const cols = arg.width;
2259
+ const orient = rows === 1 ? "row" : cols === 1 ? "col" : "matrix";
2260
+ return { m: { data, rows, cols }, orient };
2261
+ }
2262
+ /**
2263
+ * Normalize the `known_x's` argument to a design matrix X of shape [n, k],
2264
+ * where n is the number of observations and k is the number of predictor
2265
+ * variables. Excel infers k from the orientation of known_x's: when y is a
2266
+ * column vector (or square), each column of known_x's is one predictor; when
2267
+ * y is a row vector, each row of known_x's is one predictor.
2268
+ */
2269
+ function buildDesignMatrix(m, nObs, yOrient) {
2270
+ // Decide orientation of predictors based on y's orientation and matrix shape
2271
+ let byRows;
2272
+ let xOrient;
2273
+ if (m.rows === 1) {
2274
+ // Row vector of length n: single predictor, one observation per column
2275
+ byRows = false;
2276
+ xOrient = "row";
2277
+ }
2278
+ else if (m.cols === 1) {
2279
+ // Column vector of length n: single predictor, one observation per row
2280
+ byRows = true;
2281
+ xOrient = "col";
2282
+ }
2283
+ else if (yOrient === "row") {
2284
+ // y is a row vector: predictors are rows of known_x's
2285
+ byRows = false;
2286
+ xOrient = "row";
2287
+ }
2288
+ else {
2289
+ // y is a column/matrix: predictors are columns of known_x's
2290
+ byRows = true;
2291
+ xOrient = "col";
2292
+ }
2293
+ const n = byRows ? m.rows : m.cols;
2294
+ const k = byRows ? m.cols : m.rows;
2295
+ if (n !== nObs) {
2296
+ return values_1.ERRORS.REF;
2297
+ }
2298
+ const X = [];
2299
+ for (let i = 0; i < n; i++) {
2300
+ const row = [];
2301
+ for (let j = 0; j < k; j++) {
2302
+ row.push(byRows ? m.data[i][j] : m.data[j][i]);
2303
+ }
2304
+ X.push(row);
2305
+ }
2306
+ return { X, k, xOrient };
2307
+ }
2308
+ /** Solve (A^T A) β = A^T b via Gauss–Jordan on the augmented matrix. */
2309
+ function solveNormalEquations(A, b) {
2310
+ const n = A.length;
2311
+ const k = A[0]?.length ?? 0;
2312
+ // Build augmented [AᵀA | Aᵀb]
2313
+ const aug = Array.from({ length: k }, () => new Array(k + 1).fill(0));
2314
+ for (let i = 0; i < k; i++) {
2315
+ for (let j = 0; j < k; j++) {
2316
+ let s = 0;
2317
+ for (let r = 0; r < n; r++) {
2318
+ s += A[r][i] * A[r][j];
2319
+ }
2320
+ aug[i][j] = s;
2321
+ }
2322
+ let sb = 0;
2323
+ for (let r = 0; r < n; r++) {
2324
+ sb += A[r][i] * b[r];
2325
+ }
2326
+ aug[i][k] = sb;
2327
+ }
2328
+ // Gauss–Jordan with partial pivoting
2329
+ for (let i = 0; i < k; i++) {
2330
+ let piv = i;
2331
+ for (let r = i + 1; r < k; r++) {
2332
+ if (Math.abs(aug[r][i]) > Math.abs(aug[piv][i])) {
2333
+ piv = r;
2334
+ }
2335
+ }
2336
+ if (Math.abs(aug[piv][i]) < 1e-12) {
2337
+ return null;
2338
+ }
2339
+ if (piv !== i) {
2340
+ [aug[i], aug[piv]] = [aug[piv], aug[i]];
2341
+ }
2342
+ const d = aug[i][i];
2343
+ for (let j = i; j <= k; j++) {
2344
+ aug[i][j] /= d;
2345
+ }
2346
+ for (let r = 0; r < k; r++) {
2347
+ if (r === i) {
2348
+ continue;
2349
+ }
2350
+ const f = aug[r][i];
2351
+ if (f === 0) {
2352
+ continue;
2353
+ }
2354
+ for (let j = i; j <= k; j++) {
2355
+ aug[r][j] -= f * aug[i][j];
2356
+ }
2357
+ }
2358
+ }
2359
+ return aug.map(row => row[k]);
2360
+ }
2361
+ /** Compute inverse of k×k symmetric positive-definite matrix via Gauss–Jordan. */
2362
+ function invertSquareMatrix(M) {
2363
+ const k = M.length;
2364
+ const aug = Array.from({ length: k }, (_, i) => {
2365
+ const row = new Array(2 * k).fill(0);
2366
+ for (let j = 0; j < k; j++) {
2367
+ row[j] = M[i][j];
2368
+ }
2369
+ row[k + i] = 1;
2370
+ return row;
2371
+ });
2372
+ for (let i = 0; i < k; i++) {
2373
+ let piv = i;
2374
+ for (let r = i + 1; r < k; r++) {
2375
+ if (Math.abs(aug[r][i]) > Math.abs(aug[piv][i])) {
2376
+ piv = r;
2377
+ }
2378
+ }
2379
+ if (Math.abs(aug[piv][i]) < 1e-12) {
2380
+ return null;
2381
+ }
2382
+ if (piv !== i) {
2383
+ [aug[i], aug[piv]] = [aug[piv], aug[i]];
2384
+ }
2385
+ const d = aug[i][i];
2386
+ for (let j = 0; j < 2 * k; j++) {
2387
+ aug[i][j] /= d;
2388
+ }
2389
+ for (let r = 0; r < k; r++) {
2390
+ if (r === i) {
2391
+ continue;
2392
+ }
2393
+ const f = aug[r][i];
2394
+ if (f === 0) {
2395
+ continue;
2396
+ }
2397
+ for (let j = 0; j < 2 * k; j++) {
2398
+ aug[r][j] -= f * aug[i][j];
2399
+ }
2400
+ }
2401
+ }
2402
+ return aug.map(row => row.slice(k));
2403
+ }
2404
+ function runLeastSquares(input, withStats) {
2405
+ const { includeIntercept, logMode } = input;
2406
+ const n = input.y.length;
2407
+ const k = input.X[0]?.length ?? 0;
2408
+ if (n < 1 || k < 1) {
2409
+ return values_1.ERRORS.VALUE;
2410
+ }
2411
+ // y in log domain for LOGEST/GROWTH
2412
+ const y = new Array(n);
2413
+ for (let i = 0; i < n; i++) {
2414
+ const yi = input.y[i];
2415
+ if (logMode) {
2416
+ if (yi <= 0) {
2417
+ return values_1.ERRORS.NUM;
2418
+ }
2419
+ y[i] = Math.log(yi);
2420
+ }
2421
+ else {
2422
+ y[i] = yi;
2423
+ }
2424
+ }
2425
+ // Augment X with intercept column (as the last column → Excel puts b at the end)
2426
+ const kAug = includeIntercept ? k + 1 : k;
2427
+ const A = new Array(n);
2428
+ for (let i = 0; i < n; i++) {
2429
+ const row = new Array(kAug);
2430
+ for (let j = 0; j < k; j++) {
2431
+ row[j] = input.X[i][j];
2432
+ }
2433
+ if (includeIntercept) {
2434
+ row[k] = 1;
2435
+ }
2436
+ A[i] = row;
2437
+ }
2438
+ const beta = solveNormalEquations(A, y);
2439
+ if (beta === null) {
2440
+ return values_1.ERRORS.NUM;
2441
+ }
2442
+ // Excel orders coefficients as [mk, m(k-1), ..., m1, b] — reverse the slope
2443
+ // portion but keep the intercept last.
2444
+ const coeffs = [];
2445
+ for (let j = k - 1; j >= 0; j--) {
2446
+ coeffs.push(beta[j]);
2447
+ }
2448
+ if (includeIntercept) {
2449
+ coeffs.push(beta[k]);
2450
+ }
2451
+ else {
2452
+ coeffs.push(0);
2453
+ }
2454
+ if (!withStats) {
2455
+ return { coeffs };
2456
+ }
2457
+ // Residuals, sums of squares
2458
+ const yhat = new Array(n);
2459
+ for (let i = 0; i < n; i++) {
2460
+ let s = 0;
2461
+ for (let j = 0; j < kAug; j++) {
2462
+ s += A[i][j] * beta[j];
2463
+ }
2464
+ yhat[i] = s;
2465
+ }
2466
+ let ybar = 0;
2467
+ if (includeIntercept) {
2468
+ for (const v of y) {
2469
+ ybar += v;
2470
+ }
2471
+ ybar /= n;
2472
+ }
2473
+ let ssResid = 0, ssTot = 0, ssReg = 0;
2474
+ for (let i = 0; i < n; i++) {
2475
+ ssResid += (y[i] - yhat[i]) ** 2;
2476
+ ssTot += (y[i] - ybar) ** 2;
2477
+ ssReg += (yhat[i] - ybar) ** 2;
2478
+ }
2479
+ const df = n - kAug;
2480
+ const r2 = ssTot === 0 ? 1 : 1 - ssResid / ssTot;
2481
+ const sey = df > 0 ? Math.sqrt(ssResid / df) : 0;
2482
+ const fStat = df > 0 && ssResid > 0 ? ssReg / k / (ssResid / df) : Number.POSITIVE_INFINITY;
2483
+ // Standard errors: diag(sey² · (AᵀA)⁻¹)
2484
+ const AtA = Array.from({ length: kAug }, () => new Array(kAug).fill(0));
2485
+ for (let i = 0; i < kAug; i++) {
2486
+ for (let j = 0; j < kAug; j++) {
2487
+ let s = 0;
2488
+ for (let r = 0; r < n; r++) {
2489
+ s += A[r][i] * A[r][j];
2490
+ }
2491
+ AtA[i][j] = s;
2492
+ }
2493
+ }
2494
+ const inv = invertSquareMatrix(AtA);
2495
+ const seCoeffs = [];
2496
+ if (inv) {
2497
+ for (let j = k - 1; j >= 0; j--) {
2498
+ const v = sey * sey * inv[j][j];
2499
+ seCoeffs.push(v >= 0 ? Math.sqrt(v) : 0);
2500
+ }
2501
+ if (includeIntercept) {
2502
+ const v = sey * sey * inv[k][k];
2503
+ seCoeffs.push(v >= 0 ? Math.sqrt(v) : 0);
2504
+ }
2505
+ else {
2506
+ seCoeffs.push(0);
2507
+ }
2508
+ }
2509
+ else {
2510
+ // Cannot invert — fill with NaN per Excel behavior (but we use 0 since
2511
+ // downstream consumers expect numbers).
2512
+ for (let j = 0; j <= k; j++) {
2513
+ seCoeffs.push(0);
2514
+ }
2515
+ }
2516
+ return { coeffs, seCoeffs, r2, sey, fStat, df, ssReg, ssResid };
2517
+ }
2518
+ /** Build Excel's 5×(k+1) LINEST stats block. */
2519
+ function buildStatsBlock(res) {
2520
+ const kPlus1 = res.coeffs.length;
2521
+ const row1 = res.coeffs.map(v => (0, values_1.rvNumber)(v));
2522
+ const row2 = (res.seCoeffs ?? []).map(v => (0, values_1.rvNumber)(v));
2523
+ // Row 3: r² in col 0, sey in col 1, then #N/A for k+1 ≥ 3
2524
+ const row3 = new Array(kPlus1).fill(values_1.ERRORS.NA);
2525
+ row3[0] = (0, values_1.rvNumber)(res.r2 ?? 0);
2526
+ if (kPlus1 >= 2) {
2527
+ row3[1] = (0, values_1.rvNumber)(res.sey ?? 0);
2528
+ }
2529
+ // Row 4: F in col 0, df in col 1, then #N/A
2530
+ const row4 = new Array(kPlus1).fill(values_1.ERRORS.NA);
2531
+ row4[0] = (0, values_1.rvNumber)(res.fStat ?? 0);
2532
+ if (kPlus1 >= 2) {
2533
+ row4[1] = (0, values_1.rvNumber)(res.df ?? 0);
2534
+ }
2535
+ // Row 5: ssReg in col 0, ssResid in col 1, then #N/A
2536
+ const row5 = new Array(kPlus1).fill(values_1.ERRORS.NA);
2537
+ row5[0] = (0, values_1.rvNumber)(res.ssReg ?? 0);
2538
+ if (kPlus1 >= 2) {
2539
+ row5[1] = (0, values_1.rvNumber)(res.ssResid ?? 0);
2540
+ }
2541
+ return [row1, row2, row3, row4, row5];
2542
+ }
2543
+ /** Parse known_y / known_x from args, returning design matrix and orientation info. */
2544
+ function parseRegressionInputs(args) {
2545
+ if (!args[0]) {
2546
+ return values_1.ERRORS.VALUE;
2547
+ }
2548
+ const yInfo = extractMatrix(args[0]);
2549
+ if (isErr(yInfo)) {
2550
+ return yInfo;
2551
+ }
2552
+ const y = [];
2553
+ for (const row of yInfo.m.data) {
2554
+ for (const v of row) {
2555
+ y.push(v);
2556
+ }
2557
+ }
2558
+ const nObs = y.length;
2559
+ if (nObs < 1) {
2560
+ return values_1.ERRORS.VALUE;
2561
+ }
2562
+ if (args.length > 1 && args[1].kind !== 0 /* RVKind.Blank */) {
2563
+ const xInfo = extractMatrix(args[1]);
2564
+ if (isErr(xInfo)) {
2565
+ return xInfo;
2566
+ }
2567
+ const built = buildDesignMatrix(xInfo.m, nObs, yInfo.orient);
2568
+ if (isErr(built)) {
2569
+ return built;
2570
+ }
2571
+ return { y, X: built.X, k: built.k, yOrient: yInfo.orient, xOrient: built.xOrient };
2572
+ }
2573
+ // Default known_x's = 1..n as a column vector
2574
+ const X = y.map((_, i) => [i + 1]);
2575
+ return { y, X, k: 1, yOrient: yInfo.orient, xOrient: yInfo.orient };
2576
+ }
2577
+ /** Parse new_x (third arg of TREND/GROWTH). Returns new-X matrix [m, k] and output orientation. */
2578
+ function parseNewX(arg, fallback, k, xOrient) {
2579
+ if (!arg || arg.kind === 0 /* RVKind.Blank */) {
2580
+ return { X: fallback, outOrient: xOrient };
2581
+ }
2582
+ const info = extractMatrix(arg);
2583
+ if (isErr(info)) {
2584
+ return info;
2585
+ }
2586
+ const m = info.m;
2587
+ // Determine orientation: need one of the dimensions to equal k (the number of predictors)
2588
+ if (k === 1) {
2589
+ // Single predictor → flatten whatever shape was given
2590
+ const X = [];
2591
+ for (const row of m.data) {
2592
+ for (const v of row) {
2593
+ X.push([v]);
2594
+ }
2595
+ }
2596
+ const outOrient = m.rows === 1 ? "row" : "col";
2597
+ return { X, outOrient };
2598
+ }
2599
+ // Multi-predictor: match orientation with known_x's
2600
+ if (xOrient === "col" || xOrient === "matrix") {
2601
+ // Each row is one observation with k columns of predictors
2602
+ if (m.cols !== k) {
2603
+ return values_1.ERRORS.REF;
2604
+ }
2605
+ return { X: m.data.map(r => r.slice()), outOrient: "col" };
2606
+ }
2607
+ // xOrient === "row": each column is one observation
2608
+ if (m.rows !== k) {
2609
+ return values_1.ERRORS.REF;
2610
+ }
2611
+ const X = [];
2612
+ for (let c = 0; c < m.cols; c++) {
2613
+ const row = [];
2614
+ for (let r = 0; r < k; r++) {
2615
+ row.push(m.data[r][c]);
2616
+ }
2617
+ X.push(row);
2618
+ }
2619
+ return { X, outOrient: "row" };
2620
+ }
2621
+ /** Emit an array of predictions matching the requested output orientation. */
2622
+ function emitPredictions(values, outOrient) {
2623
+ if (outOrient === "row") {
2624
+ return (0, values_1.rvArray)([values.map(v => (0, values_1.rvNumber)(v))]);
2625
+ }
2626
+ return (0, values_1.rvArray)(values.map(v => [(0, values_1.rvNumber)(v)]));
2627
+ }
2628
+ const fnGROWTH = args => {
2629
+ const parsed = parseRegressionInputs(args);
2630
+ if (isErr(parsed)) {
2631
+ return parsed;
2632
+ }
2633
+ const { y, X, k, xOrient } = parsed;
2634
+ const lsq = runLeastSquares({ y, X, includeIntercept: true, logMode: true }, false);
2635
+ if (isErr(lsq)) {
2636
+ return lsq;
2637
+ }
2638
+ // coeffs order: [mk, ..., m1, b]; slopes in log space correspond to positions [0..k-1]
2639
+ const b = lsq.coeffs[k];
2640
+ const slopes = new Array(k);
2641
+ for (let j = 0; j < k; j++) {
2642
+ slopes[j] = lsq.coeffs[k - 1 - j];
2643
+ } // m1..mk
2644
+ const newInfo = parseNewX(args[2], X, k, xOrient);
2645
+ if (isErr(newInfo)) {
2646
+ return newInfo;
2647
+ }
2648
+ const preds = newInfo.X.map(row => {
2649
+ let lp = b;
2650
+ for (let j = 0; j < k; j++) {
2651
+ lp += slopes[j] * row[j];
2652
+ }
2653
+ return Math.exp(lp);
2654
+ });
2655
+ return emitPredictions(preds, newInfo.outOrient);
2656
+ };
2657
+ exports.fnGROWTH = fnGROWTH;
2658
+ const fnTREND = args => {
2659
+ const parsed = parseRegressionInputs(args);
2660
+ if (isErr(parsed)) {
2661
+ return parsed;
2662
+ }
2663
+ const { y, X, k, xOrient } = parsed;
2664
+ const lsq = runLeastSquares({ y, X, includeIntercept: true, logMode: false }, false);
2665
+ if (isErr(lsq)) {
2666
+ return lsq;
2667
+ }
2668
+ const b = lsq.coeffs[k];
2669
+ const slopes = new Array(k);
2670
+ for (let j = 0; j < k; j++) {
2671
+ slopes[j] = lsq.coeffs[k - 1 - j];
2672
+ }
2673
+ const newInfo = parseNewX(args[2], X, k, xOrient);
2674
+ if (isErr(newInfo)) {
2675
+ return newInfo;
2676
+ }
2677
+ const preds = newInfo.X.map(row => {
2678
+ let p = b;
2679
+ for (let j = 0; j < k; j++) {
2680
+ p += slopes[j] * row[j];
2681
+ }
2682
+ return p;
2683
+ });
2684
+ return emitPredictions(preds, newInfo.outOrient);
2685
+ };
2686
+ exports.fnTREND = fnTREND;
2687
+ const fnLINEST = args => {
2688
+ const parsed = parseRegressionInputs(args);
2689
+ if (isErr(parsed)) {
2690
+ return parsed;
2691
+ }
2692
+ const { y, X } = parsed;
2693
+ // 3rd arg: const (default TRUE — include intercept). FALSE → force intercept = 0.
2694
+ let includeIntercept = true;
2695
+ if (args.length > 2 && args[2].kind !== 0 /* RVKind.Blank */) {
2696
+ const b = (0, values_1.toBooleanRV)((0, values_1.topLeft)(args[2]));
2697
+ if (b.kind === 4 /* RVKind.Error */) {
2698
+ return b;
2699
+ }
2700
+ includeIntercept = b.value;
2701
+ }
2702
+ // 4th arg: stats (default FALSE).
2703
+ let withStats = false;
2704
+ if (args.length > 3 && args[3].kind !== 0 /* RVKind.Blank */) {
2705
+ const b = (0, values_1.toBooleanRV)((0, values_1.topLeft)(args[3]));
2706
+ if (b.kind === 4 /* RVKind.Error */) {
2707
+ return b;
2708
+ }
2709
+ withStats = b.value;
2710
+ }
2711
+ const lsq = runLeastSquares({ y, X, includeIntercept, logMode: false }, withStats);
2712
+ if (isErr(lsq)) {
2713
+ return lsq;
2714
+ }
2715
+ if (withStats) {
2716
+ return (0, values_1.rvArray)(buildStatsBlock(lsq));
2717
+ }
2718
+ return (0, values_1.rvArray)([lsq.coeffs.map(v => (0, values_1.rvNumber)(v))]);
2719
+ };
2720
+ exports.fnLINEST = fnLINEST;
2721
+ const fnLOGEST = args => {
2722
+ const parsed = parseRegressionInputs(args);
2723
+ if (isErr(parsed)) {
2724
+ return parsed;
2725
+ }
2726
+ const { y, X } = parsed;
2727
+ let includeIntercept = true;
2728
+ if (args.length > 2 && args[2].kind !== 0 /* RVKind.Blank */) {
2729
+ const b = (0, values_1.toBooleanRV)((0, values_1.topLeft)(args[2]));
2730
+ if (b.kind === 4 /* RVKind.Error */) {
2731
+ return b;
2732
+ }
2733
+ includeIntercept = b.value;
2734
+ }
2735
+ let withStats = false;
2736
+ if (args.length > 3 && args[3].kind !== 0 /* RVKind.Blank */) {
2737
+ const b = (0, values_1.toBooleanRV)((0, values_1.topLeft)(args[3]));
2738
+ if (b.kind === 4 /* RVKind.Error */) {
2739
+ return b;
2740
+ }
2741
+ withStats = b.value;
2742
+ }
2743
+ const lsq = runLeastSquares({ y, X, includeIntercept, logMode: true }, withStats);
2744
+ if (isErr(lsq)) {
2745
+ return lsq;
2746
+ }
2747
+ if (withStats) {
2748
+ // LOGEST reports exp-transformed slopes/intercept in row 1 but keeps rows 2-5 as LINEST
2749
+ const block = buildStatsBlock(lsq);
2750
+ block[0] = lsq.coeffs.map(v => (0, values_1.rvNumber)(Math.exp(v)));
2751
+ return (0, values_1.rvArray)(block);
2752
+ }
2753
+ return (0, values_1.rvArray)([lsq.coeffs.map(v => (0, values_1.rvNumber)(Math.exp(v)))]);
2754
+ };
2755
+ exports.fnLOGEST = fnLOGEST;
2756
+ // ============================================================================
2757
+ // F.DIST.RT, F.INV.RT — F-distribution right tail
2758
+ // ============================================================================
2759
+ /**
2760
+ * F.DIST.RT(x, d1, d2) — right-tail probability of the F-distribution.
2761
+ *
2762
+ * Equivalent to `1 - F.DIST(x, d1, d2, TRUE)`. Using the symmetry of the
2763
+ * regularized incomplete beta function, this can be expressed as
2764
+ * `I(d2/(d2 + d1*x), d2/2, d1/2)`, which avoids subtracting from 1 and
2765
+ * is numerically stable in the upper tail.
2766
+ */
2767
+ const fnF_DIST_RT = args => {
2768
+ const x = (0, _shared_1.argToNumber)(args[0]);
2769
+ if (x.kind === 4 /* RVKind.Error */) {
2770
+ return x;
2771
+ }
2772
+ const df1 = (0, _shared_1.argToNumber)(args[1]);
2773
+ if (df1.kind === 4 /* RVKind.Error */) {
2774
+ return df1;
2775
+ }
2776
+ const df2 = (0, _shared_1.argToNumber)(args[2]);
2777
+ if (df2.kind === 4 /* RVKind.Error */) {
2778
+ return df2;
2779
+ }
2780
+ if (x.value < 0 || df1.value < 1 || df2.value < 1) {
2781
+ return values_1.ERRORS.NUM;
2782
+ }
2783
+ // At x=0 the right tail equals 1 (entire distribution above 0).
2784
+ if (x.value === 0) {
2785
+ return (0, values_1.rvNumber)(1);
2786
+ }
2787
+ const d1 = df1.value;
2788
+ const d2 = df2.value;
2789
+ // Right tail via symmetry: I(d2/(d2 + d1*x), d2/2, d1/2).
2790
+ return (0, values_1.rvNumber)(betaIncomplete(d2 / (d2 + d1 * x.value), d2 / 2, d1 / 2));
2791
+ };
2792
+ exports.fnF_DIST_RT = fnF_DIST_RT;
2793
+ /**
2794
+ * F.INV.RT(p, d1, d2) — inverse right-tail of the F-distribution.
2795
+ * Returns x such that P(F > x) = p. Implemented via binary search on the
2796
+ * right-tail CDF (monotonically decreasing from 1 at x=0 to 0 at x=∞).
2797
+ */
2798
+ const fnF_INV_RT = args => {
2799
+ const p = (0, _shared_1.argToNumber)(args[0]);
2800
+ if (p.kind === 4 /* RVKind.Error */) {
2801
+ return p;
2802
+ }
2803
+ const df1 = (0, _shared_1.argToNumber)(args[1]);
2804
+ if (df1.kind === 4 /* RVKind.Error */) {
2805
+ return df1;
2806
+ }
2807
+ const df2 = (0, _shared_1.argToNumber)(args[2]);
2808
+ if (df2.kind === 4 /* RVKind.Error */) {
2809
+ return df2;
2810
+ }
2811
+ if (p.value <= 0 || p.value > 1 || df1.value < 1 || df2.value < 1) {
2812
+ return values_1.ERRORS.NUM;
2813
+ }
2814
+ const d1 = df1.value;
2815
+ const d2 = df2.value;
2816
+ // Right-tail CDF at x: I(d2/(d2 + d1*x), d2/2, d1/2), decreases with x.
2817
+ let lo = 0;
2818
+ let hi = 1e6;
2819
+ for (let i = 0; i < 200; i++) {
2820
+ const mid = (lo + hi) / 2;
2821
+ const rt = betaIncomplete(d2 / (d2 + d1 * mid), d2 / 2, d1 / 2);
2822
+ if (rt > p.value) {
2823
+ lo = mid;
2824
+ }
2825
+ else {
2826
+ hi = mid;
2827
+ }
2828
+ if (hi - lo < 1e-10) {
2829
+ break;
2830
+ }
2831
+ }
2832
+ return (0, values_1.rvNumber)((lo + hi) / 2);
2833
+ };
2834
+ exports.fnF_INV_RT = fnF_INV_RT;
2835
+ // ============================================================================
2836
+ // SKEW, SKEW.P, KURT
2837
+ // ============================================================================
2838
+ /**
2839
+ * SKEW — sample skewness.
2840
+ * Formula: n / ((n-1)(n-2)) * Σ((xi-mean)/s)^3, where s is the sample stdev.
2841
+ */
2842
+ const fnSKEW = args => {
2843
+ const nums = (0, _shared_1.flattenNumbers)(args);
2844
+ const err = (0, _shared_1.firstError)(nums);
2845
+ if (err) {
2846
+ return err;
2847
+ }
2848
+ const xs = nums.map(n => n.value);
2849
+ const n = xs.length;
2850
+ if (n < 3) {
2851
+ return values_1.ERRORS.DIV0;
2852
+ }
2853
+ let sum = 0;
2854
+ for (const v of xs) {
2855
+ sum += v;
2856
+ }
2857
+ const mean = sum / n;
2858
+ let sumSq = 0;
2859
+ for (const v of xs) {
2860
+ sumSq += (v - mean) ** 2;
2861
+ }
2862
+ const sampleStd = Math.sqrt(sumSq / (n - 1));
2863
+ if (sampleStd === 0) {
2864
+ return values_1.ERRORS.DIV0;
2865
+ }
2866
+ let sumCubed = 0;
2867
+ for (const v of xs) {
2868
+ sumCubed += ((v - mean) / sampleStd) ** 3;
2869
+ }
2870
+ return (0, values_1.rvNumber)((n / ((n - 1) * (n - 2))) * sumCubed);
2871
+ };
2872
+ exports.fnSKEW = fnSKEW;
2873
+ /**
2874
+ * SKEW.P — population skewness.
2875
+ * Formula: (1/n) * Σ((xi-mean)/σ)^3, where σ is the population stdev.
2876
+ */
2877
+ const fnSKEW_P = args => {
2878
+ const nums = (0, _shared_1.flattenNumbers)(args);
2879
+ const err = (0, _shared_1.firstError)(nums);
2880
+ if (err) {
2881
+ return err;
2882
+ }
2883
+ const xs = nums.map(n => n.value);
2884
+ const n = xs.length;
2885
+ if (n < 1) {
2886
+ return values_1.ERRORS.DIV0;
2887
+ }
2888
+ let sum = 0;
2889
+ for (const v of xs) {
2890
+ sum += v;
2891
+ }
2892
+ const mean = sum / n;
2893
+ let sumSq = 0;
2894
+ for (const v of xs) {
2895
+ sumSq += (v - mean) ** 2;
2896
+ }
2897
+ const popStd = Math.sqrt(sumSq / n);
2898
+ if (popStd === 0) {
2899
+ return values_1.ERRORS.DIV0;
2900
+ }
2901
+ let sumCubed = 0;
2902
+ for (const v of xs) {
2903
+ sumCubed += ((v - mean) / popStd) ** 3;
2904
+ }
2905
+ return (0, values_1.rvNumber)(sumCubed / n);
2906
+ };
2907
+ exports.fnSKEW_P = fnSKEW_P;
2908
+ /**
2909
+ * KURT — sample excess kurtosis.
2910
+ * Formula: n(n+1) / ((n-1)(n-2)(n-3)) * Σ((xi-mean)/s)^4 - 3(n-1)^2 / ((n-2)(n-3)).
2911
+ */
2912
+ const fnKURT = args => {
2913
+ const nums = (0, _shared_1.flattenNumbers)(args);
2914
+ const err = (0, _shared_1.firstError)(nums);
2915
+ if (err) {
2916
+ return err;
2917
+ }
2918
+ const xs = nums.map(n => n.value);
2919
+ const n = xs.length;
2920
+ if (n < 4) {
2921
+ return values_1.ERRORS.DIV0;
2922
+ }
2923
+ let sum = 0;
2924
+ for (const v of xs) {
2925
+ sum += v;
2926
+ }
2927
+ const mean = sum / n;
2928
+ let sumSq = 0;
2929
+ for (const v of xs) {
2930
+ sumSq += (v - mean) ** 2;
2931
+ }
2932
+ const sampleStd = Math.sqrt(sumSq / (n - 1));
2933
+ if (sampleStd === 0) {
2934
+ return values_1.ERRORS.DIV0;
2935
+ }
2936
+ let sumQuad = 0;
2937
+ for (const v of xs) {
2938
+ sumQuad += ((v - mean) / sampleStd) ** 4;
2939
+ }
2940
+ const term1 = (n * (n + 1)) / ((n - 1) * (n - 2) * (n - 3));
2941
+ const term2 = (3 * (n - 1) ** 2) / ((n - 2) * (n - 3));
2942
+ return (0, values_1.rvNumber)(term1 * sumQuad - term2);
2943
+ };
2944
+ exports.fnKURT = fnKURT;
2945
+ // ============================================================================
2946
+ // PERCENTRANK family
2947
+ // ============================================================================
2948
+ /**
2949
+ * Compute PERCENTRANK's significance-truncated result.
2950
+ *
2951
+ * Excel's `significance` truncates the return value to that many
2952
+ * digits — `significance=3` (default) yields 0.123 rather than
2953
+ * 0.12345. It is a display truncation, not a rounding, so we
2954
+ * implement it by `floor(value * 10^n) / 10^n`.
2955
+ */
2956
+ function truncateToSignificance(value, significance) {
2957
+ if (significance < 1) {
2958
+ return Number.NaN;
2959
+ }
2960
+ // Significance must be an integer; Excel truncates toward zero.
2961
+ const n = Math.trunc(significance);
2962
+ const scale = Math.pow(10, n);
2963
+ return Math.floor(value * scale) / scale;
2964
+ }
2965
+ /**
2966
+ * Compute the PERCENTRANK.INC or PERCENTRANK.EXC value.
2967
+ *
2968
+ * For PERCENTRANK.INC (inclusive):
2969
+ * rank = i / (n - 1) when x is at sorted index i (0-based, exact match),
2970
+ * or linear interpolation between the two bracketing values.
2971
+ * x < min or x > max → #N/A.
2972
+ *
2973
+ * For PERCENTRANK.EXC (exclusive):
2974
+ * rank = (i + 1) / (n + 1) when x is at sorted index i (0-based, exact match).
2975
+ * x outside [min, max] or rank outside [1/(n+1), n/(n+1)] → #N/A.
2976
+ */
2977
+ function computePercentRank(sorted, x, inclusive) {
2978
+ const n = sorted.length;
2979
+ if (n === 0) {
2980
+ return null;
2981
+ }
2982
+ // Exact match: find the first index where sorted[i] === x.
2983
+ // Binary search for lower bound.
2984
+ let lo = 0;
2985
+ let hi = n - 1;
2986
+ let found = -1;
2987
+ while (lo <= hi) {
2988
+ const mid = (lo + hi) >>> 1;
2989
+ if (sorted[mid] === x) {
2990
+ // Find first occurrence (ties go to earliest index).
2991
+ let i = mid;
2992
+ while (i > 0 && sorted[i - 1] === x) {
2993
+ i--;
2994
+ }
2995
+ found = i;
2996
+ break;
2997
+ }
2998
+ if (sorted[mid] < x) {
2999
+ lo = mid + 1;
3000
+ }
3001
+ else {
3002
+ hi = mid - 1;
3003
+ }
3004
+ }
3005
+ if (found >= 0) {
3006
+ if (inclusive) {
3007
+ return n === 1 ? 1 : found / (n - 1);
3008
+ }
3009
+ return (found + 1) / (n + 1);
3010
+ }
3011
+ // Interpolation case — x is strictly between sorted[hi] and sorted[lo].
3012
+ // After the loop, lo = insertion point; hi = lo - 1.
3013
+ if (hi < 0 || lo >= n) {
3014
+ return null; // out of range
3015
+ }
3016
+ // Linear interpolation between the two neighbors.
3017
+ const lower = sorted[hi];
3018
+ const upper = sorted[lo];
3019
+ if (upper === lower) {
3020
+ // Degenerate — shouldn't happen given the exact-match check above.
3021
+ return null;
3022
+ }
3023
+ const fraction = (x - lower) / (upper - lower);
3024
+ if (inclusive) {
3025
+ if (n === 1) {
3026
+ return 1;
3027
+ }
3028
+ return (hi + fraction) / (n - 1);
3029
+ }
3030
+ const rank = (hi + 1 + fraction) / (n + 1);
3031
+ // PERCENTRANK.EXC return range is [1/(n+1), n/(n+1)].
3032
+ const minR = 1 / (n + 1);
3033
+ const maxR = n / (n + 1);
3034
+ if (rank < minR || rank > maxR) {
3035
+ return null;
3036
+ }
3037
+ return rank;
3038
+ }
3039
+ function fnPercentRankImpl(args, inclusive) {
3040
+ if (args.length < 2) {
3041
+ return values_1.ERRORS.VALUE;
3042
+ }
3043
+ const vals = (0, _shared_1.flattenNumbers)([args[0]]);
3044
+ const err = (0, _shared_1.firstError)(vals);
3045
+ if (err) {
3046
+ return err;
3047
+ }
3048
+ const xV = (0, values_1.toNumberRV)((0, values_1.topLeft)(args[1]));
3049
+ if ((0, values_1.isError)(xV)) {
3050
+ return xV;
3051
+ }
3052
+ const significanceV = args.length > 2 ? (0, values_1.toNumberRV)((0, values_1.topLeft)(args[2])) : (0, values_1.rvNumber)(3);
3053
+ if ((0, values_1.isError)(significanceV)) {
3054
+ return significanceV;
3055
+ }
3056
+ const significance = significanceV.value;
3057
+ if (significance < 1) {
3058
+ return values_1.ERRORS.NUM;
3059
+ }
3060
+ const nums = vals.map(v => v.value);
3061
+ if (nums.length === 0) {
3062
+ return values_1.ERRORS.NUM;
3063
+ }
3064
+ const sorted = [...nums].sort((a, b) => a - b);
3065
+ const rank = computePercentRank(sorted, xV.value, inclusive);
3066
+ if (rank === null) {
3067
+ return values_1.ERRORS.NA;
3068
+ }
3069
+ const truncated = truncateToSignificance(rank, significance);
3070
+ if (Number.isNaN(truncated)) {
3071
+ return values_1.ERRORS.NUM;
3072
+ }
3073
+ return (0, values_1.rvNumber)(truncated);
3074
+ }
3075
+ const fnPERCENTRANK = args => fnPercentRankImpl(args, true);
3076
+ exports.fnPERCENTRANK = fnPERCENTRANK;
3077
+ const fnPERCENTRANK_INC = args => fnPercentRankImpl(args, true);
3078
+ exports.fnPERCENTRANK_INC = fnPERCENTRANK_INC;
3079
+ const fnPERCENTRANK_EXC = args => fnPercentRankImpl(args, false);
3080
+ exports.fnPERCENTRANK_EXC = fnPERCENTRANK_EXC;
3081
+ // ============================================================================
3082
+ // PROB — probability that values in X-range are between two limits
3083
+ // ============================================================================
3084
+ /**
3085
+ * PROB(x_range, prob_range, lower_limit, [upper_limit]) — probability that
3086
+ * values in x_range are between lower_limit and upper_limit inclusive.
3087
+ *
3088
+ * Excel rules:
3089
+ * - x_range and prob_range must have the same dimensions
3090
+ * - prob_range entries must sum to 1 (±ε); otherwise #NUM!
3091
+ * - Any prob entry ≤ 0 or > 1 → #NUM!
3092
+ * - upper_limit omitted → probability that x = lower_limit
3093
+ * - Result is the sum of prob_range entries for which
3094
+ * lower_limit ≤ x_range value ≤ upper_limit
3095
+ */
3096
+ const fnPROB = args => {
3097
+ if (args.length < 3 || args.length > 4) {
3098
+ return values_1.ERRORS.VALUE;
3099
+ }
3100
+ const xVals = (0, _shared_1.flattenNumbers)([args[0]]);
3101
+ const xErr = (0, _shared_1.firstError)(xVals);
3102
+ if (xErr) {
3103
+ return xErr;
3104
+ }
3105
+ const pVals = (0, _shared_1.flattenNumbers)([args[1]]);
3106
+ const pErr = (0, _shared_1.firstError)(pVals);
3107
+ if (pErr) {
3108
+ return pErr;
3109
+ }
3110
+ if (xVals.length !== pVals.length) {
3111
+ return values_1.ERRORS.NA;
3112
+ }
3113
+ if (xVals.length === 0) {
3114
+ return values_1.ERRORS.NUM;
3115
+ }
3116
+ const lowerV = (0, values_1.toNumberRV)((0, values_1.topLeft)(args[2]));
3117
+ if ((0, values_1.isError)(lowerV)) {
3118
+ return lowerV;
3119
+ }
3120
+ const upperV = args.length > 3 ? (0, values_1.toNumberRV)((0, values_1.topLeft)(args[3])) : lowerV;
3121
+ if ((0, values_1.isError)(upperV)) {
3122
+ return upperV;
3123
+ }
3124
+ const lower = lowerV.value;
3125
+ const upper = upperV.value;
3126
+ if (lower > upper) {
3127
+ return values_1.ERRORS.NUM;
3128
+ }
3129
+ // Probabilities must be in (0, 1] and sum to 1.
3130
+ let total = 0;
3131
+ for (const p of pVals) {
3132
+ const pv = p.value;
3133
+ if (pv <= 0 || pv > 1) {
3134
+ return values_1.ERRORS.NUM;
3135
+ }
3136
+ total += pv;
3137
+ }
3138
+ // Excel's tolerance is fairly loose — well within float noise.
3139
+ if (Math.abs(total - 1) > 1e-9) {
3140
+ return values_1.ERRORS.NUM;
3141
+ }
3142
+ let result = 0;
3143
+ for (let i = 0; i < xVals.length; i++) {
3144
+ const xv = xVals[i].value;
3145
+ if (xv >= lower && xv <= upper) {
3146
+ result += pVals[i].value;
3147
+ }
3148
+ }
3149
+ return (0, values_1.rvNumber)(result);
3150
+ };
3151
+ exports.fnPROB = fnPROB;
3152
+ // ============================================================================
3153
+ // Z.TEST, T.TEST, F.TEST, CHISQ.TEST — hypothesis tests
3154
+ // ============================================================================
3155
+ /**
3156
+ * Standard normal CDF — shared by Z.TEST and the T.TEST approximations.
3157
+ * Uses the same erf-based formula as fnNORMSDIST.
3158
+ */
3159
+ function normalCDF(z) {
3160
+ // Abramowitz & Stegun 7.1.26 approximation, same family used elsewhere.
3161
+ const sign = z < 0 ? -1 : 1;
3162
+ const x = Math.abs(z) / Math.sqrt(2);
3163
+ const t = 1 / (1 + 0.3275911 * x);
3164
+ const y = 1 -
3165
+ ((((1.061405429 * t - 1.453152027) * t + 1.421413741) * t - 0.284496736) * t + 0.254829592) *
3166
+ t *
3167
+ Math.exp(-x * x);
3168
+ return 0.5 * (1 + sign * y);
3169
+ }
3170
+ /**
3171
+ * Z.TEST(array, x, [sigma]) — one-tailed probability value for z-test.
3172
+ * mean = AVERAGE(array), n = COUNT(array)
3173
+ * sigma = provided OR sample standard deviation of array
3174
+ * z = (mean - x) / (sigma / √n)
3175
+ * Z.TEST = 1 - NORM.S.DIST(z, TRUE)
3176
+ */
3177
+ const fnZ_TEST = args => {
3178
+ const vals = (0, _shared_1.flattenNumbers)([args[0]]);
3179
+ const err = (0, _shared_1.firstError)(vals);
3180
+ if (err) {
3181
+ return err;
3182
+ }
3183
+ const xV = (0, values_1.toNumberRV)((0, values_1.topLeft)(args[1]));
3184
+ if ((0, values_1.isError)(xV)) {
3185
+ return xV;
3186
+ }
3187
+ const nums = vals.map(v => v.value);
3188
+ if (nums.length === 0) {
3189
+ return values_1.ERRORS.NA;
3190
+ }
3191
+ const mean = nums.reduce((s, v) => s + v, 0) / nums.length;
3192
+ let sigma;
3193
+ if (args.length > 2) {
3194
+ const sigmaV = (0, values_1.toNumberRV)((0, values_1.topLeft)(args[2]));
3195
+ if ((0, values_1.isError)(sigmaV)) {
3196
+ return sigmaV;
3197
+ }
3198
+ if (sigmaV.value <= 0) {
3199
+ return values_1.ERRORS.NUM;
3200
+ }
3201
+ sigma = sigmaV.value;
3202
+ }
3203
+ else {
3204
+ // Sample std dev.
3205
+ if (nums.length < 2) {
3206
+ return values_1.ERRORS.DIV0;
3207
+ }
3208
+ let ss = 0;
3209
+ for (const v of nums) {
3210
+ ss += (v - mean) * (v - mean);
3211
+ }
3212
+ sigma = Math.sqrt(ss / (nums.length - 1));
3213
+ if (sigma === 0) {
3214
+ return values_1.ERRORS.DIV0;
3215
+ }
3216
+ }
3217
+ const z = (mean - xV.value) / (sigma / Math.sqrt(nums.length));
3218
+ return (0, values_1.rvNumber)(1 - normalCDF(z));
3219
+ };
3220
+ exports.fnZ_TEST = fnZ_TEST;
3221
+ /**
3222
+ * F.TEST(array1, array2) — two-tailed F-test probability comparing
3223
+ * the variances of two samples.
3224
+ *
3225
+ * F = var(larger) / var(smaller) (always >= 1)
3226
+ * P = 2 × P(F_dist(df1, df2) > F)
3227
+ */
3228
+ const fnF_TEST = args => {
3229
+ const v1 = (0, _shared_1.flattenNumbers)([args[0]]);
3230
+ const e1 = (0, _shared_1.firstError)(v1);
3231
+ if (e1) {
3232
+ return e1;
3233
+ }
3234
+ const v2 = (0, _shared_1.flattenNumbers)([args[1]]);
3235
+ const e2 = (0, _shared_1.firstError)(v2);
3236
+ if (e2) {
3237
+ return e2;
3238
+ }
3239
+ const a1 = v1.map(v => v.value);
3240
+ const a2 = v2.map(v => v.value);
3241
+ if (a1.length < 2 || a2.length < 2) {
3242
+ return values_1.ERRORS.DIV0;
3243
+ }
3244
+ const varOf = (xs) => {
3245
+ const mean = xs.reduce((s, v) => s + v, 0) / xs.length;
3246
+ let ss = 0;
3247
+ for (const v of xs) {
3248
+ ss += (v - mean) * (v - mean);
3249
+ }
3250
+ return ss / (xs.length - 1);
3251
+ };
3252
+ const var1 = varOf(a1);
3253
+ const var2 = varOf(a2);
3254
+ if (var1 === 0 || var2 === 0) {
3255
+ return values_1.ERRORS.DIV0;
3256
+ }
3257
+ // Ensure f >= 1 so we evaluate the right tail.
3258
+ const f = var1 / var2;
3259
+ const df1 = a1.length - 1;
3260
+ const df2 = a2.length - 1;
3261
+ // Regularised incomplete beta: Ix(a,b).
3262
+ // F-distribution right-tail = I_{df2/(df2+df1*F)}(df2/2, df1/2).
3263
+ // Two-tailed p = 2 × min(right, left) = 2 × min(right, 1-right).
3264
+ const x = df2 / (df2 + df1 * f);
3265
+ const rightTail = incompleteBeta(x, df2 / 2, df1 / 2);
3266
+ const twoTail = 2 * Math.min(rightTail, 1 - rightTail);
3267
+ return (0, values_1.rvNumber)(twoTail);
3268
+ };
3269
+ exports.fnF_TEST = fnF_TEST;
3270
+ /**
3271
+ * Regularised incomplete beta function I_x(a, b). Lentz's continued
3272
+ * fraction, adapted from Numerical Recipes §6.4. Sufficient precision
3273
+ * for probability-value calculations.
3274
+ */
3275
+ function incompleteBeta(x, a, b) {
3276
+ if (x <= 0) {
3277
+ return 0;
3278
+ }
3279
+ if (x >= 1) {
3280
+ return 1;
3281
+ }
3282
+ const bt = Math.exp(lnGamma(a + b) - lnGamma(a) - lnGamma(b) + a * Math.log(x) + b * Math.log(1 - x));
3283
+ const useFront = x < (a + 1) / (a + b + 2);
3284
+ const cf = (xx, aa, bb) => {
3285
+ const maxIt = 200;
3286
+ const eps = 3e-7;
3287
+ const qab = aa + bb;
3288
+ const qap = aa + 1;
3289
+ const qam = aa - 1;
3290
+ let c = 1;
3291
+ let d = 1 - (qab * xx) / qap;
3292
+ if (Math.abs(d) < 1e-30) {
3293
+ d = 1e-30;
3294
+ }
3295
+ d = 1 / d;
3296
+ let h = d;
3297
+ for (let m = 1; m <= maxIt; m++) {
3298
+ const m2 = 2 * m;
3299
+ let aa2 = (m * (bb - m) * xx) / ((qam + m2) * (aa + m2));
3300
+ d = 1 + aa2 * d;
3301
+ if (Math.abs(d) < 1e-30) {
3302
+ d = 1e-30;
3303
+ }
3304
+ c = 1 + aa2 / c;
3305
+ if (Math.abs(c) < 1e-30) {
3306
+ c = 1e-30;
3307
+ }
3308
+ d = 1 / d;
3309
+ h *= d * c;
3310
+ aa2 = (-(aa + m) * (qab + m) * xx) / ((aa + m2) * (qap + m2));
3311
+ d = 1 + aa2 * d;
3312
+ if (Math.abs(d) < 1e-30) {
3313
+ d = 1e-30;
3314
+ }
3315
+ c = 1 + aa2 / c;
3316
+ if (Math.abs(c) < 1e-30) {
3317
+ c = 1e-30;
3318
+ }
3319
+ d = 1 / d;
3320
+ const del = d * c;
3321
+ h *= del;
3322
+ if (Math.abs(del - 1) < eps) {
3323
+ break;
3324
+ }
3325
+ }
3326
+ return h;
3327
+ };
3328
+ if (useFront) {
3329
+ return (bt * cf(x, a, b)) / a;
3330
+ }
3331
+ return 1 - (bt * cf(1 - x, b, a)) / b;
3332
+ }
3333
+ /**
3334
+ * T.TEST(array1, array2, tails, type) — tails in {1, 2}, type in {1, 2, 3}.
3335
+ * type 1: paired
3336
+ * type 2: two-sample, equal variance
3337
+ * type 3: two-sample, unequal variance (Welch's)
3338
+ */
3339
+ const fnT_TEST = args => {
3340
+ const v1 = (0, _shared_1.flattenNumbers)([args[0]]);
3341
+ const e1 = (0, _shared_1.firstError)(v1);
3342
+ if (e1) {
3343
+ return e1;
3344
+ }
3345
+ const v2 = (0, _shared_1.flattenNumbers)([args[1]]);
3346
+ const e2 = (0, _shared_1.firstError)(v2);
3347
+ if (e2) {
3348
+ return e2;
3349
+ }
3350
+ const tailsV = (0, values_1.toNumberRV)((0, values_1.topLeft)(args[2]));
3351
+ if ((0, values_1.isError)(tailsV)) {
3352
+ return tailsV;
3353
+ }
3354
+ const typeV = (0, values_1.toNumberRV)((0, values_1.topLeft)(args[3]));
3355
+ if ((0, values_1.isError)(typeV)) {
3356
+ return typeV;
3357
+ }
3358
+ const tails = Math.trunc(tailsV.value);
3359
+ const type = Math.trunc(typeV.value);
3360
+ if (tails !== 1 && tails !== 2) {
3361
+ return values_1.ERRORS.NUM;
3362
+ }
3363
+ if (type !== 1 && type !== 2 && type !== 3) {
3364
+ return values_1.ERRORS.NUM;
3365
+ }
3366
+ const a1 = v1.map(v => v.value);
3367
+ const a2 = v2.map(v => v.value);
3368
+ const mean = (xs) => xs.reduce((s, v) => s + v, 0) / xs.length;
3369
+ const sampleVar = (xs, m) => {
3370
+ let ss = 0;
3371
+ for (const v of xs) {
3372
+ ss += (v - m) * (v - m);
3373
+ }
3374
+ return ss / (xs.length - 1);
3375
+ };
3376
+ let t;
3377
+ let df;
3378
+ if (type === 1) {
3379
+ // Paired
3380
+ if (a1.length !== a2.length) {
3381
+ return values_1.ERRORS.NA;
3382
+ }
3383
+ if (a1.length < 2) {
3384
+ return values_1.ERRORS.DIV0;
3385
+ }
3386
+ const diffs = a1.map((v, i) => v - a2[i]);
3387
+ const md = mean(diffs);
3388
+ const sd2 = sampleVar(diffs, md);
3389
+ if (sd2 === 0) {
3390
+ return values_1.ERRORS.DIV0;
3391
+ }
3392
+ t = md / Math.sqrt(sd2 / diffs.length);
3393
+ df = diffs.length - 1;
3394
+ }
3395
+ else if (type === 2) {
3396
+ // Two-sample, equal variance (pooled)
3397
+ const n1 = a1.length;
3398
+ const n2 = a2.length;
3399
+ if (n1 < 2 || n2 < 2) {
3400
+ return values_1.ERRORS.DIV0;
3401
+ }
3402
+ const m1 = mean(a1);
3403
+ const m2 = mean(a2);
3404
+ const s1 = sampleVar(a1, m1);
3405
+ const s2 = sampleVar(a2, m2);
3406
+ const sp2 = ((n1 - 1) * s1 + (n2 - 1) * s2) / (n1 + n2 - 2);
3407
+ if (sp2 === 0) {
3408
+ return values_1.ERRORS.DIV0;
3409
+ }
3410
+ t = (m1 - m2) / Math.sqrt(sp2 * (1 / n1 + 1 / n2));
3411
+ df = n1 + n2 - 2;
3412
+ }
3413
+ else {
3414
+ // Two-sample, unequal variance (Welch's)
3415
+ const n1 = a1.length;
3416
+ const n2 = a2.length;
3417
+ if (n1 < 2 || n2 < 2) {
3418
+ return values_1.ERRORS.DIV0;
3419
+ }
3420
+ const m1 = mean(a1);
3421
+ const m2 = mean(a2);
3422
+ const s1 = sampleVar(a1, m1);
3423
+ const s2 = sampleVar(a2, m2);
3424
+ if (s1 === 0 && s2 === 0) {
3425
+ return values_1.ERRORS.DIV0;
3426
+ }
3427
+ const se2 = s1 / n1 + s2 / n2;
3428
+ t = (m1 - m2) / Math.sqrt(se2);
3429
+ df = (se2 * se2) / (((s1 / n1) * (s1 / n1)) / (n1 - 1) + ((s2 / n2) * (s2 / n2)) / (n2 - 1));
3430
+ }
3431
+ // Two-tailed p = I_{df/(df + t^2)}(df/2, 1/2)
3432
+ const x = df / (df + t * t);
3433
+ const oneTail = 0.5 * incompleteBeta(x, df / 2, 0.5);
3434
+ return (0, values_1.rvNumber)(tails === 1 ? oneTail : 2 * oneTail);
3435
+ };
3436
+ exports.fnT_TEST = fnT_TEST;
3437
+ /**
3438
+ * CHISQ.TEST(actual_range, expected_range) — chi-square independence test.
3439
+ *
3440
+ * χ² = Σ (actual_i - expected_i)² / expected_i
3441
+ * df = (rows-1)(cols-1) for a contingency table, or n-1 for 1-D
3442
+ * p = 1 - CHISQ.DIST(χ², df, TRUE)
3443
+ */
3444
+ const fnCHISQ_TEST = args => {
3445
+ if (args[0].kind !== 5 /* RVKind.Array */ || args[1].kind !== 5 /* RVKind.Array */) {
3446
+ return values_1.ERRORS.VALUE;
3447
+ }
3448
+ const a = args[0];
3449
+ const e = args[1];
3450
+ if (a.height !== e.height || a.width !== e.width) {
3451
+ return values_1.ERRORS.NA;
3452
+ }
3453
+ let chi2 = 0;
3454
+ for (let r = 0; r < a.height; r++) {
3455
+ for (let c = 0; c < a.width; c++) {
3456
+ const av = a.rows[r][c];
3457
+ const ev = e.rows[r][c];
3458
+ if (av.kind === 4 /* RVKind.Error */) {
3459
+ return av;
3460
+ }
3461
+ if (ev.kind === 4 /* RVKind.Error */) {
3462
+ return ev;
3463
+ }
3464
+ if (av.kind !== 1 /* RVKind.Number */ || ev.kind !== 1 /* RVKind.Number */) {
3465
+ return values_1.ERRORS.VALUE;
3466
+ }
3467
+ if (ev.value <= 0) {
3468
+ return values_1.ERRORS.NUM;
3469
+ }
3470
+ const diff = av.value - ev.value;
3471
+ chi2 += (diff * diff) / ev.value;
3472
+ }
3473
+ }
3474
+ // df: (rows-1)(cols-1) for contingency tables, n-1 for 1-D.
3475
+ let df;
3476
+ if (a.height === 1 || a.width === 1) {
3477
+ df = a.height * a.width - 1;
3478
+ }
3479
+ else {
3480
+ df = (a.height - 1) * (a.width - 1);
3481
+ }
3482
+ if (df < 1) {
3483
+ return values_1.ERRORS.NA;
3484
+ }
3485
+ // p = 1 - CHISQ.DIST.CDF(chi2, df) = right tail
3486
+ return (0, values_1.rvNumber)(1 - gammaIncomplete(df / 2, chi2 / 2));
3487
+ };
3488
+ exports.fnCHISQ_TEST = fnCHISQ_TEST;