/*---------------------------------------------------------------------------* Project: Horizon File: math_Arithmetic.h Copyright (C)2009-2010 Nintendo Co., Ltd. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Revision: 27154 $ *---------------------------------------------------------------------------*/ #ifndef NN_MATH_ARITHMETIC_H_ #define NN_MATH_ARITHMETIC_H_ #include #include #include #include #include #pragma push #pragma Otime namespace nn { namespace math { /* ======================================================================= 浮動少数に関する数学関数 ======================================================================== */ /*! @name 浮動小数に関する数学関数 @{ */ // u32 F32AsU32(f32 x) // // 説明: f32 型の値をビット列を変更することなく u32 型にします // 引数: x: u32型 にする値。 // 返値: x と等しいビット表現を持つ u32 型の値。 inline u32 F32AsU32(f32 x) { return *reinterpret_cast(&x); } /*!--------------------------------------------------------------------------* @brief u32 型の値をビット列を変更することなく f32 型にします @param[in] x f32型にする値。 @return x と等しいビット表現を持つ f32 型の値。 *---------------------------------------------------------------------------*/ inline f32 U32AsF32(u32 x) { return *reinterpret_cast(&x); } /*!--------------------------------------------------------------------------* @brief 浮動小数点数の指数部を取得します。 @param[in] f 指数部を取得する数。 @return f の指数部を返します。ただし負の値はオフセット表現ではなく 2 の補数表現です。 *---------------------------------------------------------------------------*/ inline s32 FGetExpPart(f32 f) { s32 s = static_cast((F32AsU32(f) >> 23) & 0xFF); return s - 127; } /*!--------------------------------------------------------------------------* @brief 浮動小数点数の仮数部を求めます。 @param[in] f 仮数部を取得する数。 @return f の仮数部を返します。返り値は f と同じ符号を持っています。 *---------------------------------------------------------------------------*/ inline f32 FGetMantPart(f32 f) { // 指数部を 127 にする u32 u = (F32AsU32(f) & 0x807FFFFF) | 0x3F800000; return U32AsF32(u); } /*!--------------------------------------------------------------------------* @brief 数の正負に応じて値を選択します。 @param[in] cond 返り値を選択する条件。 @param[in] ifPos cond が0以上の場合の返り値。 @param[in] ifNeg cond が負の場合の返り値。 @return cond が 0 以上であれば ifPos を、そうでなければ ifNeg を返します。 *---------------------------------------------------------------------------*/ inline f32 FSelect(f32 cond, f32 ifPos, f32 ifNeg) { f32 ret; ret = (cond >= 0) ? ifPos: ifNeg; return ret; } /*!--------------------------------------------------------------------------* @brief 絶対値を求めます @param[in] x 絶対値を求める値 @return x の絶対値を返します *---------------------------------------------------------------------------*/ inline f32 FAbs(f32 x) { f32 ret; ret = ::std::fabsf(x); return ret; } /*!--------------------------------------------------------------------------* @brief 絶対値が等しく、符号が負である数を求めます @param[in] x 元の数。 @return x と絶対値が等しく、符号が負である数を返します *---------------------------------------------------------------------------*/ inline f32 FNAbs(f32 x) { f32 ret; ret = - FAbs(x); return ret; } /*!--------------------------------------------------------------------------* @brief 一方の数の符号を他方の数にコピーします @param[in] abs 絶対値の元となる数。 @param[in] sign 符号を採用する数。 @return abs の絶対値と sign の符号を持った数を返します。 *---------------------------------------------------------------------------*/ inline f32 FCopySign(f32 abs, f32 sign) { f32 pos = FAbs(abs); f32 neg = FNAbs(abs); return FSelect(sign, pos, neg); } namespace internal { f32 FExp(f32 x); f32 FLog(f32 x); } /*!--------------------------------------------------------------------------* @brief e^x を求めます @param[in] x 指数の値 @return e^x を返します *---------------------------------------------------------------------------*/ inline f32 FExp(f32 x) { return ::std::expf(x); } /*!--------------------------------------------------------------------------* @brief 自然対数を求めます @param[in] x 自然対数を求める値 @return x の自然対数を返します *---------------------------------------------------------------------------*/ inline f32 FLog(f32 x) { NN_MATH_WARNING(x > 0, "FLog: Input is out of the domain."); return ::std::logf(x); } /*!--------------------------------------------------------------------------* @brief 常用対数を求めます @param[in] x 常用対数を求める値 @return x の常用対数を返します *---------------------------------------------------------------------------*/ inline f32 FLog10(f32 x) { NN_MATH_WARNING(x > 0, "FLog10: Input is out of the domain."); return ::std::log10f(x); } /*!--------------------------------------------------------------------------* @brief 剰余を計算します @param[in] x 割られる数 @param[in] y 割る数 @return x / y の剰余を返します *---------------------------------------------------------------------------*/ inline f32 FMod(f32 x, f32 y) { return ::std::fmodf(x, y); } /*!--------------------------------------------------------------------------* @brief 浮動小数点数を整数部と小数部に分けます。整数部、小数部共に x と同じ符号を持ちます。 @param[in] x 元の浮動小数点数。 @param[out] y 整数部を格納するバッファへのポインタ。 @return 小数部を返します *---------------------------------------------------------------------------*/ inline f32 FModf(f32 x, f32* y) { return ::std::modff(x, y); } /*!--------------------------------------------------------------------------* @brief x を下回らない最小の整数値を求めます @param[in] x 対象の値 @return x を下回らない最小の整数値を返します *---------------------------------------------------------------------------*/ inline f32 FCeil(f32 x) { return ::std::ceilf(x); } /*!--------------------------------------------------------------------------* @brief x を超えない最大の整数値を求めます @param[in] x 対象の値 @return x を超えない最大の整数値を返します *---------------------------------------------------------------------------*/ inline f32 FFloor(f32 x) { return ::std::floorf(x); } /*!--------------------------------------------------------------------------* @brief f32型からs16型に変換します @param[in] x s16型に変換する値 @return x と同じ値を持ったs16型の値を返します *---------------------------------------------------------------------------*/ inline s16 F32ToS16(f32 x) { return s16(x); } /*!--------------------------------------------------------------------------* @brief f32型からu16型に変換します @param[in] x u16型に変換する値 @return x と同じ値を持ったu16型の値を返します *---------------------------------------------------------------------------*/ inline u16 F32ToU16(f32 x) { return u16(x); } /*!--------------------------------------------------------------------------* @brief u16型からf32型に変換します @param[in] x f32型に変換する値 @return x と同じ値を持ったf32型の値を返します *---------------------------------------------------------------------------*/ inline f32 U16ToF32(u16 x) { return f32(x); } /*!--------------------------------------------------------------------------* @brief s16型からf32型に変換します @param[in] x f32型に変換する値 @return x と同じ値を持ったf32型の値を返します *---------------------------------------------------------------------------*/ inline f32 S16ToF32(s16 x) { return f32(x); } /*!--------------------------------------------------------------------------* @brief 逆数を高速低精度に求めます @param[in] x 逆数を求める値 @return x の逆数を返します *---------------------------------------------------------------------------*/ inline f32 FInv(f32 x) { f32 ix; ix = 1.0f / x; return ix; } /*!--------------------------------------------------------------------------* @brief 平方根の逆数を求めます。 @param[in] x 平方根の逆数を求める値。 @return x の平方根の逆数を返します。 *---------------------------------------------------------------------------*/ inline f32 FrSqrt(f32 x) { NN_MATH_WARNING(x > 0, "FrSqrt: Input is out of the domain."); return 1.f / ::std::sqrtf(x); } /*!--------------------------------------------------------------------------* @brief 平方根を求めます @param[in] x 平方根を求める値 @return x の平方根を返します *---------------------------------------------------------------------------*/ inline f32 FSqrt(f32 x) { NN_MATH_WARNING(x >= 0, "FSqrt: Input is out of the domain."); return ::std::sqrtf(x); } /*!--------------------------------------------------------------------------* @brief 立方根を求めます @param[in] x 立方根を求める値 @return x の立方根を返します *---------------------------------------------------------------------------*/ inline f32 FCbrt(f32 x) { #if defined(NN_CW3) return ::std::cbrtf(x); #else return ::std::pow(x, 1/3.f); #endif } /*!--------------------------------------------------------------------------* @brief エルミート補間を行います @param[in] v0 点1での値。 @param[in] t0 点1での傾き。 @param[in] v1 点2での値。 @param[in] t1 点2での傾き。 @param[in] s 補間対象位置。(点1:0.0~1.0:点2) @return 補間結果の値。 *---------------------------------------------------------------------------*/ inline f32 Hermite(f32 v0, f32 t0, f32 v1, f32 t1, f32 s) { #if defined( NN_HARDWARE_CTR ) #if (HERMITE_5_CONFIG == D_ORG) return ARMv6::HermiteC(v0, t0, v1, t1, s); #elif (HERMITE_5_CONFIG == D_FAST_C) return ARMv6::HermiteC_FAST(v0, t0, v1, t1, s); #elif (HERMITE_5_CONFIG == D_FAST_ASM) #elif (HERMITE_5_CONFIG == D_FAST_C_ALGO) #elif (HERMITE_5_CONFIG == D_FAST_ASM_ALGO) #endif #else #endif } /*!--------------------------------------------------------------------------* @brief エルミート補間計算です。 @param[in] v0 点1での値。 @param[in] t0 点1での傾き。 @param[in] v1 点2での値。 @param[in] t1 点2での傾き。 @param[in] p 点1から補間対象位置の距離。 @param[in] d 点1と点2の距離。 @return エルミート補間の結果です。 *---------------------------------------------------------------------------*/ NN_FORCE_INLINE f32 Hermite(f32 v0, f32 t0, f32 v1, f32 t1, f32 p, f32 d) { #if defined( NN_HARDWARE_CTR ) #if (HERMITE_6_CONFIG == D_ORG) return ARMv6::HermiteC(v0, t0, v1, t1, p, d); #elif (HERMITE_6_CONFIG == D_FAST_C) return ARMv6::HermiteC_FAST(v0, t0, v1, t1, p, d); #elif (HERMITE_6_CONFIG == D_FAST_ASM) return ARMv6::HermiteAsm(v0, t0, v1, t1, p, d); #elif (HERMITE_6_CONFIG == D_FAST_C_ALGO) #elif (HERMITE_6_CONFIG == D_FAST_ASM_ALGO) #endif #else #endif } f32 Bezier(f32 p1, f32 p2, f32 p3, f32 p4, f32 s); f32 CatmullRom(f32 p0, f32 p1, f32 p2, f32 p3, f32 s); /*! @} */ /* ======================================================================= 整数関連 ======================================================================== */ /*! @name 整数に関する数学関数 @{ */ // 非インライン関数 u32 CntBit1(u32 x); u32 CntBit1(const u32* first, const u32* last); u32 DistBit(const u32* first1, const u32* last1, const u32* first2); u32 RevBit(u32 x); int IExp(int x, u32 n); u32 ILog10(u32 x); #ifndef NN_PROCESSOR_ARM namespace internal { u32 CntLz_(u32 x); } #endif /*!--------------------------------------------------------------------------* @brief MSBからの連続する 0 のビットを数えます。 @param[in] x 対象のビット列 @return MSBからの連続する 0 のビット数を返します。 *---------------------------------------------------------------------------*/ inline u32 CntLz(u32 x) { #ifdef NN_PROCESSOR_ARM return __clz(x); #else return internal::CntLz_(x); #endif } /*!--------------------------------------------------------------------------* @brief 整数値が2の整数乗かどうかを判定します。 @param[in] x 判定対象の整数値 @return x が 2 の累乗であれば true を、そうでなければ false を返します。 *---------------------------------------------------------------------------*/ // ただし x が 0 の場合は true を返します。 inline bool IsPwr2(int x) { return 0 == (x & (x - 1)); } /*!--------------------------------------------------------------------------* @brief 1 になっているビットで一番右(LSB側)のビットを取得します。 @param[in] x 対象とするビット列 @return x で一番右の 1 となっているビット位置のみが 1 となっているビット列を返します。 *---------------------------------------------------------------------------*/ inline int Rightmost1(int x) { return x & (-x); } inline bit32 Rightmost1(bit32 x) { return x & (-x); } inline bit64 Rightmost1(bit64 x) { return x & (-x); } /*!--------------------------------------------------------------------------* @brief 0 になっているビットで一番右(LSB側)のビットを取得します。 @param[in] x 対象とするビット列 @return x で一番右の 0 となっているビット位置のみが 1 となっているビット列を返します。 *---------------------------------------------------------------------------*/ inline int Rightmost0(int x) { return ~x & (x + 1); } inline bit32 Rightmost0(bit32 x) { return ~x & (x + 1); } inline bit64 Rightmost0(bit64 x) { return ~x & (x + 1); } /*!--------------------------------------------------------------------------* @brief ビット列同士の距離を計算します。 @param[in] x ビット列 1 @param[in] y ビット列 2 @return ビット列 1 とビット列 2 の距離を返します。 *---------------------------------------------------------------------------*/ inline u32 DistBit(u32 x, u32 y) { return CntBit1(x ^ y); } /*!--------------------------------------------------------------------------* @brief LSBからの連続する 0 のビットを数えます。 @param[in] x 対象のビット列 @return LSBからの連続する 0 のビット数を返します。 *---------------------------------------------------------------------------*/ inline u32 CntTz(u32 x) { return 32 - CntLz(~x & (x - 1)); } /*!--------------------------------------------------------------------------* @brief 整数の 2 を底とする対数を計算し、結果を整数で返します。 @param[in] x 真数 @return 整数の 2 を底とする対数を整数で返します。 *---------------------------------------------------------------------------*/ inline u32 ILog2(u32 x) { return 31 - CntLz(x); } /*!--------------------------------------------------------------------------* @brief 与えられた整数以下の最大の 2 の累乗を計算します。 @param[in] x 対象の整数 @return x 以下の最大の2の累乗を返します。 *---------------------------------------------------------------------------*/ inline u32 FloorPwr2(u32 x) { return 0x80000000 >> CntLz(x); } /*!--------------------------------------------------------------------------* @brief 与えられた整数以上の最小の 2 の累乗を計算します。 @param[in] x 対象の整数 @return x 以上の最小の 2 の累乗を返します。 *---------------------------------------------------------------------------*/ inline u32 CeilPwr2(u32 x) { return 0x80000000 >> (CntLz(x - 1) - 1); } /*! @} */ }} // nn::math #pragma pop /* NN_MATH_ARITHMETIC_H_ */ #endif