vs2019 c++20 语法规范 头文件 <ratio> 的源码阅读与注释,这是 STL 引入的分数类型,处理分数的存储,加减乘除,以及分数之间的大小比较等运算,本头文件的内容概览

(1) 本源文件不长,只有几百行(400行),还带有详细的注释。分数的概念出现在 STL 库里的时间单位里,而时间又会出现在 STL 库的线程互斥量的限时等待里。所以有必要学习下。以前没明白 ratio 是分数的意思,总结的不好。这是新的、完善的版本,并附上源文件:

// ratio standard header (core)

// Copyright (c) Microsoft Corporation.     
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

// ************ <ratio>  头文件 ************* 

#pragma once

#ifndef _RATIO_
#define _RATIO_

#include <yvals_core.h>

#if _STL_COMPILER_PREPROCESSOR

#include <cstdint>
#include <type_traits>

#pragma pack(push, _CRT_PACKING)
// 以下的结构体以及 union 将采用 8 字节对齐。入栈原来的对齐方式 _CRT_PACKING = 8

#pragma warning(push, _STL_WARNING_LEVEL)
//调整本源文件编译时候的警告级别,是较减少了警告。 _STL_WARNING_LEVEL = 3
// 0 不警告,4 全警告。并把原来的警告级别入栈

#pragma warning(disable : _STL_DISABLED_WARNINGS)
//#define  _STL_DISABLED_WARNINGS  4180 4412 4455 4494 4514 4574 ......
// 表示禁用这些警告,忽略这些警告 <yvals_core.h>

_STL_DISABLE_CLANG_WARNINGS
// 按字面意思,禁止 clang 警告,最后还有对应的 宏定义,_STL_RESTORE_CLANG_WARNINGS

#pragma push_macro("new")
#undef new
// 入栈系统之前的 new 的宏定义,并取消此宏定义。可能要自己定义内存管理方式

_STD_BEGIN
// #define _STD_BEGIN namespace std {  表示以下内容全部定义于  std  命名空间

//*******************************************************************************************

template <class _Ty, _Ty _Val> // 这是粘贴过来的已经简化的定义,该类型含有一个静态变量
struct integral_constant 
{
    static constexpr _Ty value = _Val;
    using type = integral_constant;
};

#define INT64_MAX        9223372036854775807i64
#define INTMAX_MAX       INT64_MAX
typedef long long   intmax_t;   // 这是头文件 ratio 啊

template <intmax_t _Val>       // computes sign of _Val 返回数据 _Val 的符号
struct _Sign_of : integral_constant<intmax_t, (_Val < 0 ? -1 : 1)> {};

template <intmax_t _Val>   // computes absolute value of _Val  计算整数的绝对值
struct _Abs : integral_constant<intmax_t, (_Val < 0 ? -_Val : _Val)> {};

//***********************************************************************************************

// computes _Ax * _Bx without overflow   不会溢出的乘法
template <intmax_t _Ax, intmax_t _Bx, bool _Sfinae = false,
    bool _Good = (   _Abs<_Ax>::value   <=   INTMAX_MAX / (_Bx == 0 ? 1 : _Abs<_Bx>::value)  ) >
struct _Safe_mult : integral_constant< intmax_t, _Ax * _Bx > {}; 

template <intmax_t _Ax, intmax_t _Bx, bool _Sfinae>  // _Ax * _Bx would overflow
struct _Safe_mult<_Ax, _Bx, _Sfinae, false>          // 静态断言只有条件为真时才继续编译
{   static_assert(_Sfinae, "integer arithmetic overflow"); };

//****************************************************************************************

// computes _Ax + _Bx without overflow  安全加法
template <intmax_t _Ax, intmax_t _Bx, bool _Good, bool _Also_good>
struct _Safe_addX : integral_constant<intmax_t, _Ax + _Bx> {}; 

template <intmax_t _Ax, intmax_t _Bx>  // _Ax + _Bx would overflow
struct _Safe_addX<_Ax, _Bx, false, false> 
{   static_assert(_Always_false<_Safe_addX>, "integer arithmetic overflow"); };

