C++ 浮点数封装。

头文件:

cpp 复制代码
#ifndef LIBSCL_UTILITY_H_
#define LIBSCL_UTILITY_H_

//////////////////////////////////////////////////////////////////////////

#include "base.h"
#include <type_traits>
#include <limits>
#include <istream>
#include <ostream>

//////////////////////////////////////////////////////////////////////////

namespace scl {

//////////////////////////////////////////////////////////////////////////

bool float_equal(double a, double b, double eps = 1e-9) noexcept;

bool float_greater(double a, double b, double eps = 1e-9) noexcept;

bool float_greater_equal(double a, double b, double eps = 1e-9) noexcept;

bool float_less(double a, double b, double eps = 1e-9) noexcept;

bool float_less_equal(double a, double b, double eps = 1e-9) noexcept;

double float_round_one(double a) noexcept;

double float_round_two(double a) noexcept;

double float_round_three(double a) noexcept;

double float_round_four(double a) noexcept;

double float_round_five(double a) noexcept;

double float_round_six(double a) noexcept;

double float_round(double a, int precision) noexcept;

//////////////////////////////////////////////////////////////////////////

class float_num_t {
  public:
    double value = 0.0;

  public:
    float_num_t() noexcept {
    }

    float_num_t(const double &val) noexcept
        : value(val) {
    }

    float_num_t &operator=(const double &val) noexcept {
        value = val;
        return *this;
    }

    operator double() const noexcept {
        return value;
    }

    /// <
    template <typename T>
    bool operator<(const T &val) const noexcept {
        return float_less(value, static_cast<double>(val));
    }

    /// <=
    template <typename T>
    bool operator<=(const T &val) const noexcept {
        return float_less_equal(value, static_cast<double>(val));
    }

    /// >
    template <typename T>
    bool operator>(const T &val) const noexcept {
        return float_greater(value, static_cast<double>(val));
    }

    /// >=
    template <typename T>
    bool operator>=(const T &val) const noexcept {
        return float_greater_equal(value, static_cast<double>(val));
    }

    /// ==
    template <typename T>
    bool operator==(const T &val) const noexcept {
        return float_equal(value, static_cast<double>(val));
    }

    /// +
    template <typename T>
    float_num_t operator+(const T &val) noexcept {
        return float_num_t(value + static_cast<double>(val));
    }

    /// +=
    template <typename T>
    float_num_t &operator+=(const T &val) noexcept {
        value += static_cast<double>(val);
        return *this;
    }

    /// -
    template <typename T>
    float_num_t operator-(const T &val) noexcept {
        return float_num_t(value - static_cast<double>(val));
    }

    /// -=
    template <typename T>
    float_num_t &operator-=(const T &val) noexcept {
        value -= static_cast<double>(val);
        return *this;
    }

    /// *
    template <typename T>
    float_num_t operator*(const T &val) noexcept {
        return float_num_t(value * static_cast<double>(val));
    }

    /// *=
    template <typename T>
    float_num_t &operator*=(const T &val) noexcept {
        value *= static_cast<double>(val);
        return *this;
    }

    /// /
    template <typename T>
    float_num_t operator/(const T &val) noexcept {
        return float_num_t(value / static_cast<double>(val));
    }

    /// /=
    template <typename T>
    float_num_t &operator/=(const T &val) noexcept {
        value /= static_cast<double>(val);
        return *this;
    }

    float_num_t &round_one() noexcept {
        value = float_round_one(value);
        return *this;
    }

    float_num_t &round_two() noexcept {
        value = float_round_two(value);
        return *this;
    }

    float_num_t &round_three() noexcept {
        value = float_round_three(value);
        return *this;
    }

    float_num_t &round_four() noexcept {
        value = float_round_four(value);
        return *this;
    }

    float_num_t &round_five() noexcept {
        value = float_round_five(value);
        return *this;
    }

    float_num_t &round_six() noexcept {
        value = float_round_six(value);
        return *this;
    }

    float_num_t &round(int precision) noexcept {
        value = float_round(value, precision);
        return *this;
    }

    /// >>
    friend std::ostream &operator<<(std::ostream &os, const float_num_t &v) noexcept {
        os << v.value;
        return os;
    }

    /// <<
    friend std::istream &operator>>(std::istream &is, float_num_t &v) noexcept {
        is >> v.value;
        return is;
    }
};

//////////////////////////////////////////////////////////////////////////

template <typename T>
class range_t {
  public:
    T min = std::numeric_limits<T>::min();
    T max = std::numeric_limits<T>::max();

  public:
    range_t() noexcept {
    }

    range_t(T first, T last) noexcept
        : min(first), max(last) {
        clean();
    }

    range_t(const std::pair<T, T> &p) noexcept
        : min(p.first), max(p.second) {
        clean();
    }

    range_t &operator=(const range_t &p) noexcept {
        if (&p != this) {
            min = p.min;
            max = p.max;
            clean();
        }
        return *this;
    }

