or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

async-programming.mdcharacter-operations.mdcollections.mdconfiguration.mdcore-infrastructure.mddata-encoding.mddate-time.mdexternal-integration.mdindex.mdnumeric-types.mdreactive-programming.mdstring-operations.mdtype-system.md
tile.json

external-integration.mddocs/

External Integration

Integration with external JavaScript libraries and type definitions, specifically focusing on the big.js library integration for high-precision decimal arithmetic support.

Big.js Library Integration

The Fable library integrates with the big.js library to provide high-precision decimal arithmetic capabilities that match .NET's decimal type behavior. This integration is defined in lib/big.d.ts.

Type Definitions Overview

The big.js integration provides TypeScript type definitions for arbitrary precision decimal arithmetic with configurable precision and rounding modes.

Core Types and Enums

BigSource Input Type

// Input type for Big constructor - accepts various numeric formats
type BigSource = number | string | Big;

// Usage examples of valid BigSource values
const examples: BigSource[] = [
    42,                    // number
    "123.456",            // string  
    "1.23e+5",            // scientific notation string
    new Big("789.012")    // existing Big instance
];

Comparison Result Enumeration

// Comparison result constants
enum Comparison {
    GT = 1,   // Greater than
    EQ = 0,   // Equal
    LT = -1   // Less than
}

// Usage in comparison operations
import { Comparison } from "fable-library/lib/big.d.ts";

const result: Comparison = big1.cmp(big2);
switch (result) {
    case Comparison.GT:
        console.log("big1 is greater than big2");
        break;
    case Comparison.EQ:
        console.log("big1 equals big2");
        break;
    case Comparison.LT:
        console.log("big1 is less than big2");
        break;
}

Rounding Mode Enumeration

// Rounding mode constants for precision control
enum RoundingMode {
    RoundDown = 0,      // Round towards zero (truncate)
    RoundHalfUp = 1,    // Round half away from zero
    RoundHalfEven = 2,  // Round half to even (banker's rounding)
    RoundUp = 3         // Round away from zero
}

// Usage in rounding operations
import { RoundingMode } from "fable-library/lib/big.d.ts";

// Configure global rounding mode
Big.RM = RoundingMode.RoundHalfEven;

// Or use in specific operations
const rounded = value.round(2, RoundingMode.RoundUp);

BigConstructor Interface

The Big.js constructor interface with static configuration and utility methods.

interface BigConstructor {
    // Constructor
    new (value: BigSource): Big;
    (value: BigSource): Big; // Callable without 'new'
    
    // Global configuration properties
    DP: number;         // Decimal places for division operations
    RM: RoundingMode;   // Default rounding mode
    NE: number;         // Negative exponent limit
    PE: number;         // Positive exponent limit
    strict: boolean;    // Strict mode for error handling
    
    // Static utility methods
    max(...values: BigSource[]): Big;
    min(...values: BigSource[]): Big;
    
    // Version information
    version: string;
}

// Usage examples
import { Big, RoundingMode } from "fable-library/lib/big.js";

// Configure Big.js globally
Big.DP = 20;                           // 20 decimal places for division
Big.RM = RoundingMode.RoundHalfEven;   // Banker's rounding
Big.strict = true;                     // Enable strict mode

// Create Big instances
const price1 = new Big("19.99");
const price2 = Big("25.50");          // Without 'new'

// Use static methods
const maxPrice = Big.max(price1, price2, "30.00");
const minPrice = Big.min(price1, price2, "15.75");

console.log(`Max price: ${maxPrice}`); // "30"
console.log(`Min price: ${minPrice}`); // "15.75"
console.log(`Big.js version: ${Big.version}`);

Big Instance Interface

The Big instance interface providing arithmetic operations and utility methods.

Arithmetic Operations

