Implementing Negative Numbers with Custom Arithmetic in Rust
This challenge focuses on creating a custom number type in Rust that represents negative numbers using a fixed-width integer representation. You'll define an impl block for this custom type, providing basic arithmetic operations (+, -, *, /) and comparison operators (<, >, <=, >=, ==, !=) that handle the nuances of representing negative values within the fixed-width constraint. This exercise demonstrates Rust's powerful impl feature and the ability to define custom behavior for data types.
Problem Description
You are tasked with creating a new number type called FixedWidthInt that represents integers within a fixed width (e.g., 8 bits, 16 bits). This type should be able to represent both positive and negative numbers using two's complement representation. You need to implement the following traits and methods for FixedWidthInt:
std::ops::Add: Implement addition (+) forFixedWidthInt. Handle overflow and underflow correctly, wrapping around the fixed width.std::ops::Sub: Implement subtraction (-) forFixedWidthInt. Handle overflow and underflow correctly, wrapping around the fixed width.std::ops::Mul: Implement multiplication (*) forFixedWidthInt. Handle overflow and underflow correctly, wrapping around the fixed width.std::ops::Div: Implement division (/) forFixedWidthInt. Handle division by zero by returningNone. Handle overflow and underflow correctly, wrapping around the fixed width.std::cmp::PartialOrd: Implement comparison operators (<,>,<=,>=) forFixedWidthInt.std::cmp::Eq: Implement equality operators (==,!=) forFixedWidthInt.
The FixedWidthInt type should be generic over the bit width, allowing you to create different sized integers (e.g., FixedWidthInt<8>, FixedWidthInt<16>).
Examples
Example 1: (8-bit)
Input: FixedWidthInt<8>::new(5) + FixedWidthInt<8>::new(3)
Output: FixedWidthInt<8>::new(8)
Explanation: 5 + 3 = 8, which fits within 8 bits.
Example 2: (8-bit)
Input: FixedWidthInt<8>::new(127) + FixedWidthInt<8>::new(1)
Output: FixedWidthInt<8>::new(0)
Explanation: 127 + 1 = 128, which overflows. It wraps around to 0 (128 % 256 = 0).
Example 3: (8-bit)
Input: FixedWidthInt<8>::new(5) - FixedWidthInt<8>::new(3)
Output: FixedWidthInt<8>::new(2)
Explanation: 5 - 3 = 2.
Example 4: (8-bit)
Input: FixedWidthInt<8>::new(-1) - FixedWidthInt<8>::new(1)
Output: FixedWidthInt<8>::new(255)
Explanation: -1 - 1 = -2, which underflows. It wraps around to 255 (256 - 2 = 254, but we want the two's complement representation).
Example 5: (8-bit)
Input: FixedWidthInt<8>::new(10) / FixedWidthInt<8>::new(0)
Output: None
Explanation: Division by zero is undefined.
Constraints
- The bit width (
N) must be a compile-time constant between 8 and 32 (inclusive). - The
FixedWidthInttype must use two's complement representation for negative numbers. - All arithmetic operations must wrap around the fixed width.
- Division by zero must return
None. - The implementation should be reasonably efficient. Avoid unnecessary allocations.
Notes
- Consider using Rust's
Wrappingmodule for handling overflow and underflow in arithmetic operations. - You'll need to define a
new()method forFixedWidthIntto create instances from raw integer values. - Remember that two's complement representation is crucial for correctly representing negative numbers.
- The
PartialOrdtrait requires implementing<and either<=or>=. You can choose which one to implement. - The
Eqtrait requires implementing==and either!=or vice versa. You can choose which one to implement. - Think carefully about how to handle the sign bit when performing arithmetic operations.
- Consider using
u32internally to represent the value, and then masking it to fit within the fixed width. This simplifies the implementation.