// computes _Ax + _Bx, forbids overflow  符号相反的数相加,肯定不会溢出
template <intmax_t _Ax, intmax_t _Bx>  
struct _Safe_add : _Safe_addX<_Ax, _Bx, _Sign_of<_Ax>::value != _Sign_of<_Bx>::value,
                       (_Abs<_Ax>::value <= INTMAX_MAX - _Abs<_Bx>::value) >::type {  };

//********************************************************************************************

// (1)当 _Ax 与 _Bx 都为正数时,选择此模板  。      这个求最大公约数的方法很巧妙!!!!!!
template <intmax_t _Ax, intmax_t _Bx>  // greatest common divisor 最大公约数
struct _GcdX : _GcdX<_Bx, _Ax % _Bx>::type {}; // computes GCD of _Ax and _Bx

// (2)计算 _Ax 与 0 的最大公约数,认为是 _Ax 本身 
template <intmax_t _Ax>
struct _GcdX<_Ax, 0> : integral_constant<intmax_t, _Ax> {}; // computes GCD of _Ax and 0

//-------------------------------------

// (a)先统一转换为正数,再求公约数 
template <intmax_t _Ax, intmax_t _Bx>
struct _Gcd : _GcdX<_Abs<_Ax>::value, _Abs<_Bx>::value>::type {}; // computes GCD of abs(_Ax) and abs(_Bx)

// (b)0 与 0 的最大公约数,认为是 1
template <> // contrary to mathematical convention; avoids division by 0 in ratio_less
struct _Gcd<0, 0> : integral_constant<intmax_t, 1> { };  // 与数学惯例相反,避免除以 0

//**************************************************************************************************

template <intmax_t _Nx, intmax_t _Dx = 1>  // 有了这俩单词的意思,就好记忆这个类的意思了
struct ratio    // holds the ratio of _Nx to _Dx
{
    static_assert(_Dx != 0, "zero denominator"); // 静态断言的条件必须为真
    static_assert(-INTMAX_MAX <= _Nx, "numerator too negative");  // numerator 分子,被除数
    static_assert(-INTMAX_MAX <= _Dx, "denominator too negative"); // denominator 分母

    static constexpr intmax_t num =  //= 符号(N) * 符号(D) * abs(N) / 最大公约数
        _Sign_of<_Nx>::value * _Sign_of<_Dx>::value * _Abs<_Nx>::value / _Gcd<_Nx, _Dx>::value;

    static constexpr intmax_t den = _Abs<_Dx>::value / _Gcd<_Nx, _Dx>::value; //= abs(N) / 最大公约数

    using type = ratio<num, den>; // 这个 type 保存了简化版的比率
};

template <class _Ty>                // 模板的泛型与特化
constexpr bool _Is_ratio_v = false; // test for ratio type

template <intmax_t _Rx1, intmax_t _Rx2> // 意思是只有 ratio< N,D > 才为真
constexpr bool _Is_ratio_v< ratio<_Rx1, _Rx2> > = true;

//***************************************************************************************

// a/b + c/d = (ad + bc)/ bd  就是这么个意思
// a   c     ad + bc
// - + - =  ---------
// b   d       bd
template <class _Rx1, class _Rx2>   // add two ratios  分数加法
struct _Ratio_add       // 静态断言要求两个模板参数都是 ratio 分数类型,才可以进行分数加法
{ 
    static_assert(_Is_ratio_v<_Rx1> && _Is_ratio_v<_Rx2>, "ratio_add<R1, R2> requires R1 and R2 to be ratio<>s.");

    static constexpr intmax_t _Nx1 = _Rx1::num;
    static constexpr intmax_t _Dx1 = _Rx1::den;
    static constexpr intmax_t _Nx2 = _Rx2::num;
    static constexpr intmax_t _Dx2 = _Rx2::den;

    static constexpr intmax_t _Gx = _Gcd<_Dx1, _Dx2>::value;

    // typename ratio<>::type is necessary here
    using type = typename ratio< 
        _Safe_add< _Safe_mult<_Nx1, _Dx2 / _Gx>::value, _Safe_mult<_Nx2, _Dx1 / _Gx>::value>::value,
            _Safe_mult<_Dx1, _Dx2 / _Gx>::value
                                  >::type;
};

template <class _Rx1, class _Rx2>
using ratio_add = typename _Ratio_add<_Rx1, _Rx2>::type;

//*************************************************************************************

