#!/usr/bin/env python3 # MIT License # # Copyright (c) 2026 Kevin Thomas # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. # # Author: Kevin Thomas # Email: kevin@mytechnotalent.com # GitHub: https://github.com/mytechnotalent # File: float_hex_converter.py # Desc: Convert and explain IEEE 754 float/hex operations step-by-step. # Created: 2026 """Convert and explain IEEE 754 float/hex operations step-by-step.""" import argparse import struct import sys def _exp_str(e_val: int, bias: int, is_64: bool) -> str: """ Get accurate true exponent string accounting for IEEE 754 edge cases. Parameters ---------- e_val : int The stored exponent value. bias : int The exponent bias (127 or 1023). is_64 : bool True if 64-bit precision. Returns ------- str The formatted true exponent explanation string. """ if e_val == 0: return f"0 (Zero/Subnormal, True Exp: {1 - bias})" if e_val == (2047 if is_64 else 255): return f"{e_val} (Inf/NaN flag)" return f"{e_val} - {bias} = {e_val - bias}" def _print_encode_steps(val: float, b: int) -> None: """ Print the math steps for encoding a float to hex. Parameters ---------- val : float The float value to encode. b : int The bit size (32 or 64). Returns ------- None """ f1, f2, bias = (" None: """ Print the math steps for decoding a hex string to float. Parameters ---------- hex_str : str The hex string to decode. Returns ------- None """ c = hex_str.lower() if c.startswith("0x"): c = c[2:] b, f1, f2, bias = (64, " 8 else (32, " bool: """ Check if a string is a hexadecimal representation. Parameters ---------- s : str Candidate string, with or without a 0x prefix. Returns ------- bool True if every character is a hexadecimal digit. """ cleaned = s.lower() if cleaned.startswith("0x"): cleaned = cleaned[2:] if not cleaned: return False return all(c in "0123456789abcdef" for c in cleaned) def _process_conversion(val_str: str) -> None: """ Execute the conversion and print the output. Parameters ---------- val_str : str The raw input string to process. Returns ------- None """ cleaned = val_str.strip() if cleaned.lower().startswith("0x") or (len(cleaned) >= 8 and _is_hex(cleaned)): _print_decode_steps(cleaned) else: val = float(cleaned) _print_encode_steps(val, 32) _print_encode_steps(val, 64) def main() -> int: """ Execute the conversion pipeline based on CLI arguments. Parameters ---------- None Returns ------- int Zero on successful conversion, otherwise non-zero. """ parser = argparse.ArgumentParser(description="Float/Hex step converter.") parser.add_argument("val", help="Hex (0x...) or Float value to convert.") args = parser.parse_args() try: _process_conversion(args.val) return 0 except Exception as e: print(f"Error: {e}", file=sys.stderr) return 1 if __name__ == "__main__": sys.exit(main())