    range_t &operator=(const std::pair<T, T> &p) noexcept {
        min = p.first;
        max = p.second;
        clean();
        return *this;
    }

    bool contains(T v) const noexcept {
        if constexpr (std::is_floating_point_v<T>) {
            return float_greater_equal(v, min) && float_less_equal(v, max);
        }
        return min <= v && v <= max;
    }

    bool min_limits() const noexcept {
        return min == std::numeric_limits<T>::min();
    }

    bool max_limits() const noexcept {
        return max == std::numeric_limits<T>::max();
    }

    void clean() noexcept {
        if constexpr (std::is_floating_point_v<T>) {
            if (float_greater(min, max)) {
                std::swap(min, max);
            }
        } else {
            if (min > max) {
                std::swap(min, max);
            }
        }
    }
};

template <>
inline bool range_t<float_num_t>::min_limits() const noexcept {
    return min.value == std::numeric_limits<double>::min();
}

template <>
inline bool range_t<float_num_t>::max_limits() const noexcept {
    return max.value == std::numeric_limits<double>::max();
}

template <typename T>
range_t<T> make_range(T first, T last) noexcept {
    return range_t<T>(first, last);
}

//////////////////////////////////////////////////////////////////////////

template <typename T>
class Singleton {
  public:
    Singleton() {
        if (singleton_ != nullptr) {
            throw std::runtime_error("Singleton constructor should only be called once");
        }
        singleton_ = static_cast<T *>(this);
    }

    virtual ~Singleton() noexcept {
        singleton_ = nullptr;
    }

    DISABLE_COPY_AND_ASSIGN(Singleton)

    static T *instance() noexcept {
        return singleton_;
    }

  private:
    static T *singleton_;
};

template <typename T>
T *Singleton<T>::singleton_ = nullptr;

//////////////////////////////////////////////////////////////////////////

uint16_t make_word(uint8_t l, uint8_t h) noexcept;

uint8_t low_byte(uint16_t v) noexcept;

uint8_t high_byte(uint16_t v) noexcept;

uint32_t make_dword(uint16_t l, uint16_t h) noexcept;

uint16_t low_word(uint32_t v) noexcept;

uint16_t high_word(uint32_t v) noexcept;

uint64_t make_qword(uint32_t l, uint32_t h) noexcept;

uint32_t low_dword(uint64_t v) noexcept;

uint32_t high_dword(uint64_t v) noexcept;

//////////////////////////////////////////////////////////////////////////

void random_seed(unsigned int seed) noexcept;

int random_range_value(int min, int max) noexcept;

double random_float_value(unsigned int precision) noexcept;

//////////////////////////////////////////////////////////////////////////

class random_t {
  public:
    random_t(unsigned int seed = 0) noexcept;

    virtual ~random_t() noexcept;

  public:
    int range_value(int min, int max) noexcept;

    double float_value(unsigned int precision) noexcept;

  private:
    unsigned int seed_;
};

//////////////////////////////////////////////////////////////////////////

}  // namespace scl

//////////////////////////////////////////////////////////////////////////

// std::numeric_limits for scl::float_num_t

template <>
struct std::numeric_limits<scl::float_num_t> {
    static constexpr double min() noexcept {
        return std::numeric_limits<double>::min();
    }
    static constexpr double max() noexcept {
        return std::numeric_limits<double>::max();
    }
};

//////////////////////////////////////////////////////////////////////////

#endif  // !LIBSCL_UTILITY_H_

源文件:

cpp 复制代码
#include "utility.h"
#include <cmath>
#include <ctime>

//////////////////////////////////////////////////////////////////////////

