Hone logo
Hone
Problems

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 (+) for FixedWidthInt. Handle overflow and underflow correctly, wrapping around the fixed width.
  • std::ops::Sub: Implement subtraction (-) for FixedWidthInt. Handle overflow and underflow correctly, wrapping around the fixed width.
  • std::ops::Mul: Implement multiplication (*) for FixedWidthInt. Handle overflow and underflow correctly, wrapping around the fixed width.
  • std::ops::Div: Implement division (/) for FixedWidthInt. Handle division by zero by returning None. Handle overflow and underflow correctly, wrapping around the fixed width.
  • std::cmp::PartialOrd: Implement comparison operators (<, >, <=, >=) for FixedWidthInt.
  • std::cmp::Eq: Implement equality operators (==, !=) for FixedWidthInt.

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 FixedWidthInt type 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 Wrapping module for handling overflow and underflow in arithmetic operations.
  • You'll need to define a new() method for FixedWidthInt to create instances from raw integer values.
  • Remember that two's complement representation is crucial for correctly representing negative numbers.
  • The PartialOrd trait requires implementing < and either <= or >=. You can choose which one to implement.
  • The Eq trait 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 u32 internally to represent the value, and then masking it to fit within the fixed width. This simplifies the implementation.
Loading editor...
rust