Files
DX12/Engine/Utilities/Math.h
2026-03-19 18:27:49 +08:00

186 lines
4.5 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @file Math.h
* @brief 数学工具函数与二进制对齐辅助函数。
* @details
* 提供模板化的数值打包/解包与内存对齐能力,包括:
* - clamp 与归一化浮点量化打包;
* - 固定/动态对齐粒度下的向上与向下对齐;
* - 基于 SIMD 指令的 CRC32 快速计算辅助。
*/
#pragma once
#include "CommonHeader.h"
#include "MathTypes.h"
namespace XEngine::math {
/**
* @brief 将值限制在给定区间内。
* @tparam T 标量类型。
* @param value 输入值。
* @param min 下界。
* @param max 上界。
* @return 限制后的值。
*/
template<typename T>
[[nodiscard]] constexpr T
clamp(T value, T min, T max)
{
return (value < min) ? min : (value > max) ? max : value;
}
/**
* @brief 将 [0,1] 浮点值量化到指定位宽的无符号整数。
* @tparam bits 量化位宽。
* @param i 归一化输入值。
* @return 量化结果。
*/
template<u32 bits>
[[nodiscard]] constexpr u32
pack_unit_float(f32 i)
{
static_assert(bits <= sizeof(u32) * 8);
assert(i >= 0.f && i <= 1.f);
constexpr f32 intervals{ (f32)(((u32)1 << bits) - 1) };
return (u32)(intervals * i + 0.5f);
}
/**
* @brief 将 [min,max] 浮点值量化到指定位宽。
* @tparam bits 量化位宽。
* @param i 输入值。
* @param min 下界。
* @param max 上界。
* @return 量化结果。
*/
template<u32 bits>
[[nodiscard]] constexpr u32
pack_float(f32 i, f32 min, f32 max)
{
assert(min < max);
assert(i <= max && i >= min);
const f32 distance{ (i - min) / (max - min) };
return pack_unit_float<bits>(distance);
}
/**
* @brief 将量化整数还原为 [0,1] 浮点值。
* @tparam bits 量化位宽。
* @param i 量化输入值。
* @return 反量化结果。
*/
template<u32 bits>
[[nodiscard]] constexpr f32
unpack_unit_float(u32 i)
{
static_assert(bits <= sizeof(u32) * 8);
assert(i < ((u32)i << bits));
constexpr f32 intervals{ (f32)(((u32)1 << bits) - 1) };
return (f32)i / intervals;
}
/**
* @brief 将量化值还原到 [min,max] 区间。
* @tparam bits 量化位宽。
* @param i 量化输入值。
* @param min 下界。
* @param max 上界。
* @return 反量化结果。
*/
template<u32 bits>
[[nodiscard]] constexpr f32
unpack_float(f32 i, f32 min, f32 max)
{
assert(min < max);
return unpack_unit_float<bits>(i) * (max - min) + min;
}
/**
* @brief 按固定对齐值向上对齐。
* @tparam alignment 对齐粒度2 的幂)。
* @param size 原始大小。
* @return 向上对齐后的大小。
*/
template<u64 alignment>
[[nodiscard]] constexpr u64
align_size_up(u64 size)
{
static_assert(alignment, "Alignment must be non-zero.");
constexpr u64 mask{ alignment - 1 };
static_assert(!(alignment & mask), "Alignment should be a power of 2.");
return ((size + mask) & ~mask);
}
/**
* @brief 按固定对齐值向下对齐。
* @tparam alignment 对齐粒度2 的幂)。
* @param size 原始大小。
* @return 向下对齐后的大小。
*/
template<u64 alignment>
[[nodiscard]] constexpr u64
align_size_down(u64 size)
{
static_assert(alignment, "Alignment must be non-zero.");
constexpr u64 mask{ alignment - 1 };
static_assert(!(alignment & mask), "Alignment should be a power of 2.");
return (size & ~mask);
}
/**
* @brief 按运行时对齐值向上对齐。
* @param size 原始大小。
* @param alignment 对齐粒度2 的幂)。
* @return 向上对齐后的大小。
*/
[[nodiscard]] constexpr u64
align_size_up(u64 size, u64 alignment)
{
assert(alignment && "Alignment must be non-zero.");
const u64 mask{ alignment - 1 };
assert(!(alignment & mask) && "Alignment should be a power of 2.");
return ((size + mask) & ~mask);
}
/**
* @brief 按运行时对齐值向下对齐。
* @param size 原始大小。
* @param alignment 对齐粒度2 的幂)。
* @return 向下对齐后的大小。
*/
[[nodiscard]] constexpr u64
align_size_down(u64 size, u64 alignment)
{
assert(alignment && "Alignment must be non-zero.");
const u64 mask{ alignment - 1 };
assert(!(alignment & mask) && "Alignment should be a power of 2.");
return (size & ~mask);
}
/**
* @brief 计算数据块的 64 位 CRC32 累积值。
* @param data 输入字节流。
* @param size 输入长度。
* @return CRC32 累积结果。
*/
[[nodiscard]] constexpr u64
calcect_crc32_u64(const u8 *const data, u64 size)
{
assert(size >= sizeof(u64));
u64 crc{ 0 };
const u8* at{ data };
const u8 *const end{ data + align_size_down<sizeof(u64)>(size) };
while (at < end)
{
crc = _mm_crc32_u64(crc, *((const u64*)at));
at += sizeof(u64);
}
return crc;
}
}