// 分数减法看成是分数加法的进化版
template <class _Rx1, class _Rx2> // subtract two ratios 分数减法
struct _Ratio_subtract
{ 
    static_assert(_Is_ratio_v<_Rx1> && _Is_ratio_v<_Rx2>, "ratio_subtract<R1, R2> requires R1 and R2 to be ratio<>s.");

    static constexpr intmax_t _Nx2 = _Rx2::num;
    static constexpr intmax_t _Dx2 = _Rx2::den;

    using type = ratio_add<  _Rx1, ratio< -_Nx2, _Dx2 >   >; // 注意多了一个 负号
};

template <class _Rx1, class _Rx2>
using ratio_subtract = typename _Ratio_subtract<_Rx1, _Rx2>::type;

//*************************************************************************************************

// a/b * c/d =  ac / bd  就是这么个意思
// a   c       ac
// - * - =  ---------
// b   d       bd
template <class _Rx1, class _Rx2>  // multiply two ratios  分数乘法
struct _Ratio_multiply 
{ 
    static_assert(_Is_ratio_v<_Rx1> && _Is_ratio_v<_Rx2>, "ratio_multiply<R1, R2> requires R1 and R2 to be ratio<>s.");

    static constexpr intmax_t _Nx1 = _Rx1::num;
    static constexpr intmax_t _Dx1 = _Rx1::den;
    static constexpr intmax_t _Nx2 = _Rx2::num;
    static constexpr intmax_t _Dx2 = _Rx2::den;

    static constexpr intmax_t _Gx = _Gcd<_Nx1, _Dx2>::value;  // 假设是四个质数,最大公约数为 1 ,
    static constexpr intmax_t _Gy = _Gcd<_Nx2, _Dx1>::value;  // 这样的计算情形最简单

    using _Num = _Safe_mult<_Nx1 / _Gx, _Nx2 / _Gy, true>;
    using _Den = _Safe_mult<_Dx1 / _Gy, _Dx2 / _Gx, true>;
};

template <class _Rx1, class _Rx2, bool _Sfinae = true, class = void>  // 模板的泛化特化
struct _Ratio_multiply_sfinae    // detect overflow during multiplication
{
    static_assert(_Sfinae, "integer arithmetic overflow");
};

template <class _Rx1, class _Rx2, bool _Sfinae> // typename ratio<>::type is unnecessary here
struct _Ratio_multiply_sfinae<_Rx1, _Rx2, _Sfinae,
    void_t< typename _Ratio_multiply<_Rx1, _Rx2>::_Num::type, typename _Ratio_multiply<_Rx1, _Rx2>::_Den::type > > 
{ 
    using type = ratio<_Ratio_multiply<_Rx1, _Rx2>::_Num::value, _Ratio_multiply<_Rx1, _Rx2>::_Den::value>;
};

template <class _Rx1, class _Rx2>
using ratio_multiply = typename _Ratio_multiply_sfinae<_Rx1, _Rx2, false>::type;

//***************************************************************************************

// a / b = a * 1/b   由乘法来实现除法运算
template <class _Rx1, class _Rx2>  // divide two ratios 分数的除法
struct _Ratio_divide 
{ 
    static_assert(_Is_ratio_v<_Rx1> && _Is_ratio_v<_Rx2>, "ratio_divide<R1, R2> requires R1 and R2 to be ratio<>s.");

    static constexpr intmax_t _Nx2 = _Rx2::num;
    static constexpr intmax_t _Dx2 = _Rx2::den;

    using _Rx2_inverse = ratio<_Dx2, _Nx2>;  // 颠倒了分子与分母
};

template <class _Rx1, class _Rx2, bool _Sfinae = true>
using _Ratio_divide_sfinae = 
    typename _Ratio_multiply_sfinae<_Rx1, typename _Ratio_divide<_Rx1, _Rx2>::_Rx2_inverse, _Sfinae>::type;

template <class _Rx1, class _Rx2>
using ratio_divide = _Ratio_divide_sfinae<_Rx1, _Rx2, false>;

//******************************************************************************************************

template <class _Ty, _Ty _Val>
struct integral_constant   // 简化版的定义
{
    static constexpr _Ty value = _Val;
    using value_type = _Ty;
    using type = integral_constant;
};