interface Big {
    // Basic arithmetic
    plus(n: BigSource): Big;      // Addition
    minus(n: BigSource): Big;     // Subtraction  
    times(n: BigSource): Big;     // Multiplication
    div(n: BigSource): Big;       // Division
    mod(n: BigSource): Big;       // Modulo
    pow(n: number): Big;          // Exponentiation
    
    // Unary operations
    abs(): Big;                   // Absolute value
    neg(): Big;                   // Negation
    sqrt(): Big;                  // Square root
}

// Usage examples
import { Big } from "fable-library/lib/big.js";

const a = new Big("123.456");
const b = new Big("78.9");

// Arithmetic operations
const sum = a.plus(b);           // "202.356"
const difference = a.minus(b);   // "44.556"
const product = a.times(b);      // "9740.6784"
const quotient = a.div(b);       // "1.5640354604096..."
const remainder = a.mod(b);      // "44.556"
const power = a.pow(2);          // "15241.383936"

// Unary operations
const absolute = a.abs();        // "123.456"
const negated = a.neg();         // "-123.456"
const squareRoot = a.sqrt();     // "11.11080555135405..."

console.log(`${a} + ${b} = ${sum}`);
console.log(`${a} - ${b} = ${difference}`);
console.log(`${a} × ${b} = ${product}`);

Comparison Operations

interface Big {
    // Comparison methods
    cmp(n: BigSource): Comparison;     // Compare (-1, 0, 1)
    eq(n: BigSource): boolean;         // Equal
    gt(n: BigSource): boolean;         // Greater than
    gte(n: BigSource): boolean;        // Greater than or equal
    lt(n: BigSource): boolean;         // Less than
    lte(n: BigSource): boolean;        // Less than or equal
}

// Usage examples
const value1 = new Big("100.50");
const value2 = new Big("75.25");
const value3 = new Big("100.50");

// Comparison operations
console.log(value1.cmp(value2));    // 1 (GT)
console.log(value1.cmp(value3));    // 0 (EQ)
console.log(value2.cmp(value1));    // -1 (LT)

console.log(value1.eq(value3));     // true
console.log(value1.gt(value2));     // true
console.log(value1.gte(value3));    // true
console.log(value2.lt(value1));     // true
console.log(value2.lte(value1));    // true

// Sorting with comparisons
const values = [
    new Big("50.25"),
    new Big("100.00"), 
    new Big("75.50")
];

values.sort((a, b) => a.cmp(b));
console.log("Sorted:", values.map(v => v.toString())); // ["50.25", "75.5", "100"]

Formatting and Conversion

interface Big {
    // Rounding operations
    round(dp?: number, rm?: RoundingMode): Big;
    
    // String conversion
    toString(): string;
    toFixed(dp?: number, rm?: RoundingMode): string;
    toExponential(dp?: number, rm?: RoundingMode): string;
    toPrecision(sd?: number, rm?: RoundingMode): string;
    
    // Number conversion (may lose precision)
    toNumber(): number;
    
    // JSON serialization
    toJSON(): string;
    valueOf(): string;
}

// Usage examples
const value = new Big("123.456789");

// Rounding
const rounded2 = value.round(2);                    // "123.46"
const rounded2Down = value.round(2, RoundingMode.RoundDown); // "123.45"

// String formatting
console.log(value.toString());                      // "123.456789"
console.log(value.toFixed(2));                     // "123.46"
console.log(value.toFixed(2, RoundingMode.RoundDown)); // "123.45"
console.log(value.toExponential(3));               // "1.235e+2"
console.log(value.toPrecision(5));                 // "123.46"

// Number conversion (loses precision for very large/small numbers)
console.log(value.toNumber());                     // 123.456789

// JSON serialization
console.log(JSON.stringify({amount: value}));      // {"amount":"123.456789"}
console.log(value.valueOf());                      // "123.456789"

Properties and State

interface Big {
    // Read-only properties
    readonly s: number;    // Sign: 1 for positive, -1 for negative
    readonly e: number;    // Exponent
    readonly c: number[];  // Coefficient array (digits)
}

