@neutrium/decimal API - v2.2.0
    Preparing search index...

    @neutrium/decimal API - v2.2.0

    @neutrium/decimal

    Arbitrary-precision decimal arithmetic for JavaScript and TypeScript.

    @neutrium/decimal provides configurable precision and rounding, scientific functions, comparisons, and formatting without the floating-point surprises of JavaScript numbers.

    Try the interactive demo to explore the functionality and compare Decimal calculations with native JavaScript.

    pnpm install @neutrium/decimal
    

    The package has no runtime dependencies and includes JavaScript source maps, TypeScript declarations, and declaration maps.

    Applications upgrading from 1.x should follow the 2.0 migration guide.

    import { Decimal } from '@neutrium/decimal';

    // Decimal
    const result = new Decimal('0.1').add('0.2');

    result.toString(); // '0.3'

    // Native JavaScript
    const nativeResult = 0.1 + 0.2;
    console.log(nativeResult); // 0.30000000000000004

    Pass decimal values as strings when their exact value cannot be represented by a JavaScript number, particularly for long values and decimal fractions.

    Import from @neutrium/decimal by default to use the full API. If bundle size is a priority, choose the smallest entry point that contains the operations your application needs:

    Entry point Includes Minified size Budget
    @neutrium/decimal/core Representation, parsing, comparison, predicates, and string/number formatting 15.03 KiB 20 KiB
    @neutrium/decimal/arithmetic Core plus arithmetic, rounding, shifting, and fractions 26.30 KiB 32 KiB
    @neutrium/decimal/scientific Arithmetic plus powers, logarithms, trigonometry, PI, and atan2 (the complete API) 42.25 KiB 50 KiB
    @neutrium/decimal Alias for the scientific tier; retained for compatibility 42.24 KiB 50 KiB

    Sizes are measured from the browser smoke fixtures (minified ES2022 IIFE, uncompressed, including fixture code) and refreshed by pnpm run build. Actual application sizes depend on usage and bundler settings. Budgets are enforced by pnpm run test:package.

    Each entry point exports a Decimal constructor and the shared configuration, error, input, rounding, modulo, and limits types. The core, arithmetic, and scientific constructors have independent configurations; the root and scientific entry points expose the same complete constructor.

    Internally, the implementations form the inheritance chain DecimalLike → CoreDecimal → ArithmeticDecimal → ScientificDecimal. The scientific entry point exports its implementation as both Decimal and ScientificDecimal, and the root entry point re-exports the scientific API. Both names refer to the same constructor and configuration.

    Values are interoperable across tiers, so a richer tier can consume a value directly without converting it to a string:

    import { Decimal as CoreDecimal } from '@neutrium/decimal/core';
    import { Decimal as ArithmeticDecimal } from '@neutrium/decimal/arithmetic';

    const parsed = new CoreDecimal('9007199254740993.0000000000000000001');
    const calculated = new ArithmeticDecimal(parsed).add(1);

    Create a decimal with new Decimal(value), where value is a string, number, bigint, or another Decimal.

    new Decimal(42).toString();                         // '42'
    new Decimal(9007199254740993n).toString(); // '9007199254740993'
    new Decimal('503248.334').toString(); // '503248.334'
    new Decimal('4.321e+4').toString(); // '43210'
    new Decimal('.5').toString(); // '0.5'
    new Decimal(Infinity).toString(); // 'Infinity'
    new Decimal(NaN).toString(); // 'NaN'

    The number of digits in value is not limited, except by JavaScript's maximum array size and, in practice, the processing time required.

    Decimal strings may use fixed-point or exponential notation. Numeric separators are accepted between digits, and prefixed binary, octal, and hexadecimal strings are also supported.

    In exponential notation, e or E defines a power-of-ten exponent for decimal values, while p or P defines a power-of-two exponent for binary, octal, or hexadecimal values.

    new Decimal('0.046_875').toString();                // '0.046875'
    new Decimal('0b101.1').toString(); // '5.5'
    new Decimal('0o10').toString(); // '8'
    new Decimal('0xff.8').toString(); // '255.5'
    new Decimal('0x1.8p-5').toString(); // '0.046875'
    new Decimal('0b1p2_0').toString(); // '1048576'

    Invalid values, including objects other than Decimal and malformed numeric strings, throw a DecimalError.

    A Decimal with an isolated configuration can be created using Decimal.clone(). A clone starts with the calling constructor's current settings and then applies the supplied overrides.

    const Money = Decimal.clone({
    precision: 20,
    rounding: 'half-even'
    });

    const Measurements = Decimal.clone({ precision: 50 });

    Money.config = { precision: 12 };

    Money.config.precision; // 12
    Measurements.config.precision; // 50
    Decimal.config.precision; // 20 (unchanged default)

    Decimal-returning operations, Decimal.PI, Decimal.atan2(), and toFraction() preserve constructors produced by Decimal.clone().

    Configure Decimal behaviour through the following properties.

    Property Description Type Valid values Default
    precision The maximum number of significant digits in the result of an operation integer 1 to 1e9 20
    maxPrefixedDigits Limits the number of decimal coefficient digits created while converting binary, octal, or hexadecimal strings integer 1 to 1e9 1e6
    maxOutputDigits Limits the mantissa digits produced by string-formatting operations. It includes leading and padded zeros, but excludes the sign, decimal point, and scientific exponent suffix integer 1 to 1e9 1e6
    rounding The default rounding mode used when rounding an operation's result to the configured number of significant digits RoundingMode See rounding modes 'half-up'
    modulo The modulo mode used when calculating the modulus ModuloMode See modulo modes 'down'
    toExpNeg The negative exponent value at and below which toString() returns exponential notation integer -9e15 to 0 -7
    toExpPos The positive exponent value at and above which toString() returns exponential notation integer 0 to 9e15 21
    minE The negative exponent limit, i.e. the exponent value below which underflow to zero occurs integer -9e15 to 0 -9e15
    maxE The positive exponent limit, i.e. the exponent value above which overflow to Infinity occurs integer 0 to 9e15 9e15

    Configuration is scoped to a Decimal constructor. Assign any subset of the properties to Decimal.config:

    Decimal.config = {
    precision: 40,
    rounding: 'half-even',
    modulo: 'euclid',
    toExpNeg: -9,
    toExpPos: 30,
    minE: -1e6,
    maxE: 1e6
    };

    Calculation results are rounded to the configured number of significant digits where the operation requires rounding. minE and maxE control underflow to zero and overflow to Infinity.

    A rounding mode may be specified using the constructor configuration and occasionally as a function parameter. Supported rounding modes are listed below:

    Value Behavior
    'up' Away from zero
    'down' Toward zero
    'ceil' Toward positive Infinity
    'floor' Toward negative Infinity
    'half-up' To nearest; ties away from zero
    'half-down' To nearest; ties toward zero
    'half-even' To nearest; ties toward the even neighbor
    'half-ceil' To nearest; ties toward positive Infinity
    'half-floor' To nearest; ties toward negative Infinity

    Methods that accept an optional rounding mode use the constructor's configured mode when it is omitted.

    The modulo mode determines how the quotient is rounded before calculating remainder = dividend - divisor * quotient. It accepts every RoundingMode plus 'euclid'. Common modulo modes are listed below:

    Value Remainder behavior
    'down' Same sign as the dividend; equivalent to JavaScript %
    'floor' Same sign as the divisor; equivalent to Python %
    'half-even' IEEE 754 remainder
    'euclid' Always non-negative

    Decimal instances provide the following categories of precision-preserving operations.

    The DecimalValue type used below is string | number | bigint | DecimalLike. Unless noted otherwise, methods return a new Decimal and do not change the receiver.

    Refer to the API reference for comprehensive library documentation, and specifically the Decimal class for details of the complete API.

    Member Description
    Decimal.config Get a readonly configuration snapshot or assign partial configuration.
    Decimal.clone(config?) Create an independently configured Decimal constructor.
    Decimal.atan2(y, x) Return the angle in radians from the positive x-axis to (x, y).
    Decimal.min(value, ...values) or Decimal.min(values) Return the minimum using the receiving constructor.
    Decimal.max(value, ...values) or Decimal.max(values) Return the maximum using the receiving constructor.
    Decimal.PI Pi as a Decimal from the receiving constructor.
    Decimal.limits Readonly public validation limits: maxDigits and maxExponent.
    Method Returns Description
    dp() number Number of decimal places, or NaN for a non-finite value.
    precision(includeTrailingZeros?) number Number of significant digits. Pass true to count trailing integer zeroes; only booleans are accepted.
    sign() number -1, -0, 0, 1, or NaN, preserving the sign of zero.
    Method Description
    add(value) Add value to the decimal value.
    sub(value) Subtract value from the decimal value.
    mul(value) Multiply the decimal by value.
    div(value) Divide the decimal by value.
    divToInt(value) Divide the decimal by value and truncate the quotient to an integer.
    mod(value) Return the remainder after dividing the decimal by value using the configured modulo mode.
    abs() Return the absolute value of the decimal.
    neg() Invert the sign of the decimal.
    shift(places) Shift the decimal point by a safe integer number of places.
    pow(value) Raise the decimal to the power of value.
    sqrt() Return the square root of the decimal.
    cbrt() Return the cube root of the decimal.

    All angles are expressed in radians.

    Method Description
    exp() Return e raised to the value of the decimal.
    ln() Return the natural logarithm of the decimal.
    log(base) Return the logarithm of the decimal in the supplied base.
    sin(), cos(), tan() Trigonometric functions.
    asin(), acos(), atan() Inverse trigonometric functions.
    sinh(), cosh(), tanh() Hyperbolic functions.
    asinh(), acosh(), atanh() Inverse hyperbolic functions.

    The internal constant for PI contains approximately 1,000 decimal places. That limits the maximum useful precision of trigonometric and logarithmic calculations.

    Method Returns Description
    Decimal.min(value, ...values) or Decimal.min(values) Decimal Minimum of scalar arguments or a finite, non-empty iterable.
    Decimal.max(value, ...values) or Decimal.max(values) Decimal Maximum of scalar arguments or a finite, non-empty iterable.
    cmp(value) number -1, 0, 1, or NaN.
    eq(value) boolean Equal to.
    gt(value) boolean Greater than.
    gte(value) boolean Greater than or equal to.
    lt(value) boolean Less than.
    lte(value) boolean Less than or equal to.

    Decimal.min() and Decimal.max() accept either one or more scalar DecimalValue arguments or one finite, non-empty iterable. Arrays, sets, and generators are streamed without being spread into an argument list. Strings remain scalar decimal values rather than being treated as iterables.

    Method Description
    isFinite() Whether the value is finite.
    isInt() Whether the value is an integer.
    isNaN() Whether the value is NaN.
    isNeg() Whether the value is negative, including negative zero.
    isPos() Whether the value is positive, including positive zero.
    isZero() Whether the value is positive or negative zero.
    isOdd() Whether the value is an odd integer.
    isEven() Whether the value is an even integer.
    Method Description
    ceil() Round toward positive Infinity.
    floor() Round toward negative Infinity.
    round() Round to an integer using the configured rounding mode.
    trunc() Truncate to an integer toward zero.
    toNearest(value?, rounding?) Round to the nearest multiple of the magnitude of value; its sign is ignored and the value defaults to 1.
    Method Returns Description
    toDP(dp?, rounding?) Decimal Round to at most dp decimal places. With no dp, return an equal new Decimal.
    toSD(sd?, rounding?) Decimal Round to at most sd significant digits. Defaults to configured precision.
    toExponential(dp?, rounding?) string Exponential notation with optional decimal-place count.
    toFixed(dp?, rounding?) string Fixed-point notation with optional decimal-place count; preserves negative zero.
    toPrecision(sd?, rounding?) string Precision notation with optional significant-digit count.
    toFraction(maxDenominator?) readonly [Decimal, Decimal] | readonly [Decimal] Numerator and denominator, or a one-item tuple for a non-finite value.
    toNumber() number Convert to a JavaScript number, preserving negative zero.
    toString() string Canonical string using the configured exponential thresholds.
    toValue() string Primitive string representation that preserves negative zero.
    valueOf() string Exact value used for default coercion; preserves negative zero.
    toJSON() string Exact JSON string value; preserves negative zero and non-finite values.

    String coercion uses toString(), so it follows the configured exponential thresholds and renders negative zero as '0'. Default coercion uses valueOf() and therefore preserves negative zero. Numeric coercion uses toNumber() and can lose precision or overflow like any conversion to a JavaScript number.

    const exact = new Decimal('9007199254740993');

    String(exact); // '9007199254740993'
    exact + ''; // '9007199254740993'
    Number(exact); // 9007199254740992 (precision is lost)
    JSON.stringify({ exact }); // '{"exact":"9007199254740993"}'
    JSON.stringify(new Decimal('-0')); // '"-0"'
    JSON.stringify(new Decimal(NaN)); // '"NaN"'

    JSON serialisation intentionally produces strings rather than JSON numbers so that finite values retain all digits and -0, NaN, and infinities retain their Decimal representation.

    The + operator uses default coercion and therefore concatenates Decimal values as strings. Other arithmetic operators and relational operators request numeric coercion and may lose precision. Use add, sub, mul, div, and the Decimal comparison methods for exact Decimal operations.

    All input validation and configured-limit failures throw DecimalError with a stable code property:

    Code Meaning
    INVALID_ARGUMENT A constructor or method argument is invalid.
    INVALID_CONFIGURATION A configuration value or the configuration object is invalid.
    UNKNOWN_CONFIGURATION_KEY A configuration property is not supported.
    PRECISION_LIMIT_EXCEEDED A calculation requires more digits than a built-in constant provides.
    PREFIXED_EXPANSION_LIMIT_EXCEEDED A prefixed number would exceed maxPrefixedDigits.
    OUTPUT_DIGIT_LIMIT_EXCEEDED String output would exceed maxOutputDigits.

    For example:

    import { Decimal, DecimalError } from '@neutrium/decimal';

    try
    {
    new Decimal('not-a-number');
    }
    catch (error)
    {
    if (error instanceof DecimalError)
    {
    console.error(error.code); // 'INVALID_ARGUMENT'
    }
    }

    The package exports these public types:

    import {
    Decimal,
    DecimalError,
    type DecimalConfig,
    type DecimalConfigInput,
    type DecimalConstructor,
    type DecimalErrorCode,
    type DecimalFraction,
    type DecimalLike,
    type DecimalLimits,
    type DecimalValue,
    type DecimalValueIterable,
    type ModuloMode,
    type RoundingMode
    } from '@neutrium/decimal';

    Decimal-returning methods return Decimal. Decimal.clone() returns an independently configured DecimalConstructor; values created by it preserve that constructor through subsequent Decimal-returning operations.

    const Money: DecimalConstructor = Decimal.clone({ precision: 24 });
    const amount: Decimal = new Money('10.00').mul(3).toDP(2);
    const angle: Decimal = Money.atan2(1, 1);
    • Added feature-tier entry points backed by a shared core → arithmetic → scientific inheritance chain.
    • Added iterable support to Decimal.min() and Decimal.max().
    • Added an interactive precision demo and automated demo publishing alongside the API documentation.
    • Improved multiplication performance for large coefficients and expanded package and architecture validation.
    • Expanded CI coverage to Node.js 24.
    • Moved API documentation generation into the GitHub Pages deployment workflow.
    • Fixed toFixed() so negative values rounded to zero retain their negative sign.
    • Corrected README formatting.
    • Refactored the public API and internal calculation architecture.
    • Added human-readable rounding and modulo modes, structured errors, immutable private state, and bigint input support.
    • Removed JavaScript floating-point dependence from trigonometric calculations and improved performance.
    • See the 2.0 migration guide for upgrade details.

    This project is licensed under the MIT License (see the LICENSE file for details).

    You are free to:

    • Use this library for personal or commercial purposes
    • Modify and distribute the code
    • Include it in other projects

    Under the following conditions:

    • You must include the original license and copyright notice

    This library is provided "as is", without warranty of any kind. Use at your own risk.