template <bool _Val>
using bool_constant = integral_constant<bool, _Val>;

using true_type = bool_constant<true>;
using false_type = bool_constant<false>;

// 分数相等的含义是分子和分母都要相等,因为数据已经最简化了,全是质数。
template <class _Rx1, class _Rx2>  // tests if ratio == ratio 测试两个分数是否相等
struct ratio_equal : bool_constant<_Rx1::num == _Rx2::num && _Rx1::den == _Rx2::den> 
{ 
    static_assert(_Is_ratio_v<_Rx1> && _Is_ratio_v<_Rx2>, "ratio_equal<R1, R2> requires R1 and R2 to be ratio<>s.");
};

template <class _Rx1, class _Rx2>
constexpr bool ratio_equal_v = ratio_equal<_Rx1, _Rx2>::value;

template <class _Rx1, class _Rx2>   // tests if ratio != ratio 测试分数是否不等
struct ratio_not_equal : bool_constant<!ratio_equal_v<_Rx1, _Rx2>>
{ 
    static_assert(_Is_ratio_v<_Rx1> && _Is_ratio_v<_Rx2>, "ratio_not_equal<R1, R2> requires R1 and R2 to be ratio<>s.");
};

template <class _Rx1, class _Rx2>
constexpr bool ratio_not_equal_v = ratio_not_equal<_Rx1, _Rx2>::value;

//****************************************************************************************************

// 以下内容继续实现了小数的比较运算 :  <   <=    >   >=  这四种运算

struct _Big_uint128   // 这些内容是为小数的  小于 <  比较的 ,保留,不再细看
{
    uint64_t _Upper;
    uint64_t _Lower;

    constexpr bool operator<(const _Big_uint128 _Rhs) const noexcept {
        if (_Upper != _Rhs._Upper) {
            return _Upper < _Rhs._Upper;
        }

        return _Lower < _Rhs._Lower;
    }
};

// multiply two 64-bit integers into a 128-bit integer, Knuth's algorithm M 
// 将 64 bit 的数相乘保存在 128 bit 里
constexpr _Big_uint128 _Big_multiply(const uint64_t _Lfactor, const uint64_t _Rfactor) noexcept
{  
    const uint64_t _Llow  = _Lfactor & 0xFFFF'FFFFULL;
    const uint64_t _Lhigh = _Lfactor >> 32;
    const uint64_t _Rlow  = _Rfactor & 0xFFFF'FFFFULL;
    const uint64_t _Rhigh = _Rfactor >> 32;

    uint64_t _Temp          = _Llow * _Rlow;
    const uint64_t _Lower32 = _Temp & 0xFFFF'FFFFULL;
    uint64_t _Carry         = _Temp >> 32;

    _Temp                     = _Llow * _Rhigh + _Carry;
    const uint64_t _Mid_lower = _Temp & 0xFFFF'FFFFULL;
    const uint64_t _Mid_upper = _Temp >> 32;

    _Temp  = _Lhigh * _Rlow + _Mid_lower;
    _Carry = _Temp >> 32;

    return {_Lhigh * _Rhigh + _Mid_upper + _Carry, (_Temp << 32) + _Lower32};
}


// 意思就是  a/b < c/d   等价于  ad < bc
// a   c     
// - < -  ==  ad < bc
// b   d      
constexpr bool _Ratio_less(const int64_t _Nx1, const int64_t _Dx1, const int64_t _Nx2, const int64_t _Dx2) noexcept 
{
    if (_Nx1 >= 0 && _Nx2 >= 0) {
        return _Big_multiply(static_cast<uint64_t>(_Nx1), static_cast<uint64_t>(_Dx2))
             < _Big_multiply(static_cast<uint64_t>(_Nx2), static_cast<uint64_t>(_Dx1));
    }

    if (_Nx1 < 0 && _Nx2 < 0) {
        return _Big_multiply(static_cast<uint64_t>(-_Nx2), static_cast<uint64_t>(_Dx1))
             < _Big_multiply(static_cast<uint64_t>(-_Nx1), static_cast<uint64_t>(_Dx2));
    }

    return _Nx1 < _Nx2;
}

