TypeScript Sized Integer Implementation
Many programming languages offer fixed-size integer types (e.g., int8, uint32). These types guarantee that a value will always fit within a specific bit range, preventing overflow errors and enabling efficient memory usage. In TypeScript, we typically work with the number type, which is a double-precision floating-point number and doesn't inherently enforce size constraints. This challenge asks you to implement custom sized integer types in TypeScript.
Problem Description
Your task is to create a mechanism in TypeScript that allows for the definition and usage of integers with specific bit sizes. This should include both signed and unsigned integers. You need to handle:
- Type Definition: Create distinct types for different bit sizes (e.g.,
Int8,Uint8,Int16,Uint16,Int32,Uint32). - Value Representation: Ensure that values assigned to these types adhere to their defined size and signedness.
- Arithmetic Operations: Implement basic arithmetic operations (addition, subtraction, multiplication) that respect the size constraints and perform appropriate wrapping or saturation on overflow.
- Type Safety: Leverage TypeScript's type system to enforce these constraints at compile time where possible, and at runtime otherwise.
You should aim to create a flexible system that can be extended to other bit sizes if needed, though focusing on the common 8, 16, and 32-bit integers is sufficient for this challenge.
Examples
Example 1: Uint8 (Unsigned 8-bit Integer)
// Assuming you have implemented Uint8
const u8_max = new Uint8(255);
const u8_one = new Uint8(1);
const result_add = u8_max.add(u8_one); // Should wrap around
console.log(result_add.getValue()); // Expected output: 0
const result_sub = u8_one.subtract(new Uint8(2)); // Should wrap around
console.log(result_sub.getValue()); // Expected output: 255
Explanation:
Adding 1 to the maximum Uint8 value (255) should result in 0 due to unsigned 8-bit integer wrapping. Subtracting 2 from 1 should wrap around from 0 to 255.
Example 2: Int16 (Signed 16-bit Integer)
// Assuming you have implemented Int16
const i16_min = new Int16(-32768);
const i16_one = new Int16(1);
const result_sub = i16_min.subtract(i16_one); // Should saturate at minimum
console.log(result_sub.getValue()); // Expected output: -32768
const i16_max = new Int16(32767);
const result_add_overflow = i16_max.add(new Int16(2)); // Should saturate at maximum
console.log(result_add_overflow.getValue()); // Expected output: 32767
Explanation:
Subtracting 1 from the minimum Int16 value (-32768) should result in saturation at -32768 because the value would become -32769, which is out of range for a signed 16-bit integer. Similarly, adding 2 to the maximum Int16 value (32767) should saturate at 32767.
Example 3: Uint32 Addition with Intermediate Overflow
// Assuming you have implemented Uint32
const u32_large1 = new Uint32(0xFFFFFFFF); // Max Uint32
const u32_large2 = new Uint32(1);
const result_overflow = u32_large1.add(u32_large2); // Should wrap around
console.log(result_overflow.getValue()); // Expected output: 0
Explanation:
Adding 1 to the maximum Uint32 value results in wrapping around to 0, demonstrating correct overflow behavior for unsigned 32-bit integers.
Constraints
- The implementation should focus on
Int8,Uint8,Int16,Uint16,Int32, andUint32. - Arithmetic operations (
add,subtract,multiply) must be implemented for each type. - For signed types, overflow should result in saturation (clamping to the minimum or maximum representable value).
- For unsigned types, overflow should result in wrapping (circular behavior).
- The internal representation of the numbers can be TypeScript's
numbertype, but you must ensure that the operations and values are managed according to the specified bit sizes. - You should provide a method (e.g.,
getValue()) to retrieve the underlying numeric value, which should be within the correct range for the type. - When constructing a new instance, if the provided value is out of range for the target type, it should be clamped or wrapped appropriately during initialization.
Notes
- Consider how to best represent the bit size and signedness. A factory pattern or class inheritance might be useful.
- Think about the mathematical formulas for signed and unsigned integer ranges and overflow/underflow behavior.
- TypeScript's
numbertype is a 64-bit float, so you'll need to be careful about precision when dealing with large 32-bit integer values and avoid JavaScript's automatic conversion to floats that might lose precision if not handled correctly (though for the specified 32-bit integers, standardnumbershould suffice if operations are managed carefully). - The primary goal is to enforce the behavior of sized integers using TypeScript.