// Usage examples
const positive = new Big("123.456");
const negative = new Big("-789.012");
const zero = new Big("0");

console.log("Positive number:");
console.log(`  Sign: ${positive.s}`);      // 1
console.log(`  Exponent: ${positive.e}`);  // 2 (position of decimal point)
console.log(`  Coefficient: ${positive.c}`); // [1,2,3,4,5,6]

console.log("Negative number:");
console.log(`  Sign: ${negative.s}`);      // -1
console.log(`  Exponent: ${negative.e}`);  // 2
console.log(`  Coefficient: ${negative.c}`); // [7,8,9,0,1,2]

console.log("Zero:");
console.log(`  Sign: ${zero.s}`);          // 1
console.log(`  Exponent: ${zero.e}`);      // 0
console.log(`  Coefficient: ${zero.c}`);   // [0]

Practical Integration Examples

Financial Calculations

import { Big, RoundingMode } from "fable-library/lib/big.js";

// Configure for financial calculations
Big.DP = 28;  // High precision for intermediate calculations
Big.RM = RoundingMode.RoundHalfEven; // Banker's rounding

class MonetaryAmount {
    private value: Big;
    
    constructor(amount: BigSource) {
        this.value = new Big(amount);
    }
    
    add(other: MonetaryAmount): MonetaryAmount {
        return new MonetaryAmount(this.value.plus(other.value));
    }
    
    subtract(other: MonetaryAmount): MonetaryAmount {
        return new MonetaryAmount(this.value.minus(other.value));
    }
    
    multiply(factor: BigSource): MonetaryAmount {
        return new MonetaryAmount(this.value.times(factor));
    }
    
    divide(divisor: BigSource): MonetaryAmount {
        return new MonetaryAmount(this.value.div(divisor));
    }
    
    // Calculate percentage
    percentage(percent: BigSource): MonetaryAmount {
        return new MonetaryAmount(this.value.times(percent).div(100));
    }
    
    // Apply tax
    addTax(taxRate: BigSource): MonetaryAmount {
        const tax = this.percentage(taxRate);
        return this.add(new MonetaryAmount(tax.value));
    }
    
    // Currency formatting
    toCurrency(decimals: number = 2): string {
        return this.value.toFixed(decimals, RoundingMode.RoundHalfEven);
    }
    
    // Comparison
    equals(other: MonetaryAmount): boolean {
        return this.value.eq(other.value);
    }
    
    greaterThan(other: MonetaryAmount): boolean {
        return this.value.gt(other.value);
    }
    
    toString(): string {
        return this.value.toString();
    }
}

// Usage examples
const price = new MonetaryAmount("19.99");
const discount = new MonetaryAmount("2.50");
const taxRate = new Big("8.25"); // 8.25%

// Calculate final price
const discountedPrice = price.subtract(discount);      // $17.49
const finalPrice = discountedPrice.addTax(taxRate);    // $18.93 (with tax)

console.log(`Original price: $${price.toCurrency()}`);
console.log(`After discount: $${discountedPrice.toCurrency()}`);
console.log(`Final price (with tax): $${finalPrice.toCurrency()}`);

// Bulk calculations
const items = [
    new MonetaryAmount("15.99"),
    new MonetaryAmount("25.50"),
    new MonetaryAmount("8.75")
];

const total = items.reduce((sum, item) => sum.add(item), new MonetaryAmount("0"));
console.log(`Total: $${total.toCurrency()}`);

Scientific Calculations

import { Big, RoundingMode } from "fable-library/lib/big.js";

// Configure for scientific precision
Big.DP = 50;  // Very high precision
Big.RM = RoundingMode.RoundHalfEven;

