@helpers4/number 2.0.0 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,6 +13,7 @@ A set of helpers for working with URLs.
13
13
 
14
14
  <!-- AUTOMATIC-METHODS -->
15
15
  - clamp
16
+ - correctFloat
16
17
  - formatCompact
17
18
  - formatSize
18
19
  - inRange
@@ -33,6 +34,7 @@ A set of helpers for working with URLs.
33
34
  - [function](../function)
34
35
  - [id](../id)
35
36
  - [markdown](../markdown)
37
+ - [node](../node)
36
38
  - [object](../object)
37
39
  - [observable](../observable)
38
40
  - [promise](../promise)
@@ -54,6 +56,7 @@ A set of helpers for working with URLs.
54
56
  | function | [@helpers4/function](https://www.npmjs.com/package/@helpers4/function) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/function) | Function utilities and type guards |
55
57
  | id | [@helpers4/id](https://www.npmjs.com/package/@helpers4/id) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/id) | Unique identifier generation utilities |
56
58
  | markdown | [@helpers4/markdown](https://www.npmjs.com/package/@helpers4/markdown) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/markdown) | Markdown formatting and escaping utilities |
59
+ | node | [@helpers4/node](https://www.npmjs.com/package/@helpers4/node) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/node) | Node.js-specific utilities |
57
60
  | number | [@helpers4/number](https://www.npmjs.com/package/@helpers4/number) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/number) | Number utility functions and validation |
58
61
  | object | [@helpers4/object](https://www.npmjs.com/package/@helpers4/object) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/object) | Object manipulation utilities |
59
62
  | observable | [@helpers4/observable](https://www.npmjs.com/package/@helpers4/observable) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/observable) | Observable utilities and combinators |
package/lib/index.d.ts CHANGED
@@ -13,6 +13,30 @@
13
13
  */
14
14
  declare function clamp(value: number, min: number, max: number): number;
15
15
 
16
+ /**
17
+ * This file is part of helpers4.
18
+ * Copyright (C) 2025 baxyz
19
+ * SPDX-License-Identifier: LGPL-3.0-or-later
20
+ */
21
+ /**
22
+ * Corrects floating-point arithmetic errors by rounding to a given number
23
+ * of significant digits. Useful after calculations that accumulate binary
24
+ * floating-point drift (e.g. `0.1 + 0.2 === 0.30000000000000004`).
25
+ *
26
+ * The default precision of 14 significant digits eliminates typical
27
+ * rounding noise for values in the range used by most applications.
28
+ * Note: for values whose integer part already consumes 14 or more digits
29
+ * (i.e. |value| ≥ 1e13), toPrecision(14) has no room left for decimal
30
+ * digits and will silently truncate them. Increase `precision` if you
31
+ * need to correct drift in very large numbers.
32
+ *
33
+ * @param value - The floating-point value to correct
34
+ * @param precision - Integer number of significant digits (default: 14)
35
+ * @returns The corrected value
36
+ * @since 2.0.2
37
+ */
38
+ declare function correctFloat(value: number, precision?: number): number;
39
+
16
40
  /**
17
41
  * This file is part of helpers4.
18
42
  * Copyright (C) 2025 baxyz
@@ -193,5 +217,5 @@ declare function roundTo(value: number, decimals: number): number;
193
217
  */
194
218
  declare function sum(array: readonly number[]): number;
195
219
 
196
- export { clamp, formatCompact, formatSize, inRange, lerp, mean, randomBetween, randomIntBetween, roundTo, sum };
220
+ export { clamp, correctFloat, formatCompact, formatSize, inRange, lerp, mean, randomBetween, randomIntBetween, roundTo, sum };
197
221
  export type { InRangeOptions };
package/lib/index.js CHANGED
@@ -16,6 +16,36 @@ function clamp(value, min, max) {
16
16
  return Math.min(Math.max(value, min), max);
17
17
  }
18
18
  //#endregion
19
+ //#region helpers/number/correctFloat.ts
20
+ /**
21
+ * This file is part of helpers4.
22
+ * Copyright (C) 2025 baxyz
23
+ * SPDX-License-Identifier: LGPL-3.0-or-later
24
+ */
25
+ /**
26
+ * Corrects floating-point arithmetic errors by rounding to a given number
27
+ * of significant digits. Useful after calculations that accumulate binary
28
+ * floating-point drift (e.g. `0.1 + 0.2 === 0.30000000000000004`).
29
+ *
30
+ * The default precision of 14 significant digits eliminates typical
31
+ * rounding noise for values in the range used by most applications.
32
+ * Note: for values whose integer part already consumes 14 or more digits
33
+ * (i.e. |value| ≥ 1e13), toPrecision(14) has no room left for decimal
34
+ * digits and will silently truncate them. Increase `precision` if you
35
+ * need to correct drift in very large numbers.
36
+ *
37
+ * @param value - The floating-point value to correct
38
+ * @param precision - Integer number of significant digits (default: 14)
39
+ * @returns The corrected value
40
+ * @since 2.0.2
41
+ */
42
+ function correctFloat(value, precision = 14) {
43
+ if (!Number.isFinite(value)) throw new RangeError(`correctFloat: value must be a finite number, got ${value}`);
44
+ if (!Number.isInteger(precision) || precision < 1 || precision > 100) throw new RangeError(`correctFloat: precision must be an integer between 1 and 100, got ${precision}`);
45
+ const result = parseFloat(value.toPrecision(precision));
46
+ return Object.is(value, -0) && result === 0 ? -0 : result;
47
+ }
48
+ //#endregion
19
49
  //#region helpers/number/formatCompact.ts
20
50
  /**
21
51
  * This file is part of helpers4.
@@ -224,6 +254,6 @@ function sum(array) {
224
254
  return array.reduce((acc, n) => acc + n, 0);
225
255
  }
226
256
  //#endregion
227
- export { clamp, formatCompact, formatSize, inRange, lerp, mean, randomBetween, randomIntBetween, roundTo, sum };
257
+ export { clamp, correctFloat, formatCompact, formatSize, inRange, lerp, mean, randomBetween, randomIntBetween, roundTo, sum };
228
258
 
229
259
  //# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../helpers/number/clamp.ts","../../../helpers/number/formatCompact.ts","../../../helpers/number/formatSize.ts","../../../helpers/number/inRange.ts","../../../helpers/number/lerp.ts","../../../helpers/number/mean.ts","../../../helpers/number/random.ts","../../../helpers/number/roundTo.ts","../../../helpers/number/sum.ts"],"sourcesContent":["/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Clamps a number between min and max values\n * @param value - The value to clamp\n * @param min - Minimum value\n * @param max - Maximum value\n * @returns Clamped value\n * @since 1.9.0\n */\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Formats a number using compact notation (e.g. `1_500_000 → \"1.5M\"`).\n *\n * Thin wrapper over `Intl.NumberFormat` with `notation: 'compact'`. Companion\n * of `formatSize` in the same `format*` family.\n *\n * @param value - The number to format.\n * @param locale - BCP 47 locale tag. Defaults to the runtime locale.\n * @returns A compact string representation of the number.\n * @example\n * formatCompact(1_500_000); // '1.5M' (en-US locale)\n * formatCompact(1_000); // '1K'\n * formatCompact(999); // '999'\n * formatCompact(1_500_000, 'fr'); // '1,5 M'\n * @since 2.0.0\n */\nexport function formatCompact(value: number, locale?: string): string {\n return new Intl.NumberFormat(locale, { notation: 'compact' }).format(value);\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/** Size units in ascending order. */\nconst UNITS = ['B', 'KB', 'MB', 'GB', 'TB'] as const;\n\n/**\n * Format a byte count into a human-readable string with the appropriate unit.\n *\n * Each unit is 1024 of the previous (binary prefix). The result is formatted\n * with one decimal place.\n *\n * @param bytes - A non-negative integer representing a byte count.\n * @returns A human-readable string such as `'0.0B'`, `'1.5KB'`, `'3.2MB'`.\n * @example\n * formatSize(0) // '0.0B'\n * formatSize(512) // '512.0B'\n * formatSize(1024) // '1.0KB'\n * formatSize(1536) // '1.5KB'\n * formatSize(1_048_576) // '1.0MB'\n * formatSize(1_073_741_824) // '1.0GB'\n * @since 2.0.0\n */\nexport function formatSize(bytes: number): string {\n let size = bytes;\n let unitIndex = 0;\n\n while (size >= 1024 && unitIndex < UNITS.length - 1) {\n size /= 1024;\n unitIndex++;\n }\n\n return `${size.toFixed(1)}${UNITS[unitIndex]}`;\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Options for {@link inRange}.\n */\nexport interface InRangeOptions {\n /**\n * Which boundary (or boundaries) are included in the range.\n * - `'both'` (default): `min <= value <= max`\n * - `'min'`: `min <= value < max`\n * - `'max'`: `min < value <= max`\n * - `'none'`: `min < value < max`\n */\n inclusive?: 'both' | 'min' | 'max' | 'none';\n}\n\n/**\n * Checks whether a number falls within `[min, max]` (both inclusive by default).\n *\n * @param value - The number to test\n * @param min - Lower bound\n * @param max - Upper bound\n * @param options - Boundary inclusion mode (default: `'both'`)\n * @returns `true` if `value` is within the specified range\n * @example\n * inRange(5, 1, 10) // => true\n * inRange(1, 1, 10) // => true (min inclusive)\n * inRange(1, 1, 10, { inclusive: 'none' }) // => false\n * inRange(10, 1, 10, { inclusive: 'max' }) // => true\n * @since 2.0.0\n */\nexport function inRange(value: number, min: number, max: number, options: InRangeOptions = {}): boolean {\n const { inclusive = 'both' } = options;\n const minOk = inclusive === 'both' || inclusive === 'min' ? value >= min : value > min;\n const maxOk = inclusive === 'both' || inclusive === 'max' ? value <= max : value < max;\n return minOk && maxOk;\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Linearly interpolates between `start` and `end` by the factor `t`.\n *\n * - `t = 0` returns `start`.\n * - `t = 1` returns `end`.\n * - Values of `t` outside `[0, 1]` extrapolate beyond the range.\n *\n * @param start - The start value.\n * @param end - The end value.\n * @param t - The interpolation factor.\n * @returns The interpolated value.\n * @example\n * lerp(0, 100, 0); // 0\n * lerp(0, 100, 1); // 100\n * lerp(0, 100, 0.5); // 50\n * lerp(0, 100, 0.25); // 25\n * @since 2.0.0\n */\nexport function lerp(start: number, end: number, t: number): number {\n if (t === 0) return start;\n if (t === 1) return end;\n if (Object.is(start, end)) return start;\n return start + (end - start) * t;\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Calculates the arithmetic mean (average) of an array of numbers.\n * Returns `NaN` for an empty array.\n *\n * Pairs with {@link sum} for aggregate operations.\n *\n * @param array - The array of numbers to average\n * @returns The arithmetic mean, or `NaN` if the array is empty\n * @example\n * mean([1, 2, 3, 4]) // => 2.5\n * mean([10]) // => 10\n * mean([]) // => NaN\n * @since 2.0.0\n */\nexport function mean(array: readonly number[]): number {\n if (array.length === 0) return NaN;\n return array.reduce((acc, n) => acc + n, 0) / array.length;\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Generates a random number between min and max (inclusive)\n * @param min - Minimum value\n * @param max - Maximum value\n * @returns Random number between min and max\n * @since 1.9.0\n */\nexport function randomBetween(min: number, max: number): number {\n return Math.random() * (max - min) + min;\n}\n\n/**\n * Generates a random integer between min and max (inclusive)\n * @param min - Minimum value\n * @param max - Maximum value\n * @returns Random integer between min and max\n * @since 1.9.0\n */\nexport function randomIntBetween(min: number, max: number): number {\n return Math.floor(Math.random() * (max - min + 1)) + min;\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Rounds a number to specified decimal places\n * @param value - The number to round\n * @param decimals - Number of decimal places\n * @returns Rounded number\n * @since 1.9.0\n */\nexport function roundTo(value: number, decimals: number): number {\n const multiplier = Math.pow(10, decimals);\n return Math.round(value * multiplier) / multiplier;\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Calculates the sum of an array of numbers.\n * @param array - The array of numbers to sum\n * @returns The sum of all values\n * @example\n * sum([1, 2, 3, 4])\n * // => 10\n * @since 2.0.0\n */\nexport function sum(array: readonly number[]): number {\n return array.reduce((acc, n) => acc + n, 0);\n}\n"],"mappings":";;;;;;;;;;;;;;AAcA,SAAgB,MAAM,OAAe,KAAa,KAAqB;CACrE,OAAO,KAAK,IAAI,KAAK,IAAI,OAAO,GAAG,GAAG,GAAG;AAC3C;;;;;;;;;;;;;;;;;;;;;;;;ACMA,SAAgB,cAAc,OAAe,QAAyB;CACpE,OAAO,IAAI,KAAK,aAAa,QAAQ,EAAE,UAAU,UAAU,CAAC,EAAE,OAAO,KAAK;AAC5E;;;;;;;;;ACjBA,IAAM,QAAQ;CAAC;CAAK;CAAM;CAAM;CAAM;AAAI;;;;;;;;;;;;;;;;;;AAmB1C,SAAgB,WAAW,OAAuB;CAChD,IAAI,OAAO;CACX,IAAI,YAAY;CAEhB,OAAO,QAAQ,QAAQ,YAAY,MAAM,SAAS,GAAG;EACnD,QAAQ;EACR;CACF;CAEA,OAAO,GAAG,KAAK,QAAQ,CAAC,IAAI,MAAM;AACpC;;;;;;;;;;;;;;;;;;ACDA,SAAgB,QAAQ,OAAe,KAAa,KAAa,UAA0B,CAAC,GAAY;CACtG,MAAM,EAAE,YAAY,WAAW;CAG/B,QAFc,cAAc,UAAU,cAAc,QAAQ,SAAS,MAAM,QAAQ,SACrE,cAAc,UAAU,cAAc,QAAQ,SAAS,MAAM,QAAQ;AAErF;;;;;;;;;;;;;;;;;;;;;;;;;;AChBA,SAAgB,KAAK,OAAe,KAAa,GAAmB;CAClE,IAAI,MAAM,GAAG,OAAO;CACpB,IAAI,MAAM,GAAG,OAAO;CACpB,IAAI,OAAO,GAAG,OAAO,GAAG,GAAG,OAAO;CAClC,OAAO,SAAS,MAAM,SAAS;AACjC;;;;;;;;;;;;;;;;;;;;;;ACTA,SAAgB,KAAK,OAAkC;CACrD,IAAI,MAAM,WAAW,GAAG,OAAO;CAC/B,OAAO,MAAM,QAAQ,KAAK,MAAM,MAAM,GAAG,CAAC,IAAI,MAAM;AACtD;;;;;;;;;;;;;;;ACVA,SAAgB,cAAc,KAAa,KAAqB;CAC9D,OAAO,KAAK,OAAO,KAAK,MAAM,OAAO;AACvC;;;;;;;;AASA,SAAgB,iBAAiB,KAAa,KAAqB;CACjE,OAAO,KAAK,MAAM,KAAK,OAAO,KAAK,MAAM,MAAM,EAAE,IAAI;AACvD;;;;;;;;;;;;;;;ACbA,SAAgB,QAAQ,OAAe,UAA0B;CAC/D,MAAM,aAAa,KAAK,IAAI,IAAI,QAAQ;CACxC,OAAO,KAAK,MAAM,QAAQ,UAAU,IAAI;AAC1C;;;;;;;;;;;;;;;;;ACDA,SAAgB,IAAI,OAAkC;CACpD,OAAO,MAAM,QAAQ,KAAK,MAAM,MAAM,GAAG,CAAC;AAC5C"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../helpers/number/clamp.ts","../../../helpers/number/correctFloat.ts","../../../helpers/number/formatCompact.ts","../../../helpers/number/formatSize.ts","../../../helpers/number/inRange.ts","../../../helpers/number/lerp.ts","../../../helpers/number/mean.ts","../../../helpers/number/random.ts","../../../helpers/number/roundTo.ts","../../../helpers/number/sum.ts"],"sourcesContent":["/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Clamps a number between min and max values\n * @param value - The value to clamp\n * @param min - Minimum value\n * @param max - Maximum value\n * @returns Clamped value\n * @since 1.9.0\n */\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Corrects floating-point arithmetic errors by rounding to a given number\n * of significant digits. Useful after calculations that accumulate binary\n * floating-point drift (e.g. `0.1 + 0.2 === 0.30000000000000004`).\n *\n * The default precision of 14 significant digits eliminates typical\n * rounding noise for values in the range used by most applications.\n * Note: for values whose integer part already consumes 14 or more digits\n * (i.e. |value| ≥ 1e13), toPrecision(14) has no room left for decimal\n * digits and will silently truncate them. Increase `precision` if you\n * need to correct drift in very large numbers.\n *\n * @param value - The floating-point value to correct\n * @param precision - Integer number of significant digits (default: 14)\n * @returns The corrected value\n * @since 2.0.2\n */\nexport function correctFloat(value: number, precision: number = 14): number {\n if (!Number.isFinite(value)) {\n throw new RangeError(`correctFloat: value must be a finite number, got ${value}`);\n }\n if (!Number.isInteger(precision) || precision < 1 || precision > 100) {\n throw new RangeError(`correctFloat: precision must be an integer between 1 and 100, got ${precision}`);\n }\n const result = parseFloat(value.toPrecision(precision));\n // toPrecision(-0) produces \"0.000…\" (no minus sign per spec) — restore the sign bit.\n return Object.is(value, -0) && result === 0 ? -0 : result;\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Formats a number using compact notation (e.g. `1_500_000 → \"1.5M\"`).\n *\n * Thin wrapper over `Intl.NumberFormat` with `notation: 'compact'`. Companion\n * of `formatSize` in the same `format*` family.\n *\n * @param value - The number to format.\n * @param locale - BCP 47 locale tag. Defaults to the runtime locale.\n * @returns A compact string representation of the number.\n * @example\n * formatCompact(1_500_000); // '1.5M' (en-US locale)\n * formatCompact(1_000); // '1K'\n * formatCompact(999); // '999'\n * formatCompact(1_500_000, 'fr'); // '1,5 M'\n * @since 2.0.0\n */\nexport function formatCompact(value: number, locale?: string): string {\n return new Intl.NumberFormat(locale, { notation: 'compact' }).format(value);\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/** Size units in ascending order. */\nconst UNITS = ['B', 'KB', 'MB', 'GB', 'TB'] as const;\n\n/**\n * Format a byte count into a human-readable string with the appropriate unit.\n *\n * Each unit is 1024 of the previous (binary prefix). The result is formatted\n * with one decimal place.\n *\n * @param bytes - A non-negative integer representing a byte count.\n * @returns A human-readable string such as `'0.0B'`, `'1.5KB'`, `'3.2MB'`.\n * @example\n * formatSize(0) // '0.0B'\n * formatSize(512) // '512.0B'\n * formatSize(1024) // '1.0KB'\n * formatSize(1536) // '1.5KB'\n * formatSize(1_048_576) // '1.0MB'\n * formatSize(1_073_741_824) // '1.0GB'\n * @since 2.0.0\n */\nexport function formatSize(bytes: number): string {\n let size = bytes;\n let unitIndex = 0;\n\n while (size >= 1024 && unitIndex < UNITS.length - 1) {\n size /= 1024;\n unitIndex++;\n }\n\n return `${size.toFixed(1)}${UNITS[unitIndex]}`;\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Options for {@link inRange}.\n */\nexport interface InRangeOptions {\n /**\n * Which boundary (or boundaries) are included in the range.\n * - `'both'` (default): `min <= value <= max`\n * - `'min'`: `min <= value < max`\n * - `'max'`: `min < value <= max`\n * - `'none'`: `min < value < max`\n */\n inclusive?: 'both' | 'min' | 'max' | 'none';\n}\n\n/**\n * Checks whether a number falls within `[min, max]` (both inclusive by default).\n *\n * @param value - The number to test\n * @param min - Lower bound\n * @param max - Upper bound\n * @param options - Boundary inclusion mode (default: `'both'`)\n * @returns `true` if `value` is within the specified range\n * @example\n * inRange(5, 1, 10) // => true\n * inRange(1, 1, 10) // => true (min inclusive)\n * inRange(1, 1, 10, { inclusive: 'none' }) // => false\n * inRange(10, 1, 10, { inclusive: 'max' }) // => true\n * @since 2.0.0\n */\nexport function inRange(value: number, min: number, max: number, options: InRangeOptions = {}): boolean {\n const { inclusive = 'both' } = options;\n const minOk = inclusive === 'both' || inclusive === 'min' ? value >= min : value > min;\n const maxOk = inclusive === 'both' || inclusive === 'max' ? value <= max : value < max;\n return minOk && maxOk;\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Linearly interpolates between `start` and `end` by the factor `t`.\n *\n * - `t = 0` returns `start`.\n * - `t = 1` returns `end`.\n * - Values of `t` outside `[0, 1]` extrapolate beyond the range.\n *\n * @param start - The start value.\n * @param end - The end value.\n * @param t - The interpolation factor.\n * @returns The interpolated value.\n * @example\n * lerp(0, 100, 0); // 0\n * lerp(0, 100, 1); // 100\n * lerp(0, 100, 0.5); // 50\n * lerp(0, 100, 0.25); // 25\n * @since 2.0.0\n */\nexport function lerp(start: number, end: number, t: number): number {\n if (t === 0) return start;\n if (t === 1) return end;\n if (Object.is(start, end)) return start;\n return start + (end - start) * t;\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Calculates the arithmetic mean (average) of an array of numbers.\n * Returns `NaN` for an empty array.\n *\n * Pairs with {@link sum} for aggregate operations.\n *\n * @param array - The array of numbers to average\n * @returns The arithmetic mean, or `NaN` if the array is empty\n * @example\n * mean([1, 2, 3, 4]) // => 2.5\n * mean([10]) // => 10\n * mean([]) // => NaN\n * @since 2.0.0\n */\nexport function mean(array: readonly number[]): number {\n if (array.length === 0) return NaN;\n return array.reduce((acc, n) => acc + n, 0) / array.length;\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Generates a random number between min and max (inclusive)\n * @param min - Minimum value\n * @param max - Maximum value\n * @returns Random number between min and max\n * @since 1.9.0\n */\nexport function randomBetween(min: number, max: number): number {\n return Math.random() * (max - min) + min;\n}\n\n/**\n * Generates a random integer between min and max (inclusive)\n * @param min - Minimum value\n * @param max - Maximum value\n * @returns Random integer between min and max\n * @since 1.9.0\n */\nexport function randomIntBetween(min: number, max: number): number {\n return Math.floor(Math.random() * (max - min + 1)) + min;\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Rounds a number to specified decimal places\n * @param value - The number to round\n * @param decimals - Number of decimal places\n * @returns Rounded number\n * @since 1.9.0\n */\nexport function roundTo(value: number, decimals: number): number {\n const multiplier = Math.pow(10, decimals);\n return Math.round(value * multiplier) / multiplier;\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Calculates the sum of an array of numbers.\n * @param array - The array of numbers to sum\n * @returns The sum of all values\n * @example\n * sum([1, 2, 3, 4])\n * // => 10\n * @since 2.0.0\n */\nexport function sum(array: readonly number[]): number {\n return array.reduce((acc, n) => acc + n, 0);\n}\n"],"mappings":";;;;;;;;;;;;;;AAcA,SAAgB,MAAM,OAAe,KAAa,KAAqB;CACrE,OAAO,KAAK,IAAI,KAAK,IAAI,OAAO,GAAG,GAAG,GAAG;AAC3C;;;;;;;;;;;;;;;;;;;;;;;;;ACOA,SAAgB,aAAa,OAAe,YAAoB,IAAY;CAC1E,IAAI,CAAC,OAAO,SAAS,KAAK,GACxB,MAAM,IAAI,WAAW,oDAAoD,OAAO;CAElF,IAAI,CAAC,OAAO,UAAU,SAAS,KAAK,YAAY,KAAK,YAAY,KAC/D,MAAM,IAAI,WAAW,qEAAqE,WAAW;CAEvG,MAAM,SAAS,WAAW,MAAM,YAAY,SAAS,CAAC;CAEtD,OAAO,OAAO,GAAG,OAAO,EAAE,KAAK,WAAW,IAAI,KAAK;AACrD;;;;;;;;;;;;;;;;;;;;;;;;ACXA,SAAgB,cAAc,OAAe,QAAyB;CACpE,OAAO,IAAI,KAAK,aAAa,QAAQ,EAAE,UAAU,UAAU,CAAC,EAAE,OAAO,KAAK;AAC5E;;;;;;;;;ACjBA,IAAM,QAAQ;CAAC;CAAK;CAAM;CAAM;CAAM;AAAI;;;;;;;;;;;;;;;;;;AAmB1C,SAAgB,WAAW,OAAuB;CAChD,IAAI,OAAO;CACX,IAAI,YAAY;CAEhB,OAAO,QAAQ,QAAQ,YAAY,MAAM,SAAS,GAAG;EACnD,QAAQ;EACR;CACF;CAEA,OAAO,GAAG,KAAK,QAAQ,CAAC,IAAI,MAAM;AACpC;;;;;;;;;;;;;;;;;;ACDA,SAAgB,QAAQ,OAAe,KAAa,KAAa,UAA0B,CAAC,GAAY;CACtG,MAAM,EAAE,YAAY,WAAW;CAG/B,QAFc,cAAc,UAAU,cAAc,QAAQ,SAAS,MAAM,QAAQ,SACrE,cAAc,UAAU,cAAc,QAAQ,SAAS,MAAM,QAAQ;AAErF;;;;;;;;;;;;;;;;;;;;;;;;;;AChBA,SAAgB,KAAK,OAAe,KAAa,GAAmB;CAClE,IAAI,MAAM,GAAG,OAAO;CACpB,IAAI,MAAM,GAAG,OAAO;CACpB,IAAI,OAAO,GAAG,OAAO,GAAG,GAAG,OAAO;CAClC,OAAO,SAAS,MAAM,SAAS;AACjC;;;;;;;;;;;;;;;;;;;;;;ACTA,SAAgB,KAAK,OAAkC;CACrD,IAAI,MAAM,WAAW,GAAG,OAAO;CAC/B,OAAO,MAAM,QAAQ,KAAK,MAAM,MAAM,GAAG,CAAC,IAAI,MAAM;AACtD;;;;;;;;;;;;;;;ACVA,SAAgB,cAAc,KAAa,KAAqB;CAC9D,OAAO,KAAK,OAAO,KAAK,MAAM,OAAO;AACvC;;;;;;;;AASA,SAAgB,iBAAiB,KAAa,KAAqB;CACjE,OAAO,KAAK,MAAM,KAAK,OAAO,KAAK,MAAM,MAAM,EAAE,IAAI;AACvD;;;;;;;;;;;;;;;ACbA,SAAgB,QAAQ,OAAe,UAA0B;CAC/D,MAAM,aAAa,KAAK,IAAI,IAAI,QAAQ;CACxC,OAAO,KAAK,MAAM,QAAQ,UAAU,IAAI;AAC1C;;;;;;;;;;;;;;;;;ACDA,SAAgB,IAAI,OAAkC;CACpD,OAAO,MAAM,QAAQ,KAAK,MAAM,MAAM,GAAG,CAAC;AAC5C"}
package/llms.txt CHANGED
@@ -1,7 +1,7 @@
1
1
  # @helpers4/number
2
2
 
3
3
  > Tree-shakable TypeScript utility functions for the `number` domain.
4
- > Package: `@helpers4/number` — Version: 2.0.0
4
+ > Package: `@helpers4/number` — Version: 2.0.2
5
5
  > License: LGPL-3.0-or-later
6
6
 
7
7
  ## Installation
@@ -15,7 +15,7 @@ pnpm add @helpers4/number
15
15
  ## Usage
16
16
 
17
17
  ```typescript
18
- import { clamp, formatCompact, formatSize, ... } from '@helpers4/number';
18
+ import { clamp, correctFloat, formatCompact, ... } from '@helpers4/number';
19
19
  ```
20
20
 
21
21
  ## Functions
@@ -23,6 +23,7 @@ import { clamp, formatCompact, formatSize, ... } from '@helpers4/number';
23
23
  | Function | Description |
24
24
  |---|---|
25
25
  | `clamp` | Clamps a number between min and max values |
26
+ | `correctFloat` | Corrects floating-point arithmetic errors by rounding to a given number of significant digits. Usefu |
26
27
  | `formatCompact` | Formats a number using compact notation (e.g. `1_500_000 → "1.5M"`). Thin wrapper over `Intl.Number |
27
28
  | `formatSize` | Format a byte count into a human-readable string with the appropriate unit. Each unit is 1024 of th |
28
29
  | `inRange` | Checks whether a number falls within `[min, max]` (both inclusive by default). |
@@ -69,6 +70,54 @@ clamp(5, 0, 10) // => 5
69
70
 
70
71
  ---
71
72
 
73
+ ### `correctFloat`
74
+
75
+ Corrects floating-point arithmetic errors by rounding to a given number
76
+ of significant digits. Useful after calculations that accumulate binary
77
+ floating-point drift (e.g. `0.1 + 0.2 === 0.30000000000000004`).
78
+
79
+ The default precision of 14 significant digits eliminates typical
80
+ rounding noise for values in the range used by most applications.
81
+ Note: for values whose integer part already consumes 14 or more digits
82
+ (i.e. |value| ≥ 1e13), toPrecision(14) has no room left for decimal
83
+ digits and will silently truncate them. Increase `precision` if you
84
+ need to correct drift in very large numbers.
85
+
86
+ ```typescript
87
+ import { correctFloat } from '@helpers4/number';
88
+
89
+ correctFloat(value: number, precision: number): number
90
+ ```
91
+
92
+ **Parameters:**
93
+
94
+ - `value: number` — The floating-point value to correct
95
+ - `precision: number` (default: `14`) — Integer number of significant digits (default: 14)
96
+
97
+ **Returns:** `number` — The corrected value
98
+
99
+ **Examples:**
100
+
101
+ *Fix floating-point drift*
102
+
103
+ Corrects the classic 0.1 + 0.2 floating-point arithmetic error.
104
+
105
+ ```typescript
106
+ 0.1 + 0.2 // => 0.30000000000000004
107
+ correctFloat(0.1 + 0.2) // => 0.3
108
+ ```
109
+
110
+ *Custom significant-digit precision*
111
+
112
+ Pass a second argument to control how many significant digits to keep.
113
+
114
+ ```typescript
115
+ correctFloat(1.23456789, 4) // => 1.235
116
+ correctFloat(1.23456789, 6) // => 1.23457
117
+ ```
118
+
119
+ ---
120
+
72
121
  ### `formatCompact`
73
122
 
74
123
  Formats a number using compact notation (e.g. `1_500_000 → "1.5M"`).
package/meta/api.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "category": "number",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "functions": [
5
5
  {
6
6
  "name": "clamp",
@@ -43,6 +43,48 @@
43
43
  ],
44
44
  "sourceFile": "clamp.ts"
45
45
  },
46
+ {
47
+ "name": "correctFloat",
48
+ "kind": "function",
49
+ "description": "Corrects floating-point arithmetic errors by rounding to a given number\nof significant digits. Useful after calculations that accumulate binary\nfloating-point drift (e.g. `0.1 + 0.2 === 0.30000000000000004`).\n\nThe default precision of 14 significant digits eliminates typical\nrounding noise for values in the range used by most applications.\nNote: for values whose integer part already consumes 14 or more digits\n(i.e. |value| ≥ 1e13), toPrecision(14) has no room left for decimal\ndigits and will silently truncate them. Increase `precision` if you\nneed to correct drift in very large numbers.",
50
+ "since": "2.0.2",
51
+ "signatures": [
52
+ {
53
+ "signature": "correctFloat(value: number, precision: number): number",
54
+ "description": "Corrects floating-point arithmetic errors by rounding to a given number\nof significant digits. Useful after calculations that accumulate binary\nfloating-point drift (e.g. `0.1 + 0.2 === 0.30000000000000004`).\n\nThe default precision of 14 significant digits eliminates typical\nrounding noise for values in the range used by most applications.\nNote: for values whose integer part already consumes 14 or more digits\n(i.e. |value| ≥ 1e13), toPrecision(14) has no room left for decimal\ndigits and will silently truncate them. Increase `precision` if you\nneed to correct drift in very large numbers.",
55
+ "params": [
56
+ {
57
+ "name": "value",
58
+ "type": "number",
59
+ "description": "The floating-point value to correct"
60
+ },
61
+ {
62
+ "name": "precision",
63
+ "type": "number",
64
+ "description": "Integer number of significant digits (default: 14)",
65
+ "defaultValue": "14"
66
+ }
67
+ ],
68
+ "returns": {
69
+ "type": "number",
70
+ "description": "The corrected value"
71
+ }
72
+ }
73
+ ],
74
+ "examples": [
75
+ {
76
+ "title": "Fix floating-point drift",
77
+ "description": "Corrects the classic 0.1 + 0.2 floating-point arithmetic error.",
78
+ "code": "0.1 + 0.2 // => 0.30000000000000004\ncorrectFloat(0.1 + 0.2) // => 0.3"
79
+ },
80
+ {
81
+ "title": "Custom significant-digit precision",
82
+ "description": "Pass a second argument to control how many significant digits to keep.",
83
+ "code": "correctFloat(1.23456789, 4) // => 1.235\ncorrectFloat(1.23456789, 6) // => 1.23457"
84
+ }
85
+ ],
86
+ "sourceFile": "correctFloat.ts"
87
+ },
46
88
  {
47
89
  "name": "formatCompact",
48
90
  "kind": "function",
@@ -11,6 +11,21 @@
11
11
  }
12
12
  ]
13
13
  },
14
+ {
15
+ "name": "correctFloat",
16
+ "examples": [
17
+ {
18
+ "title": "Fix floating-point drift",
19
+ "description": "Corrects the classic 0.1 + 0.2 floating-point arithmetic error.",
20
+ "code": "0.1 + 0.2 // => 0.30000000000000004\ncorrectFloat(0.1 + 0.2) // => 0.3"
21
+ },
22
+ {
23
+ "title": "Custom significant-digit precision",
24
+ "description": "Pass a second argument to control how many significant digits to keep.",
25
+ "code": "correctFloat(1.23456789, 4) // => 1.235\ncorrectFloat(1.23456789, 6) // => 1.23457"
26
+ }
27
+ ]
28
+ },
14
29
  {
15
30
  "name": "formatCompact",
16
31
  "examples": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@helpers4/number",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "A set of helpers in TS/JS, compatible with tree-shaking, for number.",
5
5
  "author": "baxyz <baxy@etik.com>",
6
6
  "license": "LGPL-3.0",
@@ -28,6 +28,7 @@
28
28
  "helpers",
29
29
  "number",
30
30
  "clamp",
31
+ "correctFloat",
31
32
  "formatCompact",
32
33
  "formatSize",
33
34
  "inRange",