#pragma once

#include <bit>
#include <cfloat>
#include <cmath>
#include <cstdint>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <limits>
#include <type_traits>

// 2.1 基础模板实现
template <typename T>
class MathUlp {
    static_assert(std::is_floating_point_v<T>, "MathUlp only works with floating-point types");

private:
    using UIntType = std::conditional_t<std::is_same_v<T, float>, uint32_t, std::conditional_t<std::is_same_v<T, double>, uint64_t, void> >;

    static constexpr int BITS = sizeof(T) * 8;
    static constexpr int MANTISSA_BITS = std::numeric_limits<T>::digits - 1;
    static constexpr int EXPONENT_BITS = BITS - MANTISSA_BITS - 1;
    static constexpr UIntType SIGN_BIT = UIntType(1) << (BITS - 1);
    static constexpr UIntType EXPONENT_MASK = ((UIntType(1) << EXPONENT_BITS) - 1) << MANTISSA_BITS;
    static constexpr UIntType MANTISSA_MASK = (UIntType(1) << MANTISSA_BITS) - 1;
    static constexpr int EXPONENT_BIAS = (1 << (EXPONENT_BITS - 1)) - 1;
    static constexpr int MAX_EXPONENT = (1 << EXPONENT_BITS) - 1;

    // 按位访问浮点数
    static UIntType get_bits(T value) {
        UIntType bits;
        std::memcpy(&bits, &value, sizeof(T));
        return bits;
    }

    static T from_bits(UIntType bits) {
        T value;
        std::memcpy(&value, &bits, sizeof(T));
        return value;
    }

    // 获取指数部分
    static int get_exponent(T value) {
        UIntType bits = get_bits(value);
        UIntType exp_bits = (bits >> MANTISSA_BITS) & ((UIntType(1) << EXPONENT_BITS) - 1);
        return static_cast<int>(exp_bits) - EXPONENT_BIAS;
    }

    // 获取尾数部分
    static UIntType get_mantissa(T value) {
        UIntType bits = get_bits(value);
        return bits & MANTISSA_MASK;
    }

    // 判断是否为规格化数
    static bool is_normal(T value) {
        if (value == 0 || std::isinf(value) || std::isnan(value))
            return false;
        int exp = get_exponent(value);
        return exp > -EXPONENT_BIAS && exp <= EXPONENT_BIAS;
    }

    // 判断是否为非规格化数（次正规数）
    static bool is_subnormal(T value) {
        if (value == 0 || std::isinf(value) || std::isnan(value))
            return false;
        int exp = get_exponent(value);
        return exp == -EXPONENT_BIAS && get_mantissa(value) != 0;
    }

public:
    // 主函数：计算ulp
    static T ulp(T x) {
        // 处理特殊值
        if (std::isnan(x)) {
            return std::numeric_limits<T>::quiet_NaN();
        }

        if (std::isinf(x)) {
            return std::numeric_limits<T>::infinity();
        }

        // 处理0
        if (x == 0.0 || x == -0.0) {
            return std::numeric_limits<T>::min();  // 最小正规格化数
        }

        // 获取x的绝对值
        T abs_x = std::fabs(x);

        // 对于非规格化数，ulp是固定的
        if (is_subnormal(abs_x)) {
            // 非规格化数的ulp是最小正非规格化数
            return std::numeric_limits<T>::denorm_min();
        }

        // 对于规格化数
        int exp = get_exponent(abs_x);

        // ulp = 2^(exp - mantissa_bits)
        // 对于float: ulp = 2^(exp - 23)
        // 对于double: ulp = 2^(exp - 52)
        if constexpr (std::is_same_v<T, float>) {
            // 使用ldexp计算2的幂次
            return std::ldexp(1.0f, exp - 23);
        } else if constexpr (std::is_same_v<T, double>) {
            return std::ldexp(1.0, exp - 52);
        } else if constexpr (std::is_same_v<T, long double>) {
            // long double的实现可能因平台而异
            constexpr int LD_MANTISSA_BITS = std::numeric_limits<long double>::digits - 1;
            return std::ldexp(1.0L, exp - LD_MANTISSA_BITS);
        }
    }

    // 使用nextafter的实现（更简单但可能有性能开销）
    static T ulp_simple(T x) {
        // 处理特殊值
        if (std::isnan(x)) {
            return std::numeric_limits<T>::quiet_NaN();
        }

        if (std::isinf(x)) {
            return std::numeric_limits<T>::infinity();
        }

        // 处理0
        if (x == 0.0 || x == -0.0) {
            return std::numeric_limits<T>::min();
        }

        // 使用nextafter计算ulp
        T next = std::nextafter(std::fabs(x), std::numeric_limits<T>::infinity());
        T prev = std::nextafter(std::fabs(x), -std::numeric_limits<T>::infinity());

        // 取最小的正差值
        T diff1 = next - std::fabs(x);
        T diff2 = std::fabs(x) - prev;

        // 返回较小的正差值
        if (diff1 > 0 && diff2 > 0) {
            return std::min(diff1, diff2);
        } else if (diff1 > 0) {
            return diff1;
        } else {
            return diff2;
        }
    }

    // 获取浮点数的内部表示信息
    static void print_float_info(T value) {
        std::cout << "Value: " << std::setprecision(15) << value << "\n";
        std::cout << "Hex bits: ";

        if constexpr (std::is_same_v<T, float>) {
            uint32_t bits;
            std::memcpy(&bits, &value, sizeof(float));
            std::cout << std::hex << bits << std::dec;
            std::cout << "\nSign: " << ((bits >> 31) & 1);
            std::cout << "\nExponent: " << ((bits >> 23) & 0xFF);
            std::cout << " (bias-adjusted: " << ((bits >> 23) & 0xFF) - 127 << ")";
            std::cout << "\nMantissa: " << (bits & 0x7FFFFF);
        } else {
            uint64_t bits;
            std::memcpy(&bits, &value, sizeof(double));
            std::cout << std::hex << bits << std::dec;
            std::cout << "\nSign: " << ((bits >> 63) & 1);
            std::cout << "\nExponent: " << ((bits >> 52) & 0x7FF);
            std::cout << " (bias-adjusted: " << ((bits >> 52) & 0x7FF) - 1023 << ")";
            std::cout << "\nMantissa: " << (bits & 0xFFFFFFFFFFFFF);
        }

        std::cout << "\nIs normal: " << std::boolalpha << is_normal(value);
        std::cout << "\nIs subnormal: " << is_subnormal(value);
        std::cout << "\nULP (our): " << ulp(value);
        std::cout << "\nULP (simple): " << ulp_simple(value);
        std::cout << "\n---\n";
    }
};

// 2.2 用户友好接口
template <typename T>
inline T math_ulp(T x) {
    return MathUlp<T>::ulp(x);
}

template <typename T>
inline T math_ulp_simple(T x) {
    return MathUlp<T>::ulp_simple(x);
}

// 2.3 类型别名
using Ulp32 = MathUlp<float>;
using Ulp64 = MathUlp<double>;
using Ulp128 = MathUlp<long double>;