class ScientificCalculator {
    // Calculate factorial using Big for large numbers
    static factorial(n: number): Big {
        if (n < 0) throw new Error("Factorial not defined for negative numbers");
        if (n === 0 || n === 1) return new Big("1");
        
        let result = new Big("1");
        for (let i = 2; i <= n; i++) {
            result = result.times(i);
        }
        return result;
    }
    
    // Calculate e^x using Taylor series
    static exp(x: BigSource, terms: number = 50): Big {
        const xBig = new Big(x);
        let result = new Big("1"); // First term is 1
        let term = new Big("1");
        
        for (let i = 1; i < terms; i++) {
            term = term.times(xBig).div(i);
            result = result.plus(term);
        }
        
        return result;
    }
    
    // Calculate natural logarithm using Newton's method
    static ln(x: BigSource, precision: number = 30): Big {
        const xBig = new Big(x);
        if (xBig.lte(0)) throw new Error("ln not defined for non-positive numbers");
        
        // Initial guess
        let y = xBig.div(2);
        const one = new Big("1");
        
        for (let i = 0; i < precision; i++) {
            // Newton's method: y = y + 2*(x - e^y)/(x + e^y)
            const expY = this.exp(y, 30);
            const numerator = xBig.minus(expY).times(2);
            const denominator = xBig.plus(expY);
            y = y.plus(numerator.div(denominator));
        }
        
        return y;
    }
    
    // Calculate π using Machin's formula
    static pi(precision: number = 50): Big {
        // π/4 = 4*arctan(1/5) - arctan(1/239)
        const arctan1_5 = this.arctan(new Big("0.2"), precision);
        const arctan1_239 = this.arctan(new Big(1).div(239), precision);
        
        return arctan1_5.times(4).minus(arctan1_239).times(4);
    }
    
    // Calculate arctan using Taylor series
    private static arctan(x: Big, terms: number): Big {
        let result = new Big("0");
        let xPower = new Big(x);
        const xSquared = x.times(x);
        
        for (let i = 0; i < terms; i++) {
            const term = xPower.div(2 * i + 1);
            if (i % 2 === 0) {
                result = result.plus(term);
            } else {
                result = result.minus(term);
            }
            xPower = xPower.times(xSquared);
        }
        
        return result;
    }
}

// Usage examples
console.log("High-precision scientific calculations:");

// Large factorial
const fact100 = ScientificCalculator.factorial(100);
console.log(`100! = ${fact100.toString()}`);

// Mathematical constants
const e = ScientificCalculator.exp("1", 50);
const pi = ScientificCalculator.pi(50);
console.log(`e ≈ ${e.toFixed(30)}`);
console.log(`π ≈ ${pi.toFixed(30)}`);

// Logarithms
const ln10 = ScientificCalculator.ln("10");
const ln2 = ScientificCalculator.ln("2");
console.log(`ln(10) ≈ ${ln10.toFixed(20)}`);
console.log(`ln(2) ≈ ${ln2.toFixed(20)}`);

Configuration Management

import { Big, RoundingMode } from "fable-library/lib/big.js";

// Utility class for managing Big.js configuration
class BigConfig {
    private static savedConfig: {
        DP: number;
        RM: RoundingMode;
        NE: number;
        PE: number;
        strict: boolean;
    } | null = null;
    
    // Save current configuration
    static save(): void {
        this.savedConfig = {
            DP: Big.DP,
            RM: Big.RM,
            NE: Big.NE,
            PE: Big.PE,
            strict: Big.strict
        };
    }
    
    // Restore saved configuration
    static restore(): void {
        if (this.savedConfig) {
            Big.DP = this.savedConfig.DP;
            Big.RM = this.savedConfig.RM;
            Big.NE = this.savedConfig.NE;
            Big.PE = this.savedConfig.PE;
            Big.strict = this.savedConfig.strict;
        }
    }
    
    // Configure for financial calculations
    static setFinancialMode(): void {
        Big.DP = 28;
        Big.RM = RoundingMode.RoundHalfEven;
        Big.strict = true;
    }
    