template <class _Rx1, class _Rx2>   // tests if ratio < ratio  分数比大小  <
struct ratio_less : bool_constant<_Ratio_less(_Rx1::num, _Rx1::den, _Rx2::num, _Rx2::den)>
{ 
    static_assert(_Is_ratio_v<_Rx1> && _Is_ratio_v<_Rx2>, 
        "ratio_less<R1, R2> requires R1 and R2 to be ratio<>s.");
};

template <class _Rx1, class _Rx2>
constexpr bool ratio_less_v = ratio_less<_Rx1, _Rx2>::value;

// a <= b  等价于 !(b < a)   借助上面定义的 小于运算来完成  <= 的运算
template <class _Rx1, class _Rx2>  // tests if ratio <= ratio  分数比大小 <= 
struct ratio_less_equal : bool_constant< !ratio_less_v<_Rx2, _Rx1> > 
{ 
    static_assert( _Is_ratio_v<_Rx1> && _Is_ratio_v<_Rx2>, 
        "ratio_less_equal<R1, R2> requires R1 and R2 to be ratio<>s.");
};

template <class _Rx1, class _Rx2>
constexpr bool ratio_less_equal_v = ratio_less_equal<_Rx1, _Rx2>::value;

// a > b  等价于 b < a  ,借助 已经定义的小于运算来完成 > 大于符号 的定义
template <class _Rx1, class _Rx2>   // tests if ratio > ratio   实现小数的大于运算
struct ratio_greater : ratio_less<_Rx2, _Rx1>::type
{ 
    static_assert(_Is_ratio_v<_Rx1> && _Is_ratio_v<_Rx2>, 
        "ratio_greater<R1, R2> requires R1 and R2 to be ratio<>s.");
};

template <class _Rx1, class _Rx2>
constexpr bool ratio_greater_v = ratio_greater<_Rx1, _Rx2>::value;

// a >= b  等价于 !(a < b)
template <class _Rx1, class _Rx2>    // tests if ratio >= ratio  实现小数的大于等于 >= 运算
struct ratio_greater_equal : bool_constant<  !ratio_less_v<_Rx1, _Rx2>  >
{
    static_assert( _Is_ratio_v<_Rx1> && _Is_ratio_v<_Rx2>,
        "ratio_greater_equal<R1, R2> requires R1 and R2 to be ratio<>s.");
};

template <class _Rx1, class _Rx2>
constexpr bool ratio_greater_equal_v = ratio_greater_equal<_Rx1, _Rx2>::value;

//*********************************************************************************************

// 一些常用的单位,直接定义简写了
using atto  = ratio<1, 1000000000000000000LL>;
using femto = ratio<1, 1000000000000000LL>;
using pico  = ratio<1, 1000000000000LL>;
using nano  = ratio<1, 1000000000>;
using micro = ratio<1, 1000000>;
using milli = ratio<1, 1000>;     // 毫米
using centi = ratio<1, 100>;      // 厘米
using deci  = ratio<1, 10>;       // 分米   decimetre
using deca  = ratio<10, 1>;       // 十倍   decade
using hecto = ratio<100, 1>;      // 百倍   hundred 百
using kilo  = ratio<1000, 1>;     // 千米
using mega  = ratio<1000000, 1>;
using giga  = ratio<1000000000, 1>;
using tera  = ratio<1000000000000LL, 1>;
using peta  = ratio<1000000000000000LL, 1>;
using exa   = ratio<1000000000000000000LL, 1>;

//******************************************************************************************************

_STD_END
// #define _STD_END   } ,在 std  命名空间里的操作结束

#pragma pop_macro("new") 
// 恢复最开始隐藏的 new 宏定义,#pragma push_macro("new")

_STL_RESTORE_CLANG_WARNINGS
// 对应最开始的,此处是恢复 clang 警告

#pragma warning(pop)
// 恢复原来的警告级别  #pragma warning(push, _STL_WARNING_LEVEL)

#pragma pack(pop)
// 恢复原来的内存对齐方式  #pragma pack(push, _CRT_PACKING) 

#endif // _STL_COMPILER_PREPROCESSOR,本文件在此 #if 成立时才存在

#endif // _RATIO_

(2) 本 头文件的 内容概览,因为内容太多了,阅读源码也不直观,还是直接看结论,更安逸一些:

在这里插入图片描述

(3)

谢谢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值