UNPKG

k-number-utils

Version:

A TypeScript utility library for advanced mathematical operations, including BigInt conversions, type-safe numeric coercions, and deterministic string-to-number transformations.

560 lines (390 loc) 17.3 kB
# k-number-utils A TypeScript utility library for advanced mathematical operations, including BigInt conversions, type-safe numeric coercions, and deterministic string-to-number transformations. ## Features - 🎯 **`BigIntCoercion`** - Comprehensive BigInt wrapper with 25+ conversion methods - 🔄 **`stringToBigInt`** - Deterministic string-to-BigInt converter using UTF-8 encoding - 🛡️ **Type-safe** - Full TypeScript support with proper type annotations - ⚡ **Performance optimized** - Efficient conversions with minimal overhead - 🌐 **Unicode support** - Properly handles all Unicode characters including emojis ## Installation ```bash npm install k-number-utils ``` ## Table of Contents - [BigIntCoercion Class](#bigintcoercion-class) - [stringToBigInt Function](#stringtobigint-function) - [Use Cases](#use-cases) - [Browser Compatibility](#browser-and-nodejs-compatibility) --- ## BigIntCoercion Class A comprehensive class for coercing BigInt values to multiple numeric formats with predictable overflow/underflow behavior. ### Overview The `BigIntCoercion` class wraps a BigInt value and provides methods to convert it to various numeric types with different bit widths. It handles overflow and wrapping according to each numeric type's specifications. **Note**: Collision risk is expected when converting large BigInt values to smaller numeric types due to truncation and wrapping behavior. ### Constructor ```typescript new BigIntCoercion(value: bigint) ``` **Example:** ```typescript import { BigIntCoercion } from "k-number-utils" const bn = new BigIntCoercion(123456789n) const large = new BigIntCoercion(BigInt("999999999999999999")) ``` ### Core Methods #### `toBigInt(): bigint` Returns the original BigInt value. ```typescript new BigIntCoercion(123n).toBigInt() // 123n ``` #### `toNumber(): number` Converts to a JavaScript Number. **Warning**: May lose precision for values outside ±2^53 - 1. ```typescript new BigIntCoercion(42n).toNumber() // 42 new BigIntCoercion(9007199254740992n).toNumber() // May lose precision ``` ### Integer Conversion Methods #### 8-bit Conversions ##### `toInt8(): number` Converts to signed 8-bit integer (-128 to 127). ```typescript new BigIntCoercion(127n).toInt8() // 127 new BigIntCoercion(128n).toInt8() // -128 (wrapped) new BigIntCoercion(-129n).toInt8() // 127 (wrapped) ``` ##### `toUint8(): number` Converts to unsigned 8-bit integer (0 to 255). ```typescript new BigIntCoercion(255n).toUint8() // 255 new BigIntCoercion(256n).toUint8() // 0 (wrapped) new BigIntCoercion(-1n).toUint8() // 255 (wrapped) ``` #### 16-bit Conversions ##### `toInt16(): number` Converts to signed 16-bit integer (-32768 to 32767). ```typescript new BigIntCoercion(32767n).toInt16() // 32767 new BigIntCoercion(32768n).toInt16() // -32768 (wrapped) ``` ##### `toUint16(): number` Converts to unsigned 16-bit integer (0 to 65535). ```typescript new BigIntCoercion(65535n).toUint16() // 65535 new BigIntCoercion(65536n).toUint16() // 0 (wrapped) ``` #### 32-bit Conversions ##### `toInt32(): number` Converts to signed 32-bit integer (-2147483648 to 2147483647). ```typescript new BigIntCoercion(2147483647n).toInt32() // 2147483647 new BigIntCoercion(2147483648n).toInt32() // -2147483648 (wrapped) ``` ##### `toUint32(): number` Converts to unsigned 32-bit integer (0 to 4294967295). ```typescript new BigIntCoercion(4294967295n).toUint32() // 4294967295 new BigIntCoercion(-1n).toUint32() // 4294967295 (wrapped) ``` ##### `toAbsInt32(): number` ⭐ NEW Converts to absolute value clamped to positive signed 32-bit range (0 to 2147483647). ```typescript new BigIntCoercion(123n).toAbsInt32() // 123 new BigIntCoercion(-123n).toAbsInt32() // 123 (absolute) new BigIntCoercion(2147483647n).toAbsInt32() // 2147483647 (max) new BigIntCoercion(2147483648n).toAbsInt32() // 0 (wrapped) ``` #### 64-bit Conversions ##### `toInt64(): number` / `toUint64(): number` Converts to 64-bit integers as numbers. **Warning**: Precision loss beyond ±2^53. ```typescript new BigIntCoercion(9007199254740991n).toInt64() // Exact new BigIntCoercion(9007199254740992n).toInt64() // May lose precision ``` ##### `toBigInt64(): bigint` / `toBigUint64(): bigint` Converts to precise 64-bit BigInt values (preferred for 64-bit operations). ```typescript new BigIntCoercion(9223372036854775807n).toBigInt64() // 9223372036854775807n new BigIntCoercion(9223372036854775808n).toBigInt64() // -9223372036854775808n (wrapped) new BigIntCoercion(18446744073709551615n).toBigUint64() // 18446744073709551615n new BigIntCoercion(-1n).toBigUint64() // 18446744073709551615n (wrapped) ``` ### Character and String Methods #### `toChar(): string` Converts to a Unicode character using the lower 16 bits. ```typescript new BigIntCoercion(65n).toChar() // 'A' new BigIntCoercion(8364n).toChar() // '€' (Euro sign) ``` #### `toCodePoint(): string` Converts to a full Unicode character using the lower 21 bits (supports emojis). ```typescript new BigIntCoercion(65n).toCodePoint() // 'A' new BigIntCoercion(128512n).toCodePoint() // '😀' (emoji) new BigIntCoercion(127775n).toCodePoint() // '🌟' (star emoji) ``` #### `toHex(prefix?: boolean): string` Converts to hexadecimal string representation. ```typescript new BigIntCoercion(255n).toHex() // '0xff' new BigIntCoercion(255n).toHex(false) // 'ff' new BigIntCoercion(4096n).toHex() // '0x1000' ``` #### `toBinary(prefix?: boolean): string` Converts to binary string representation. ```typescript new BigIntCoercion(5n).toBinary() // '0b101' new BigIntCoercion(5n).toBinary(false) // '101' new BigIntCoercion(255n).toBinary() // '0b11111111' ``` #### `toOctal(prefix?: boolean): string` Converts to octal string representation. ```typescript new BigIntCoercion(8n).toOctal() // '0o10' new BigIntCoercion(8n).toOctal(false) // '10' new BigIntCoercion(511n).toOctal() // '0o777' ``` #### `toString(radix?: number): string` Converts to string in any base (2-36). ```typescript new BigIntCoercion(42n).toString() // '42' new BigIntCoercion(42n).toString(16) // '2a' new BigIntCoercion(42n).toString(2) // '101010' ``` ### Utility Methods #### `isZero(): boolean` ```typescript new BigIntCoercion(0n).isZero() // true new BigIntCoercion(1n).isZero() // false ``` #### `isPositive(): boolean` ```typescript new BigIntCoercion(1n).isPositive() // true new BigIntCoercion(-1n).isPositive() // false ``` #### `isNegative(): boolean` ```typescript new BigIntCoercion(-1n).isNegative() // true new BigIntCoercion(1n).isNegative() // false ``` #### `isEven(): boolean` ```typescript new BigIntCoercion(2n).isEven() // true new BigIntCoercion(3n).isEven() // false ``` #### `isOdd(): boolean` ```typescript new BigIntCoercion(3n).isOdd() // true new BigIntCoercion(2n).isOdd() // false ``` #### `equals(other: BigIntCoercion): boolean` ```typescript const a = new BigIntCoercion(42n) const b = new BigIntCoercion(42n) a.equals(b) // true ``` --- ## stringToBigInt Function ### `stringToBigInt(seed: string, encoder?: TextEncoder): BigIntCoercion` Converts a string into a deterministic `BigIntCoercion` instance using UTF-8 encoding and big-endian representation. This function encodes the input string as UTF-8 bytes and converts them into a big-endian BigInt representation wrapped in a `BigIntCoercion` instance. It properly handles all Unicode characters including emojis, special characters, and multi-byte sequences. **Parameters:** - `seed` (string): The input string to convert - `encoder` (TextEncoder, optional): Custom TextEncoder instance for UTF-8 encoding. If not provided, a new TextEncoder will be created. Reusing an encoder instance can improve performance when calling this function frequently. ### Usage ```typescript import { stringToBigInt } from "k-number-utils" // Basic ASCII string - returns BigIntCoercion instance const hello = stringToBigInt("hello") hello.toBigInt() // 448378203247n hello.toInt32() // 1701604463 hello.toUint8() // 111 (lower 8 bits) // Single character stringToBigInt("A").toBigInt() // 65n stringToBigInt("A").toUint8() // 65 // Empty string stringToBigInt("").toBigInt() // 0n // Unicode emoji // Emoji and multi-byte character support stringToBigInt("🚀").toBigInt() // 4036991616n stringToBigInt("🚀").toInt32() // -257975680 // Chinese characters stringToBigInt("你好").toBigInt() // 251503099356605n stringToBigInt("你好").toChar() // 'ꖽ' (lower 16 bits) // Mixed content const mixed = stringToBigInt("Hello 🌍") mixed.toBigInt() // Large BigInt value mixed.toHex() // Hexadecimal representation mixed.isPositive() // true ``` ### Advanced Usage Examples #### Converting to Multiple Formats ```typescript const input = stringToBigInt("test") // Get different representations const bigint = input.toBigInt() // Raw BigInt const hex = input.toHex() // Hexadecimal string const int32 = input.toInt32() // 32-bit signed integer const uint8 = input.toUint8() // 8-bit unsigned byte const char = input.toChar() // Unicode character const binary = input.toBinary() // Binary string ``` #### Using as Hash Alternative ```typescript // Generate deterministic numeric IDs from strings function generateId(name: string): number { return stringToBigInt(name).toUint32() } generateId("user123") // Always returns the same value generateId("admin") // Different value ``` #### Performance Optimization with Reusable Encoder ```typescript // Create a reusable encoder for better performance in loops const encoder = new TextEncoder() // Process multiple strings efficiently const ids = ["user1", "user2", "user3"].map((name) => stringToBigInt(name, encoder).toUint32(), ) // Or in a hot path function processLargeDataset(items: string[]) { const encoder = new TextEncoder() return items.map((item) => stringToBigInt(item, encoder).toBigInt()) } ``` #### Type Coercion Chain ```typescript // Chain conversions for specific use cases const value = stringToBigInt("🎯 Target").toBigInt() // Get raw BigInt const hash = stringToBigInt("password").toAbsInt32() // Get positive 32-bit hash const byte = stringToBigInt("A").toUint8() // Get single byte (65) ``` ### Features - ✅ **Type-safe**: Returns `BigIntCoercion` instance with 25+ conversion methods - ✅ **Input validation**: Throws `TypeError` for non-string inputs - ✅ **Unicode support**: Properly handles all Unicode characters including emojis and multi-byte sequences - ✅ **Deterministic**: Always returns the same BigInt for the same input string - ✅ **Big-endian encoding**: Maintains proper byte order for consistent results - ✅ **Empty string handling**: Returns `BigIntCoercion(0n)` for empty strings - ✅ **Performance optimized**: Early returns for edge cases ### Error Handling The function throws a `TypeError` if the input is not a string: ```typescript stringToBigInt(null) // TypeError: Expected a string, but received object stringToBigInt(undefined) // TypeError: Expected a string, but received undefined stringToBigInt(123) // TypeError: Expected a string, but received number ``` ### Implementation Details The function uses the following approach: 1. **Validation**: Ensures the input is a valid string type 2. **UTF-8 Encoding**: Uses `TextEncoder` to convert the string to UTF-8 bytes 3. **Hex Conversion**: Converts each byte to a 2-digit hexadecimal string 4. **BigInt Creation**: Combines the hex string and converts to BigInt 5. **Wrapping**: Returns a `BigIntCoercion` instance for flexible type conversions This ensures: - Consistent encoding across all JavaScript environments - Proper handling of Unicode characters and surrogate pairs - Big-endian byte order for predictable results - Maximum compatibility with web and Node.js environments - Flexible output format through `BigIntCoercion` methods --- ## Use Cases ### Deterministic Hashing (when a full hash function is overkill) Convert strings to numeric values for consistent identification. Ideally suited for scenarios where a simple, deterministic numeric representation is needed without cryptographic guarantees: ```typescript const userId = stringToBigInt("user@example.com").toUint32() const sessionId = stringToBigInt("session-token-xyz").toAbsInt32() ``` ### Random Number Seeding Generate numeric seeds from string inputs: ```typescript function seededRandom(seed: string): number { const value = stringToBigInt(seed).toUint32() return value / 0xffffffff // Normalize to [0, 1) } ``` ### Data Encoding Convert text data into various numeric representations: ```typescript const bytes = stringToBigInt("Hello").toUint8() // Single byte const int32 = stringToBigInt("Hello").toInt32() // 32-bit int const hex = stringToBigInt("Hello").toHex() // Hex string ``` ### Collision-Resistant IDs Generate numeric IDs with controllable collision space: ```typescript // 8-bit space (256 possible values) - high collision risk const smallId = stringToBigInt("item-123").toUint8() // 32-bit space (4.2B values) - low collision risk const largeId = stringToBigInt("item-123").toUint32() ``` ### Performance Considerations - By default, the function creates a new `TextEncoder` instance for each call - **Optimization**: Pass a reusable `TextEncoder` instance as the second parameter for better performance in hot paths or loops - For extremely frequent calls, consider caching results if the same strings are processed repeatedly - For very long strings (>10MB), consider processing in chunks - `BigIntCoercion` methods are optimized and have minimal overhead **Example optimization:** ```typescript // ❌ Less efficient - creates new encoder each time for (let i = 0; i < 10000; i++) { stringToBigInt(items[i]) } // ✅ More efficient - reuses encoder const encoder = new TextEncoder() for (let i = 0; i < 10000; i++) { stringToBigInt(items[i], encoder) } ``` --- ## Browser and Node.js Compatibility **Minimum Requirements:** - ✅ Node.js 10.4.0+ (BigInt support) - ✅ Chrome 67+ - ✅ Firefox 68+ - ✅ Safari 14+ - ✅ Edge 79+ **Features Used:** - `BigInt` - Native support for arbitrary precision integers - `TextEncoder` - UTF-8 encoding API (available in all modern environments) - `BigInt.asIntN()` / `BigInt.asUintN()` - Bit truncation methods --- ## API Reference Summary ### BigIntCoercion Class | Method | Return Type | Range/Description | | ------------------- | ----------- | ------------------------------------------- | | `toBigInt()` | `bigint` | Original BigInt value | | `toNumber()` | `number` | JavaScript Number (may lose precision) | | `toInt8()` | `number` | -128 to 127 | | `toUint8()` | `number` | 0 to 255 | | `toInt16()` | `number` | -32768 to 32767 | | `toUint16()` | `number` | 0 to 65535 | | `toInt32()` | `number` | -2147483648 to 2147483647 | | `toUint32()` | `number` | 0 to 4294967295 | | `toAbsInt32()` | `number` | 0 to 2147483647 (absolute + 31-bit) | | `toInt64()` | `number` | 64-bit signed (precision loss warning) | | `toUint64()` | `number` | 64-bit unsigned (precision loss warning) | | `toBigInt64()` | `bigint` | 64-bit signed BigInt (precise) | | `toBigUint64()` | `bigint` | 64-bit unsigned BigInt (precise) | | `toChar()` | `string` | Unicode character (16-bit code point) | | `toCodePoint()` | `string` | Unicode character (21-bit, supports emojis) | | `toHex(prefix?)` | `string` | Hexadecimal string | | `toBinary(prefix?)` | `string` | Binary string | | `toOctal(prefix?)` | `string` | Octal string | | `toString(radix?)` | `string` | String in any base (2-36) | | `isZero()` | `boolean` | Check if value is 0n | | `isPositive()` | `boolean` | Check if value > 0n | | `isNegative()` | `boolean` | Check if value < 0n | | `isEven()` | `boolean` | Check if value is even | | `isOdd()` | `boolean` | Check if value is odd | | `equals(other)` | `boolean` | Compare with another BigIntCoercion | ### Functions | Function | Parameters | Returns | Description | | ------------------ | ------------------------------------- | ---------------- | ------------------------------------------------------ | | `stringToBigInt()` | `seed: string, encoder?: TextEncoder` | `BigIntCoercion` | Converts string to BigIntCoercion using UTF-8 encoding | --- ## License MIT License - see LICENSE file for details ## Contributing Contributions are welcome! Please feel free to submit a Pull Request. --- **Made with ❤️ by [@21no.de](https://21no.de) for the JavaScript/TypeScript community**