    // Configure for scientific calculations
    static setScientificMode(): void {
        Big.DP = 50;
        Big.RM = RoundingMode.RoundHalfEven;
        Big.strict = false; // Allow more flexibility
    }
    
    // Configure for general purpose
    static setGeneralMode(): void {
        Big.DP = 20;
        Big.RM = RoundingMode.RoundHalfUp;
        Big.strict = true;
    }
    
    // Execute function with temporary configuration
    static withConfig<T>(
        config: Partial<typeof Big>, 
        fn: () => T
    ): T {
        this.save();
        
        try {
            Object.assign(Big, config);
            return fn();
        } finally {
            this.restore();
        }
    }
}

// Usage examples
console.log("Configuration management:");

// Default configuration
console.log(`Default DP: ${Big.DP}, RM: ${Big.RM}`);

// Financial calculation with specific configuration
BigConfig.save();
BigConfig.setFinancialMode();

const financialResult = new Big("1000.00")
    .times("0.0825")
    .toFixed(2);
console.log(`Financial calculation: ${financialResult}`);

BigConfig.restore();

// Temporary configuration for scientific calculation
const scientificResult = BigConfig.withConfig(
    { DP: 50, RM: RoundingMode.RoundHalfEven },
    () => {
        return new Big("1").div("3").toFixed(30);
    }
);

console.log(`Scientific calculation: ${scientificResult}`);
console.log(`Restored DP: ${Big.DP}, RM: ${Big.RM}`);

Error Handling and Validation

import { Big } from "fable-library/lib/big.js";

// Utility functions for safe Big.js operations
class BigValidator {
    // Validate if a value can be converted to Big
    static isValidBigSource(value: any): value is BigSource {
        if (value instanceof Big) return true;
        if (typeof value === 'number' && isFinite(value)) return true;
        if (typeof value === 'string') {
            try {
                new Big(value);
                return true;
            } catch {
                return false;
            }
        }
        return false;
    }
    
    // Safe Big creation with error handling
    static safeBig(value: any): Big | null {
        if (!this.isValidBigSource(value)) return null;
        
        try {
            return new Big(value);
        } catch (error) {
            console.error(`Failed to create Big from ${value}:`, error);
            return null;
        }
    }
    
    // Safe arithmetic operations
    static safeAdd(a: BigSource, b: BigSource): Big | null {
        const bigA = this.safeBig(a);
        const bigB = this.safeBig(b);
        
        if (!bigA || !bigB) return null;
        
        try {
            return bigA.plus(bigB);
        } catch (error) {
            console.error(`Failed to add ${a} + ${b}:`, error);
            return null;
        }
    }
    
    static safeDivide(a: BigSource, b: BigSource): Big | null {
        const bigA = this.safeBig(a);
        const bigB = this.safeBig(b);
        
        if (!bigA || !bigB) return null;
        if (bigB.eq(0)) {
            console.error("Division by zero");
            return null;
        }
        
        try {
            return bigA.div(bigB);
        } catch (error) {
            console.error(`Failed to divide ${a} / ${b}:`, error);
            return null;
        }
    }
}

// Usage examples with error handling
const testValues = ["123.456", "invalid", 0, "0", null, undefined, NaN, Infinity];

testValues.forEach(value => {
    console.log(`Testing ${value}:`);
    
    const isValid = BigValidator.isValidBigSource(value);
    console.log(`  Valid: ${isValid}`);
    
    const big = BigValidator.safeBig(value);
    console.log(`  Big: ${big ? big.toString() : 'null'}`);
    
    if (big) {
        const sum = BigValidator.safeAdd(big, "100");
        const quotient = BigValidator.safeDivide(big, "3");
        
        console.log(`  +100: ${sum ? sum.toString() : 'failed'}`);
        console.log(`  /3: ${quotient ? quotient.toFixed(6) : 'failed'}`);
    }
    
    console.log();
});