A C99 project for parsing, displaying, and manipulating numbers in arbitrary bases (2-36) with support for decimal points and repeating decimals.
- Multi-base support: Bases 2 through 36 (using digits 0-9 and letters A-Z)
- Decimal representation: Support for fractional parts (e.g.,
1A.3Fin base 16) - Repeating decimals: Notation using parentheses (e.g.,
1.(3)represents 1.333...) - Negative numbers: Standard negative sign notation
- Input/Output symmetry:
base#numberformat for both input and output - Interactive REPL: Read-Eval-Print-Loop for easy experimentation
- Comprehensive validation: Extensive error checking with helpful messages
[base#][-]digits[.digits][(repeating_digits)]
123- Decimal number (base 10, default)16#1A3F- Hexadecimal number2#1011.01- Binary with decimal point36#Z9A- Base 36 using letters-9.8- Negative decimal1.(3)- Repeating decimal (1.333...)16#1A.3(45)- Hex with decimal and repeating parts
Non-decimal numbers are displayed with the base# prefix:
> 16#FF
16#FF
> 255
255
- CMake 3.10 or higher
- C99-compatible compiler (GCC, Clang)
- Ninja build system (optional but recommended)
# Configure
cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug -S . -B build
# Build
cmake --build build
# Or use the provided tasks
cmake --build build # for the default build taskThe project includes pre-configured tasks:
- configure: Set up CMake build system
- build: Compile the project
- clean: Remove build artifacts
./build/mathThis runs the built-in test suite with:
- 10 valid test cases (various number formats)
- 12 invalid test cases (validation checks)
./build/math replThe REPL accepts numbers in base#number format:
=== Math REPL ===
Enter numbers in format: base#number (e.g., 16#1A.3(45))
Default base is 10 if no prefix (e.g., 123.45)
Type 'exit' to quit
> 16#1A.3(45)
16#1A.3(45)
> 2#1011.01
2#1011.01
> 123.45
123.45
> exit
Exiting REPL
typedef uint8_t glyph_t; // Character representation (0-9, A-Z)
typedef uint8_t value_t; // Numeric value (0-35)
typedef uint8_t base_t; // Number base (2-36)typedef struct {
number_proto_t proto; // Base number data (base, digits, length)
bool is_negative; // Sign flag
size_t decimal_length; // Number of decimal digits
size_t repeating_length; // Number of repeating digits
} number_t;initialize_number_from_string(str, base)- Parse formatted string into number_tdisplay_number(num)- Print number with base# prefixvalue_to_glyph(value)- Convert numeric value to characterglyph_to_value(glyph)- Convert character to numeric value
allocate_number_array(base, length)- Allocate number structuredeallocate_number(num)- Free allocated memory
repl()- Interactive Read-Eval-Print-Loop
The parser performs comprehensive validation:
- Negative sign must be at the start
- Decimal point requires digits before and after
- Repeating section must:
- Come after decimal point
- Be non-empty
- Use matching parentheses
- Character validation for the specified base
- No nested parentheses
- At least one digit required
Error messages are written to stderr with clear descriptions.
The project uses clang-format with LLVM style:
clang-format -i src/main.cVS Code auto-formats on save for .c and .cpp files.
GDB configuration is included in .vscode/launch.json:
- Pretty-printing enabled
- Debug build with
-g -O0
- Standard: C99
- Warnings:
-Wall -Wextra - Build type: Debug (with symbols)
- EVAL step: Arithmetic operations in the REPL
- Base conversion: Convert between different bases
- Math operations: Addition, subtraction, multiplication, division
- Precision control: Configurable decimal places for repeating sections
MIT License - see LICENSE file for details.
This is free and open-source software. You are free to use, modify, and distribute it without restriction.
Key commits:
- Initial implementation with parsing and display
- Memory allocation error handling
- Comprehensive input validation
- Invalid number representation (
<<NaN>>) - REPL functionality
- Base# prefix for input/output symmetry