(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)
谢谢