1/**
2 * Works with TypeScript `number` values.
3 *
4 * This module exposes the native `Number` constructor together with helpers for
5 * checking, parsing, arithmetic, safe division, comparison, range checks,
6 * clamping, rounding, ordering, equivalence, and numeric aggregation.
7 *
8 * @since 2.0.0
9 */
10import * as Equ from "./Equivalence.ts"
11import { dual } from "./Function.ts"
12import * as Option from "./Option.ts"
13import * as order from "./Order.ts"
14import type { Ordering } from "./Ordering.ts"
15import * as predicate from "./Predicate.ts"
16import * as Reducer from "./Reducer.ts"
17
18/**
19 * Exposes the global number constructor.
20 *
21 * **When to use**
22 *
23 * Use to access native JavaScript numeric coercion from the Effect module
24 * namespace.
25 *
26 * **Gotchas**
27 *
28 * This follows native `Number` coercion rules, including empty strings
29 * becoming `0` and invalid numeric strings becoming `NaN`.
30 *
31 * @see {@link parse} for parsing strings into an `Option`
32 *
33 * **Example** (Coercing values to numbers)
34 *
35 * ```ts import.meta.vitest
36 * import { Number as N } from "effect"
37 *
38 * N.Number("42") // => 42
39 * N.Number("3.14") // => 3.14
40 * ```
41 *
42 * @category constructors
43 * @since 4.0.0
44 */
45export const Number = globalThis.Number
46
47/**
48 * Checks whether a value is a `number`.
49 *
50 * **When to use**
51 *
52 * Use to validate unknown input and narrow it to `number`.
53 *
54 * **Example** (Checking for numbers)
55 *
56 * ```ts import.meta.vitest
57 * import { Number } from "effect"
58 *
59 * Number.isNumber(2) // => true
60 * Number.isNumber("2") // => false
61 * ```
62 *
63 * @category guards
64 * @since 2.0.0
65 */
66export const isNumber: (input: unknown) => input is number = predicate.isNumber
67
68/**
69 * Provides an addition operation on `number`s.
70 *
71 * **When to use**
72 *
73 * Use to add two numbers.
74 *
75 * **Example** (Adding numbers)
76 *
77 * ```ts import.meta.vitest
78 * import { Number } from "effect"
79 *
80 * Number.sum(2, 3) // => 5
81 * ```
82 *
83 * @see {@link sumAll} for summing an iterable of numbers
84 *
85 * @category math
86 * @since 2.0.0
87 */
88export const sum: {
89 (that: number): (self: number) => number
90 (self: number, that: number): number
91} = dual(2, (self: number, that: number): number => self + that)
92
93/**
94 * Provides a multiplication operation on `number`s.
95 *
96 * **When to use**
97 *
98 * Use to multiply two numbers.
99 *
100 * **Example** (Multiplying numbers)
101 *
102 * ```ts import.meta.vitest
103 * import { Number } from "effect"
104 *
105 * Number.multiply(2, 3) // => 6
106 * ```
107 *
108 * @see {@link multiplyAll} for multiplying an iterable of numbers
109 *
110 * @category math
111 * @since 2.0.0
112 */
113export const multiply: {
114 (that: number): (self: number) => number
115 (self: number, that: number): number
116} = dual(2, (self: number, that: number): number => self * that)
117
118/**
119 * Provides a subtraction operation on `number`s.
120 *
121 * **When to use**
122 *
123 * Use to subtract one number from another.
124 *
125 * **Example** (Subtracting numbers)
126 *
127 * ```ts import.meta.vitest
128 * import { Number } from "effect"
129 *
130 * Number.subtract(2, 3) // => -1
131 * ```
132 *
133 * @category math
134 * @since 2.0.0
135 */
136export const subtract: {
137 (that: number): (self: number) => number
138 (self: number, that: number): number
139} = dual(2, (self: number, that: number): number => self - that)
140
141/**
142 * Divides `number`s safely, returning `Option.none()` if the divisor is `0`.
143 *
144 * **When to use**
145 *
146 * Use to divide numbers while representing division by zero as `Option.none`.
147 *
148 * **Example** (Dividing numbers safely)
149 *
150 * ```ts import.meta.vitest
151 * import { Number, Option } from "effect"
152 *
153 * Number.divide(6, 3) // => Option.some(2)
154 * Number.divide(6, 0) // => Option.none()
155 * ```
156 *
157 * @see {@link divideUnsafe} for division that throws when the divisor is zero
158 * @see {@link remainder} for the numeric remainder operation
159 *
160 * @category math
161 * @since 2.0.0
162 */
163export const divide: {
164 (that: number): (self: number) => Option.Option<number>
165 (self: number, that: number): Option.Option<number>
166} = dual(
167 2,
168 (self: number, that: number): Option.Option<number> => that === 0 ? Option.none() : Option.some(self / that)
169)
170
171/**
172 * Divides two `number` values without returning an `Option`.
173 *
174 * **When to use**
175 *
176 * Use to divide `number` values where the divisor is known to be non-zero and
177 * a plain `number` result is preferred over handling `Option.none`.
178 *
179 * **Gotchas**
180 *
181 * Throws a `RangeError` if the divisor is `0`.
182 *
183 * **Example** (Dividing numbers unsafely)
184 *
185 * ```ts import.meta.vitest
186 * import { Number, Result } from "effect"
187 *
188 * Number.divideUnsafe(6, 3) // => 2
189 *
190 * const failure = Result.try({
191 * try: () => Number.divideUnsafe(6, 0),
192 * catch: (error) => (error as Error).message
193 * })
194 * Result.merge(failure) // => "Division by zero"
195 * ```
196 *
197 * @see {@link divide} for division that returns `Option.none` when the divisor is zero
198 *
199 * @category math
200 * @since 4.0.0
201 */
202export const divideUnsafe: {
203 (that: number): (self: number) => number
204 (self: number, that: number): number
205} = dual(
206 2,
207 (self: number, that: number): number =>
208 Option.getOrThrowWith(divide(self, that), () => new RangeError("Division by zero"))
209)
210
211/**
212 * Returns the result of adding `1` to a given number.
213 *
214 * **When to use**
215 *
216 * Use to increment a numeric counter by one.
217 *
218 * **Example** (Incrementing a number)
219 *
220 * ```ts import.meta.vitest
221 * import { Number } from "effect"
222 *
223 * Number.increment(2) // => 3
224 * ```
225 *
226 * @category math
227 * @since 2.0.0
228 */
229export const increment = (n: number): number => n + 1
230
231/**
232 * Decrements a number by `1`.
233 *
234 * **When to use**
235 *
236 * Use to decrement a numeric counter by one.
237 *
238 * **Example** (Decrementing a number)
239 *
240 * ```ts import.meta.vitest
241 * import { Number } from "effect"
242 *
243 * Number.decrement(3) // => 2
244 * ```
245 *
246 * @category math
247 * @since 2.0.0
248 */
249export const decrement = (n: number): number => n - 1
250
251/**
252 * Order instance for `number` values.
253 *
254 * **When to use**
255 *
256 * Use when you need to sort or compare numbers through APIs that accept an
257 * ordering instance.
258 *
259 * **Example** (Comparing numbers)
260 *
261 * ```ts import.meta.vitest
262 * import { Number } from "effect"
263 *
264 * Number.Order(1, 2) // => -1
265 * Number.Order(2, 1) // => 1
266 * Number.Order(1, 1) // => 0
267 * ```
268 *
269 * @category instances
270 * @since 2.0.0
271 */
272export const Order: order.Order<number> = order.Number
273
274/**
275 * Equivalence instance for numbers where `NaN` is considered equal to `NaN`.
276 *
277 * **When to use**
278 *
279 * Use when checking numeric equality through APIs that accept an equivalence
280 * relation.
281 *
282 * **Example** (Comparing numbers for equivalence)
283 *
284 * ```ts import.meta.vitest
285 * import { Number } from "effect"
286 *
287 * Number.Equivalence(1, 1) // => true
288 * Number.Equivalence(1, 2) // => false
289 * Number.Equivalence(NaN, NaN) // => true
290 * ```
291 *
292 * @category instances
293 * @since 2.0.0
294 */
295export const Equivalence: Equ.Equivalence<number> = Equ.Number
296
297/**
298 * Returns `true` if the first argument is less than the second, otherwise `false`.
299 *
300 * **When to use**
301 *
302 * Use to test whether one number is strictly less than another.
303 *
304 * **Example** (Checking less-than comparisons)
305 *
306 * ```ts import.meta.vitest
307 * import { Number } from "effect"
308 *
309 * Number.isLessThan(2, 3) // => true
310 * Number.isLessThan(3, 3) // => false
311 * Number.isLessThan(4, 3) // => false
312 * ```
313 *
314 * @category predicates
315 * @since 4.0.0
316 */
317export const isLessThan: {
318 (that: number): (self: number) => boolean
319 (self: number, that: number): boolean
320} = order.isLessThan(Order)
321
322/**
323 * Returns a function that checks if a given `number` is less than or equal to the provided one.
324 *
325 * **When to use**
326 *
327 * Use to test whether one number is less than or equal to another.
328 *
329 * **Example** (Checking less-than-or-equal comparisons)
330 *
331 * ```ts import.meta.vitest
332 * import { Number } from "effect"
333 *
334 * Number.isLessThanOrEqualTo(2, 3) // => true
335 * Number.isLessThanOrEqualTo(3, 3) // => true
336 * Number.isLessThanOrEqualTo(4, 3) // => false
337 * ```
338 *
339 * @category predicates
340 * @since 4.0.0
341 */
342export const isLessThanOrEqualTo: {
343 (that: number): (self: number) => boolean
344 (self: number, that: number): boolean
345} = order.isLessThanOrEqualTo(Order)
346
347/**
348 * Returns `true` if the first argument is greater than the second, otherwise `false`.
349 *
350 * **When to use**
351 *
352 * Use to test whether one number is strictly greater than another.
353 *
354 * **Example** (Checking greater-than comparisons)
355 *
356 * ```ts import.meta.vitest
357 * import { Number } from "effect"
358 *
359 * Number.isGreaterThan(2, 3) // => false
360 * Number.isGreaterThan(3, 3) // => false
361 * Number.isGreaterThan(4, 3) // => true
362 * ```
363 *
364 * @category predicates
365 * @since 4.0.0
366 */
367export const isGreaterThan: {
368 (that: number): (self: number) => boolean
369 (self: number, that: number): boolean
370} = order.isGreaterThan(Order)
371
372/**
373 * Returns a function that checks if a given `number` is greater than or equal to the provided one.
374 *
375 * **When to use**
376 *
377 * Use to test whether one number is greater than or equal to another.
378 *
379 * **Example** (Checking greater-than-or-equal comparisons)
380 *
381 * ```ts import.meta.vitest
382 * import { Number } from "effect"
383 *
384 * Number.isGreaterThanOrEqualTo(2, 3) // => false
385 * Number.isGreaterThanOrEqualTo(3, 3) // => true
386 * Number.isGreaterThanOrEqualTo(4, 3) // => true
387 * ```
388 *
389 * @category predicates
390 * @since 4.0.0
391 */
392export const isGreaterThanOrEqualTo: {
393 (that: number): (self: number) => boolean
394 (self: number, that: number): boolean
395} = order.isGreaterThanOrEqualTo(Order)
396
397/**
398 * Checks whether a `number` is between a `minimum` and `maximum` value (inclusive).
399 *
400 * **When to use**
401 *
402 * Use to test whether a number falls inside an inclusive range.
403 *
404 * **Example** (Checking inclusive ranges)
405 *
406 * ```ts import.meta.vitest
407 * import { Number } from "effect"
408 *
409 * const between = Number.between({ minimum: 0, maximum: 5 })
410 *
411 * between(3) // => true
412 * between(-1) // => false
413 * between(6) // => false
414 * ```
415 *
416 * @see {@link clamp} for forcing a number into an inclusive range
417 *
418 * @category predicates
419 * @since 2.0.0
420 */
421export const between: {
422 (options: {
423 minimum: number
424 maximum: number
425 }): (self: number) => boolean
426 (self: number, options: {
427 minimum: number
428 maximum: number
429 }): boolean
430} = order.isBetween(Order)
431
432/**
433 * Restricts the given `number` to be within the range specified by the `minimum` and `maximum` values.
434 *
435 * **When to use**
436 *
437 * Use to force a number into an inclusive range.
438 *
439 * **Details**
440 *
441 * - If the `number` is less than the `minimum` value, the function returns the `minimum` value.
442 * - If the `number` is greater than the `maximum` value, the function returns the `maximum` value.
443 * - Otherwise, it returns the original `number`.
444 * - `NaN` is ordered below every non-`NaN` number by `Number.Order`, so it is
445 * clamped to `minimum`.
446 *
447 * **Example** (Clamping to a range)
448 *
449 * ```ts import.meta.vitest
450 * import { Number } from "effect"
451 *
452 * const clamp = Number.clamp({ minimum: 1, maximum: 5 })
453 *
454 * clamp(3) // => 3
455 * clamp(0) // => 1
456 * clamp(6) // => 5
457 * ```
458 *
459 * @see {@link between} for checking whether a number is already inside a range
460 *
461 * @category math
462 * @since 2.0.0
463 */
464export const clamp: {
465 (options: {
466 minimum: number
467 maximum: number
468 }): (self: number) => number
469 (self: number, options: {
470 minimum: number
471 maximum: number
472 }): number
473} = order.clamp(Order)
474
475/**
476 * Returns the minimum between two `number`s.
477 *
478 * **When to use**
479 *
480 * Use to select the smaller of two numbers.
481 *
482 * **Example** (Finding the minimum)
483 *
484 * ```ts import.meta.vitest
485 * import { Number } from "effect"
486 *
487 * Number.min(2, 3) // => 2
488 * ```
489 *
490 * @see {@link max} for selecting the larger value
491 *
492 * @category math
493 * @since 2.0.0
494 */
495export const min: {
496 (that: number): (self: number) => number
497 (self: number, that: number): number
498} = order.min(Order)
499
500/**
501 * Returns the maximum between two `number`s.
502 *
503 * **When to use**
504 *
505 * Use to select the larger of two numbers.
506 *
507 * **Example** (Finding the maximum)
508 *
509 * ```ts import.meta.vitest
510 * import { Number } from "effect"
511 *
512 * Number.max(2, 3) // => 3
513 * ```
514 *
515 * @see {@link min} for selecting the smaller value
516 *
517 * @category math
518 * @since 2.0.0
519 */
520export const max: {
521 (that: number): (self: number) => number
522 (self: number, that: number): number
523} = order.max(Order)
524
525/**
526 * Determines the sign of a given `number`.
527 *
528 * **When to use**
529 *
530 * Use to classify a number as negative, zero, or positive.
531 *
532 * **Example** (Determining the sign)
533 *
534 * ```ts import.meta.vitest
535 * import { Number } from "effect"
536 *
537 * Number.sign(-5) // => -1
538 * Number.sign(0) // => 0
539 * Number.sign(5) // => 1
540 * ```
541 *
542 * @category math
543 * @since 2.0.0
544 */
545export const sign = (n: number): Ordering => Order(n, 0)
546
547/**
548 * Takes an `Iterable` of `number`s and returns their sum as a single `number`.
549 *
550 * **When to use**
551 *
552 * Use to sum all numbers in an iterable.
553 *
554 * **Example** (Summing an iterable)
555 *
556 * ```ts import.meta.vitest
557 * import { Number } from "effect"
558 *
559 * Number.sumAll([2, 3, 4]) // => 9
560 * ```
561 *
562 * @see {@link sum} for adding two numbers
563 * @see {@link ReducerSum} for summing through APIs that consume a `Reducer`
564 *
565 * @category math
566 * @since 2.0.0
567 */
568export const sumAll = (collection: Iterable<number>): number => {
569 let out = 0
570 for (const n of collection) {
571 out += n
572 }
573 return out
574}
575
576/**
577 * Takes an `Iterable` of `number`s and returns their multiplication as a single `number`.
578 *
579 * **When to use**
580 *
581 * Use to multiply all numbers in an iterable.
582 *
583 * **Example** (Multiplying an iterable)
584 *
585 * ```ts import.meta.vitest
586 * import { Number } from "effect"
587 *
588 * Number.multiplyAll([2, 3, 4]) // => 24
589 * ```
590 *
591 * @see {@link multiply} for multiplying two numbers
592 * @see {@link ReducerMultiply} for multiplying through APIs that consume a `Reducer`
593 *
594 * @category math
595 * @since 2.0.0
596 */
597export const multiplyAll = (collection: Iterable<number>): number => {
598 let out = 1
599 for (const n of collection) {
600 if (n === 0) {
601 return 0
602 }
603 out *= n
604 }
605 return out
606}
607
608/**
609 * Returns the remainder left over when one operand is divided by a second operand, always taking the sign of the dividend.
610 *
611 * **When to use**
612 *
613 * Use to compute a numeric remainder while preserving decimal precision better
614 * than direct JavaScript `%` for decimal operands.
615 *
616 * **Example** (Calculating remainders)
617 *
618 * ```ts import.meta.vitest
619 * import { Number } from "effect"
620 *
621 * Number.remainder(2, 2) // => 0
622 * Number.remainder(3, 2) // => 1
623 * Number.remainder(-4, 2) // => -0
624 * ```
625 *
626 * @see {@link divide} for quotient calculation with division-by-zero represented as `Option.none`
627 *
628 * @category math
629 * @since 2.0.0
630 */
631export const remainder: {
632 (divisor: number): (self: number) => number
633 (self: number, divisor: number): number
634} = dual(2, (self: number, divisor: number): number => {
635 if (!globalThis.Number.isFinite(self) || !globalThis.Number.isFinite(divisor) || divisor === 0) {
636 return NaN
637 }
638 if (globalThis.Number.isInteger(self) && globalThis.Number.isInteger(divisor)) {
639 return self % divisor
640 }
641
642 const [selfCoefficient, selfExponent] = toScientificInteger(self)
643 const [divisorCoefficient, divisorExponent] = toScientificInteger(divisor)
644 const exponent = Math.min(selfExponent, divisorExponent)
645 const selfInteger = selfCoefficient * BigInt(10) ** BigInt(selfExponent - exponent)
646 const divisorInteger = divisorCoefficient * BigInt(10) ** BigInt(divisorExponent - exponent)
647 const out = selfInteger % divisorInteger
648 if (out === BigInt(0)) {
649 return self < 0 || Object.is(self, -0) ? -0 : 0
650 }
651 const remainder = globalThis.Number(`${out}e${exponent}`)
652 return remainder === 0 ? Math.sign(self) * globalThis.Number.MIN_VALUE : remainder
653})
654
655function toScientificInteger(n: number): readonly [coefficient: bigint, exponent: number] {
656 if (globalThis.Number.isInteger(n)) {
657 return [BigInt(n), 0]
658 }
659 const scientific = Math.abs(n).toExponential()
660 const eIndex = scientific.indexOf("e")
661 const digits = scientific.slice(0, eIndex).replace(".", "")
662 const coefficient = BigInt(digits) * (n < 0 ? -BigInt(1) : BigInt(1))
663 return [coefficient, globalThis.Number(scientific.slice(eIndex + 1)) - digits.length + 1]
664}
665
666/**
667 * Returns the next power of 2 from the given number.
668 *
669 * **When to use**
670 *
671 * Use to round a number up to the next power of two.
672 *
673 * **Example** (Finding the next power of two)
674 *
675 * ```ts import.meta.vitest
676 * import { Number } from "effect"
677 *
678 * Number.nextPow2(5) // => 8
679 * Number.nextPow2(17) // => 32
680 * ```
681 *
682 * @category math
683 * @since 2.0.0
684 */
685export const nextPow2 = (n: number): number => {
686 const nextPow = Math.ceil(Math.log(n) / Math.log(2))
687 return Math.max(Math.pow(2, nextPow), 2)
688}
689
690/**
691 * Parses a `number` from a `string` safely using the `Number()` function.
692 * The following special string values are supported: "NaN", "Infinity", "-Infinity".
693 *
694 * **When to use**
695 *
696 * Use to parse numeric text without throwing on invalid input.
697 *
698 * **Example** (Parsing numbers from strings)
699 *
700 * ```ts import.meta.vitest
701 * import { Number, Option } from "effect"
702 *
703 * Number.parse("42") // => Option.some(42)
704 * Number.parse("3.14") // => Option.some(3.14)
705 * Number.parse("NaN") // => Option.some(NaN)
706 * Number.parse("Infinity") // => Option.some(Infinity)
707 * Number.parse("-Infinity") // => Option.some(-Infinity)
708 * Number.parse("not a number") // => Option.none()
709 * ```
710 *
711 * @see {@link Number} for native constructor coercion
712 *
713 * @category constructors
714 * @since 2.0.0
715 */
716export const parse = (s: string): Option.Option<number> => {
717 if (s === "NaN") {
718 return Option.some(NaN)
719 }
720 if (s === "Infinity") {
721 return Option.some(Infinity)
722 }
723 if (s === "-Infinity") {
724 return Option.some(-Infinity)
725 }
726 if (s.trim() === "") {
727 return Option.none()
728 }
729 const n = Number(s)
730 return Number.isNaN(n) ? Option.none() : Option.some(n)
731}
732
733/**
734 * Returns the number rounded with the given precision.
735 *
736 * **When to use**
737 *
738 * Use to round a number to a fixed number of decimal places.
739 *
740 * **Example** (Rounding with precision)
741 *
742 * ```ts import.meta.vitest
743 * import { Number } from "effect"
744 *
745 * Number.round(1.1234, 2) // => 1.12
746 * Number.round(1.567, 2) // => 1.57
747 * ```
748 *
749 * @category math
750 * @since 3.8.0
751 */
752export const round: {
753 (precision: number): (self: number) => number
754 (self: number, precision: number): number
755} = dual(2, (self: number, precision: number): number => {
756 const factor = Math.pow(10, precision)
757 return Math.round(self * factor) / factor
758})
759
760/**
761 * Reducer for combining `number`s using addition.
762 *
763 * **When to use**
764 *
765 * Use to sum many numbers through APIs that consume a `Reducer`.
766 *
767 * **Details**
768 *
769 * The reducer starts from `0`, so `combineAll([])` returns `0`.
770 *
771 * @see {@link sumAll} for summing an iterable directly
772 * @see {@link ReducerMultiply} for multiplying number values
773 *
774 * @category math
775 * @since 4.0.0
776 */
777export const ReducerSum: Reducer.Reducer<number> = Reducer.make((a, b) => a + b, 0)
778
779/**
780 * Reducer for combining `number`s using multiplication.
781 *
782 * **When to use**
783 *
784 * Use to multiply many numbers through APIs that consume a `Reducer`.
785 *
786 * **Details**
787 *
788 * The reducer starts from `1`, so reducing an empty collection returns `1`.
789 *
790 * **Gotchas**
791 *
792 * Reducing an iterable short-circuits when it sees `0`, so later elements are
793 * not consumed.
794 *
795 * @see {@link multiplyAll} for multiplying an iterable directly
796 *
797 * @category math
798 * @since 4.0.0
799 */
800export const ReducerMultiply: Reducer.Reducer<number> = Reducer.make((a, b) => a * b, 1, (collection) => {
801 let acc = 1
802 for (const n of collection) {
803 if (n === 0) return 0
804 acc *= n
805 }
806 return acc
807})
808
809/**
810 * Reducer for reducing `number`s by keeping the maximum value.
811 *
812 * **When to use**
813 *
814 * Use to keep the largest number through APIs that consume a `Reducer`.
815 *
816 * **Details**
817 *
818 * The reducer starts from `-Infinity`, so reducing an empty collection returns
819 * `-Infinity`.
820 *
821 * **Gotchas**
822 *
823 * `NaN` values propagate through `Math.max`.
824 *
825 * @see {@link ReducerMin} for keeping the smallest number
826 * @see {@link max} for comparing two numbers directly
827 *
828 * @category math
829 * @since 4.0.0
830 */
831export const ReducerMax: Reducer.Reducer<number> = Reducer.make((a, b) => Math.max(a, b), -Infinity)
832
833/**
834 * Reducer for reducing `number`s by keeping the minimum value.
835 *
836 * **When to use**
837 *
838 * Use to keep the smallest number through APIs that consume a `Reducer`.
839 *
840 * **Details**
841 *
842 * The reducer starts from `Infinity`, so reducing an empty collection returns
843 * `Infinity`.
844 *
845 * **Gotchas**
846 *
847 * `NaN` values propagate through `Math.min`.
848 *
849 * @see {@link ReducerMax} for keeping the largest number
850 * @see {@link min} for comparing two numbers directly
851 *
852 * @category math
853 * @since 4.0.0
854 */
855export const ReducerMin: Reducer.Reducer<number> = Reducer.make((a, b) => Math.min(a, b), Infinity)