namespace scl {

//////////////////////////////////////////////////////////////////////////

bool float_equal(double a, double b, double eps /*= 1e-9*/) noexcept {
    return std::abs(a - b) < eps;
}

bool float_greater(double a, double b, double eps /*= 1e-9*/) noexcept {
    return a - b > eps;
}

bool float_greater_equal(double a, double b, double eps /*= 1e-9*/) noexcept {
    return a - b > -eps;
}

bool float_less(double a, double b, double eps /*= 1e-9*/) noexcept {
    return b - a > eps;
}

bool float_less_equal(double a, double b, double eps /*= 1e-9*/) noexcept {
    return b - a > -eps;
}

double float_round_one(double a) noexcept {
    return std::round(a * 10.0) / 10.0;
}

double float_round_two(double a) noexcept {
    return std::round(a * 100.0) / 100.0;
}

double float_round_three(double a) noexcept {
    return std::round(a * 1'000.0) / 1'000.0;
}

double float_round_four(double a) noexcept {
    return std::round(a * 10'000.0) / 10'000.0;
}

double float_round_five(double a) noexcept {
    return std::round(a * 100'000.0) / 100'000.0;
}

double float_round_six(double a) noexcept {
    return std::round(a * 1'000'000.0) / 1'000'000.0;
}

double float_round(double a, int precision) noexcept {
    double m = std::pow(10.0, precision);
    return std::round(a * m) / m;
}

//////////////////////////////////////////////////////////////////////////

uint16_t make_word(uint8_t l, uint8_t h) noexcept {
    return static_cast<uint16_t>(l & 0xff) | static_cast<uint16_t>((h & 0xff) << 8);
}

uint8_t low_byte(uint16_t v) noexcept {
    return static_cast<uint8_t>(v & 0xff);
}

uint8_t high_byte(uint16_t v) noexcept {
    return static_cast<uint8_t>(v >> 8 & 0xff);
}

uint32_t make_dword(uint16_t l, uint16_t h) noexcept {
    return static_cast<uint32_t>(l & 0xffff) | static_cast<uint32_t>((h & 0xffff) << 16);
}

uint16_t low_word(uint32_t v) noexcept {
    return static_cast<uint16_t>(v & 0xffff);
}

uint16_t high_word(uint32_t v) noexcept {
    return static_cast<uint16_t>((v >> 16) & 0xffff);
}

uint64_t make_qword(uint32_t l, uint32_t h) noexcept {
    uint64_t v = 0;
    uint32_t *pv = reinterpret_cast<uint32_t *>(&v);
    pv[0] = l & 0xffffffff;
    pv[1] = h & 0xffffffff;
    return v;
}

uint32_t low_dword(uint64_t v) noexcept {
    uint32_t *pv = reinterpret_cast<uint32_t *>(&v);
    return static_cast<uint32_t>(pv[0] & 0xffffffff);
}

uint32_t high_dword(uint64_t v) noexcept {
    uint32_t *pv = reinterpret_cast<uint32_t *>(&v);
    return static_cast<uint32_t>(pv[1] & 0xffffffff);
}

//////////////////////////////////////////////////////////////////////////

void random_seed(unsigned int seed) noexcept {
    if (seed == 0) {
        seed = static_cast<unsigned int>((std::time(nullptr) << 16) * 1664525L + 1013904223L);
    }
    std::srand(seed);
}

int random_range_value(int min, int max) noexcept {
    double ratio = (std::rand() * 1.0) / (RAND_MAX + 1.0);

    if (min < max) {
        return static_cast<int>(ratio * (max - min + 1.0) + min);
    } else if (min > max) {
        return static_cast<int>(ratio * (min - max + 1.0) + max);
    } else {
        return min;
    }
}

double random_float_value(unsigned int precision) noexcept {
    if (precision == 0) {
        precision = RAND_MAX;
    }

    return (random_range_value(0, precision) * 1.0) / (precision + 1.0);
}

//////////////////////////////////////////////////////////////////////////

namespace {

int update_seed(unsigned int *seed) noexcept {
    *seed = *seed * 1103515245 + 12345;
    return ((unsigned)(*seed / 65536) % 32768);
}

}  // namespace

random_t::random_t(unsigned int seed /*= 0*/) noexcept {
    if (seed == 0) {
        seed = (unsigned int)((std::time(nullptr) << 16) * 1664525L + 1013904223L);
    }
    seed_ = seed;
}

random_t::~random_t() noexcept {
}

int random_t::range_value(int min, int max) noexcept {
    double ratio = (update_seed(&seed_) * 1.0) / (32767 + 1.0);

    if (min < max) {
        return static_cast<int>(ratio * (max - min + 1.0) + min);
    } else if (min > max) {
        return static_cast<int>(ratio * (min - max + 1.0) + max);
    } else {
        return min;
    }
}

double random_t::float_value(unsigned int precision) noexcept {
    if (precision == 0) {
        precision = 32767;
    }

    return (range_value(0, precision) * 1.0) / (precision + 1.0);
}

//////////////////////////////////////////////////////////////////////////

}  // namespace scl

//////////////////////////////////////////////////////////////////////////
相关推荐
Xの哲學2 小时前
Linux Miscdevice深度剖析:从原理到实战的完整指南
linux·服务器·算法·架构·边缘计算
郭涤生2 小时前
QT 架构笔记
java·数据库·系统架构
韩立学长2 小时前
基于Springboot流浪动物领养网站0kh2iyb4(程序、源码、数据库、调试部署方案及开发环境)系统界面展示及获取方式置于文档末尾,可供参考。
数据库·spring boot·后端
wordbaby3 小时前
Expo 进阶指南:赋予 TanStack Query “原生感知力” —— 深度解析 AppState 与 NetInfo
前端·react native
ZouZou老师3 小时前
C++设计模式之组合模式:以家具生产为例
c++·设计模式·组合模式
lang201509283 小时前
Sentinel核心机制:Context与EntranceNode解析
网络·sentinel
DBA小马哥3 小时前
Oracle迁移到金仓数据库:完整迁移步骤与兼容性优化实战
数据库·oracle·国产化平替
你们补药再卷啦3 小时前
ai(二)ubuntu22.04配置环境
linux·ubuntu
yong15858553433 小时前
2. Linux C++ muduo 库学习——原子变量操作头文件
linux·c++·学习