1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     math_Arithmetic.h
4 
5   Copyright (C)2009-2010 Nintendo Co., Ltd.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law.  They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Revision: 27154 $
14  *---------------------------------------------------------------------------*/
15 
16 #ifndef NN_MATH_ARITHMETIC_H_
17 #define NN_MATH_ARITHMETIC_H_
18 
19 #include <nn/assert.h>
20 #include <nn/math/math_Config.h>
21 #include <nn/math/math_Constant.h>
22 #include <nn/math/ARMv6/math_Arithmetic.h>
23 
24 #include <cmath>
25 
26 #pragma push
27 #pragma Otime
28 
29 namespace nn { namespace math {
30 
31 
32 
33 /* =======================================================================
34         浮動少数に関する数学関数
35    ======================================================================== */
36 
37 /*!
38     @name    浮動小数に関する数学関数
39     @{
40 */
41 
42 // u32 F32AsU32(f32 x)
43 //
44 // 説明: f32 型の値をビット列を変更することなく u32 型にします
45 // 引数: x: u32型 にする値。
46 // 返値: x と等しいビット表現を持つ u32 型の値。
47 inline u32
F32AsU32(f32 x)48 F32AsU32(f32 x)
49 {
50     return *reinterpret_cast<u32*>(&x);
51 }
52 
53 
54 
55 /*!--------------------------------------------------------------------------*
56   @brief        u32 型の値をビット列を変更することなく f32 型にします
57 
58   @param[in]    x  f32型にする値。
59 
60   @return       x と等しいビット表現を持つ f32 型の値。
61  *---------------------------------------------------------------------------*/
62 inline f32
U32AsF32(u32 x)63 U32AsF32(u32 x)
64 {
65     return *reinterpret_cast<f32*>(&x);
66 }
67 
68 
69 /*!--------------------------------------------------------------------------*
70   @brief        浮動小数点数の指数部を取得します。
71 
72   @param[in]    f   指数部を取得する数。
73 
74   @return       f の指数部を返します。ただし負の値はオフセット表現ではなく 2 の補数表現です。
75  *---------------------------------------------------------------------------*/
76 inline s32
FGetExpPart(f32 f)77 FGetExpPart(f32 f)
78 {
79     s32 s = static_cast<s32>((F32AsU32(f) >> 23) & 0xFF);
80     return s - 127;
81 }
82 
83 
84 /*!--------------------------------------------------------------------------*
85   @brief        浮動小数点数の仮数部を求めます。
86 
87   @param[in]    f   仮数部を取得する数。
88 
89   @return       f の仮数部を返します。返り値は f と同じ符号を持っています。
90  *---------------------------------------------------------------------------*/
91 inline f32
FGetMantPart(f32 f)92 FGetMantPart(f32 f)
93 {
94     // 指数部を 127 にする
95     u32 u = (F32AsU32(f) & 0x807FFFFF) | 0x3F800000;
96     return U32AsF32(u);
97 }
98 
99 
100 /*!--------------------------------------------------------------------------*
101   @brief        数の正負に応じて値を選択します。
102 
103   @param[in]    cond    返り値を選択する条件。
104   @param[in]    ifPos   cond が0以上の場合の返り値。
105   @param[in]    ifNeg   cond が負の場合の返り値。
106 
107   @return       cond が 0 以上であれば ifPos を、そうでなければ ifNeg を返します。
108  *---------------------------------------------------------------------------*/
109 inline f32
FSelect(f32 cond,f32 ifPos,f32 ifNeg)110 FSelect(f32 cond, f32 ifPos, f32 ifNeg)
111 {
112     f32 ret;
113 
114     ret = (cond >= 0) ? ifPos: ifNeg;
115 
116 
117     return ret;
118 }
119 
120 
121 /*!--------------------------------------------------------------------------*
122   @brief        絶対値を求めます
123 
124   @param[in]    x   絶対値を求める値
125 
126   @return       x の絶対値を返します
127  *---------------------------------------------------------------------------*/
128 inline f32
FAbs(f32 x)129 FAbs(f32 x)
130 {
131     f32 ret;
132 
133     ret = ::std::fabsf(x);
134 
135 
136     return ret;
137 }
138 
139 
140 /*!--------------------------------------------------------------------------*
141   @brief        絶対値が等しく、符号が負である数を求めます
142 
143   @param[in]    x   元の数。
144 
145   @return       x と絶対値が等しく、符号が負である数を返します
146  *---------------------------------------------------------------------------*/
147 inline f32
FNAbs(f32 x)148 FNAbs(f32 x)
149 {
150     f32 ret;
151 
152     ret = - FAbs(x);
153 
154 
155     return ret;
156 }
157 
158 
159 /*!--------------------------------------------------------------------------*
160   @brief        一方の数の符号を他方の数にコピーします
161 
162   @param[in]    abs     絶対値の元となる数。
163   @param[in]    sign    符号を採用する数。
164 
165   @return       abs の絶対値と sign の符号を持った数を返します。
166  *---------------------------------------------------------------------------*/
167 inline f32
FCopySign(f32 abs,f32 sign)168 FCopySign(f32 abs, f32 sign)
169 {
170     f32 pos = FAbs(abs);
171     f32 neg = FNAbs(abs);
172 
173     return FSelect(sign, pos, neg);
174 }
175 
176 namespace internal
177 {
178     f32 FExp(f32 x);
179     f32 FLog(f32 x);
180 }
181 
182 
183 /*!--------------------------------------------------------------------------*
184   @brief        e^x を求めます
185 
186   @param[in]    x   指数の値
187 
188   @return       e^x を返します
189  *---------------------------------------------------------------------------*/
190 inline f32
FExp(f32 x)191 FExp(f32 x)
192 {
193     return ::std::expf(x);
194 
195 }
196 
197 
198 /*!--------------------------------------------------------------------------*
199   @brief        自然対数を求めます
200 
201   @param[in]    x   自然対数を求める値
202 
203   @return       x の自然対数を返します
204  *---------------------------------------------------------------------------*/
205 inline f32
FLog(f32 x)206 FLog(f32 x)
207 {
208     NN_MATH_WARNING(x > 0, "FLog: Input is out of the domain.");
209 
210     return ::std::logf(x);
211 
212 }
213 
214 
215 /*!--------------------------------------------------------------------------*
216   @brief        常用対数を求めます
217 
218   @param[in]    x   常用対数を求める値
219 
220   @return       x の常用対数を返します
221  *---------------------------------------------------------------------------*/
222 inline f32
FLog10(f32 x)223 FLog10(f32 x)
224 {
225     NN_MATH_WARNING(x > 0, "FLog10: Input is out of the domain.");
226 
227     return ::std::log10f(x);
228 }
229 
230 
231 /*!--------------------------------------------------------------------------*
232   @brief        剰余を計算します
233 
234   @param[in]    x   割られる数
235   @param[in]    y   割る数
236 
237   @return       x / y の剰余を返します
238  *---------------------------------------------------------------------------*/
239 inline f32
FMod(f32 x,f32 y)240 FMod(f32 x, f32 y)
241 {
242     return ::std::fmodf(x, y);
243 }
244 
245 
246 /*!--------------------------------------------------------------------------*
247   @brief        浮動小数点数を整数部と小数部に分けます。整数部、小数部共に x と同じ符号を持ちます。
248 
249   @param[in]    x   元の浮動小数点数。
250   @param[out]   y   整数部を格納するバッファへのポインタ。
251 
252   @return       小数部を返します
253  *---------------------------------------------------------------------------*/
254 inline f32
FModf(f32 x,f32 * y)255 FModf(f32 x, f32* y)
256 {
257     return ::std::modff(x, y);
258 }
259 
260 
261 /*!--------------------------------------------------------------------------*
262   @brief        x を下回らない最小の整数値を求めます
263 
264   @param[in]    x   対象の値
265 
266   @return       x を下回らない最小の整数値を返します
267  *---------------------------------------------------------------------------*/
268 inline f32
FCeil(f32 x)269 FCeil(f32 x)
270 {
271     return ::std::ceilf(x);
272 }
273 
274 
275 /*!--------------------------------------------------------------------------*
276   @brief        x を超えない最大の整数値を求めます
277 
278   @param[in]    x   対象の値
279 
280   @return       x を超えない最大の整数値を返します
281  *---------------------------------------------------------------------------*/
282 inline f32
FFloor(f32 x)283 FFloor(f32 x)
284 {
285     return ::std::floorf(x);
286 }
287 
288 
289 /*!--------------------------------------------------------------------------*
290   @brief        f32型からs16型に変換します
291 
292   @param[in]    x   s16型に変換する値
293 
294   @return       x と同じ値を持ったs16型の値を返します
295  *---------------------------------------------------------------------------*/
296 inline s16
F32ToS16(f32 x)297 F32ToS16(f32 x)
298 {
299     return s16(x);
300 
301 }
302 
303 
304 /*!--------------------------------------------------------------------------*
305   @brief        f32型からu16型に変換します
306 
307   @param[in]    x   u16型に変換する値
308 
309   @return       x と同じ値を持ったu16型の値を返します
310  *---------------------------------------------------------------------------*/
311 inline u16
F32ToU16(f32 x)312 F32ToU16(f32 x)
313 {
314     return u16(x);
315 
316 }
317 
318 
319 /*!--------------------------------------------------------------------------*
320   @brief        u16型からf32型に変換します
321 
322   @param[in]    x   f32型に変換する値
323 
324   @return       x と同じ値を持ったf32型の値を返します
325  *---------------------------------------------------------------------------*/
326 inline f32
U16ToF32(u16 x)327 U16ToF32(u16 x)
328 {
329     return f32(x);
330 
331 }
332 
333 
334 /*!--------------------------------------------------------------------------*
335   @brief        s16型からf32型に変換します
336 
337   @param[in]    x   f32型に変換する値
338 
339   @return       x と同じ値を持ったf32型の値を返します
340  *---------------------------------------------------------------------------*/
341 inline f32
S16ToF32(s16 x)342 S16ToF32(s16 x)
343 {
344     return f32(x);
345 
346 }
347 
348 
349 
350 /*!--------------------------------------------------------------------------*
351   @brief        逆数を高速低精度に求めます
352 
353   @param[in]    x   逆数を求める値
354 
355   @return       x の逆数を返します
356  *---------------------------------------------------------------------------*/
357 inline f32
FInv(f32 x)358 FInv(f32 x)
359 {
360     f32 ix;
361 
362     ix = 1.0f / x;
363 
364 
365     return ix;
366 }
367 
368 
369 /*!--------------------------------------------------------------------------*
370   @brief        平方根の逆数を求めます。
371 
372   @param[in]    x 平方根の逆数を求める値。
373 
374   @return       x の平方根の逆数を返します。
375  *---------------------------------------------------------------------------*/
376 inline f32
FrSqrt(f32 x)377 FrSqrt(f32 x)
378 {
379     NN_MATH_WARNING(x > 0, "FrSqrt: Input is out of the domain.");
380 
381     return 1.f / ::std::sqrtf(x);
382 }
383 
384 
385 /*!--------------------------------------------------------------------------*
386   @brief        平方根を求めます
387 
388   @param[in]    x   平方根を求める値
389 
390   @return       x の平方根を返します
391  *---------------------------------------------------------------------------*/
392 inline f32
FSqrt(f32 x)393 FSqrt(f32 x)
394 {
395     NN_MATH_WARNING(x >= 0, "FSqrt: Input is out of the domain.");
396 
397     return ::std::sqrtf(x);
398 }
399 
400 
401 /*!--------------------------------------------------------------------------*
402   @brief        立方根を求めます
403 
404   @param[in]    x   立方根を求める値
405 
406   @return       x の立方根を返します
407  *---------------------------------------------------------------------------*/
408 inline f32
FCbrt(f32 x)409 FCbrt(f32 x)
410 {
411 #if defined(NN_CW3)
412     return ::std::cbrtf(x);
413 #else
414     return ::std::pow(x, 1/3.f);
415 #endif
416 }
417 
418 
419 /*!--------------------------------------------------------------------------*
420   @brief        エルミート補間を行います
421 
422   @param[in]    v0  点1での値。
423   @param[in]    t0  点1での傾き。
424   @param[in]    v1  点2での値。
425   @param[in]    t1  点2での傾き。
426   @param[in]    s   補間対象位置。(点1:0.0~1.0:点2)
427 
428   @return       補間結果の値。
429  *---------------------------------------------------------------------------*/
430 inline f32
Hermite(f32 v0,f32 t0,f32 v1,f32 t1,f32 s)431 Hermite(f32 v0, f32 t0, f32 v1, f32 t1, f32 s)
432 {
433 #if defined( NN_HARDWARE_CTR )
434     #if (HERMITE_5_CONFIG == D_ORG)
435         return ARMv6::HermiteC(v0, t0, v1, t1, s);
436     #elif (HERMITE_5_CONFIG == D_FAST_C)
437         return ARMv6::HermiteC_FAST(v0, t0, v1, t1, s);
438     #elif (HERMITE_5_CONFIG == D_FAST_ASM)
439     #elif (HERMITE_5_CONFIG == D_FAST_C_ALGO)
440     #elif (HERMITE_5_CONFIG == D_FAST_ASM_ALGO)
441     #endif
442 #else
443 #endif
444 }
445 
446 
447 /*!--------------------------------------------------------------------------*
448   @brief        エルミート補間計算です。
449 
450   @param[in]    v0  点1での値。
451   @param[in]    t0  点1での傾き。
452   @param[in]    v1  点2での値。
453   @param[in]    t1  点2での傾き。
454   @param[in]    p   点1から補間対象位置の距離。
455   @param[in]    d   点1と点2の距離。
456 
457   @return       エルミート補間の結果です。
458  *---------------------------------------------------------------------------*/
459 NN_FORCE_INLINE f32
Hermite(f32 v0,f32 t0,f32 v1,f32 t1,f32 p,f32 d)460 Hermite(f32 v0, f32 t0, f32 v1, f32 t1, f32 p, f32 d)
461 {
462 #if defined( NN_HARDWARE_CTR )
463     #if (HERMITE_6_CONFIG == D_ORG)
464         return ARMv6::HermiteC(v0, t0, v1, t1, p, d);
465     #elif (HERMITE_6_CONFIG == D_FAST_C)
466         return ARMv6::HermiteC_FAST(v0, t0, v1, t1, p, d);
467     #elif (HERMITE_6_CONFIG == D_FAST_ASM)
468         return ARMv6::HermiteAsm(v0, t0, v1, t1, p, d);
469     #elif (HERMITE_6_CONFIG == D_FAST_C_ALGO)
470     #elif (HERMITE_6_CONFIG == D_FAST_ASM_ALGO)
471     #endif
472 #else
473 #endif
474 }
475 
476 
477 f32 Bezier(f32 p1, f32 p2, f32 p3, f32 p4, f32 s);
478 f32 CatmullRom(f32 p0, f32 p1, f32 p2, f32 p3, f32 s);
479 
480 /*!
481     @}
482 */
483 
484 /* =======================================================================
485         整数関連
486    ======================================================================== */
487 
488 /*!
489     @name    整数に関する数学関数
490     @{
491 */
492 
493 // 非インライン関数
494 
495 u32 CntBit1(u32 x);
496 u32 CntBit1(const u32* first, const u32* last);
497 u32 DistBit(const u32* first1, const u32* last1, const u32* first2);
498 u32 RevBit(u32 x);
499 int IExp(int x, u32 n);
500 u32 ILog10(u32 x);
501 
502 #ifndef NN_PROCESSOR_ARM
503 namespace internal
504 {
505 u32 CntLz_(u32 x);
506 }
507 #endif
508 
509 /*!--------------------------------------------------------------------------*
510   @brief        MSBからの連続する 0 のビットを数えます。
511 
512   @param[in]    x  対象のビット列
513 
514   @return       MSBからの連続する 0 のビット数を返します。
515  *---------------------------------------------------------------------------*/
516 inline u32
CntLz(u32 x)517 CntLz(u32 x)
518 {
519 #ifdef NN_PROCESSOR_ARM
520     return __clz(x);
521 #else
522     return internal::CntLz_(x);
523 #endif
524 }
525 
526 
527 /*!--------------------------------------------------------------------------*
528   @brief        整数値が2の整数乗かどうかを判定します。
529 
530   @param[in]    x  判定対象の整数値
531 
532   @return       x が 2 の累乗であれば true を、そうでなければ false を返します。
533  *---------------------------------------------------------------------------*/
534 //          ただし x が 0 の場合は true を返します。
IsPwr2(int x)535 inline bool IsPwr2(int x) { return 0 == (x & (x - 1)); }
536 
537 /*!--------------------------------------------------------------------------*
538   @brief        1 になっているビットで一番右(LSB側)のビットを取得します。
539 
540   @param[in]    x  対象とするビット列
541 
542   @return       x で一番右の 1 となっているビット位置のみが 1 となっているビット列を返します。
543  *---------------------------------------------------------------------------*/
Rightmost1(int x)544 inline int Rightmost1(int x) { return x & (-x); }
Rightmost1(bit32 x)545 inline bit32 Rightmost1(bit32 x) { return x & (-x); }
Rightmost1(bit64 x)546 inline bit64 Rightmost1(bit64 x) { return x & (-x); }
547 
548 /*!--------------------------------------------------------------------------*
549   @brief        0 になっているビットで一番右(LSB側)のビットを取得します。
550 
551   @param[in]    x  対象とするビット列
552 
553   @return       x で一番右の 0 となっているビット位置のみが 1 となっているビット列を返します。
554  *---------------------------------------------------------------------------*/
Rightmost0(int x)555 inline int Rightmost0(int x) { return ~x & (x + 1); }
Rightmost0(bit32 x)556 inline bit32 Rightmost0(bit32 x) { return ~x & (x + 1); }
Rightmost0(bit64 x)557 inline bit64 Rightmost0(bit64 x) { return ~x & (x + 1); }
558 
559 /*!--------------------------------------------------------------------------*
560   @brief        ビット列同士の距離を計算します。
561 
562   @param[in]    x  ビット列 1
563   @param[in]    y  ビット列 2
564 
565   @return       ビット列 1 とビット列 2 の距離を返します。
566  *---------------------------------------------------------------------------*/
DistBit(u32 x,u32 y)567 inline u32 DistBit(u32 x, u32 y) { return CntBit1(x ^ y); }
568 
569 /*!--------------------------------------------------------------------------*
570   @brief        LSBからの連続する 0 のビットを数えます。
571 
572   @param[in]    x  対象のビット列
573 
574   @return       LSBからの連続する 0 のビット数を返します。
575  *---------------------------------------------------------------------------*/
CntTz(u32 x)576 inline u32 CntTz(u32 x) { return 32 - CntLz(~x & (x - 1)); }
577 
578 /*!--------------------------------------------------------------------------*
579   @brief        整数の 2 を底とする対数を計算し、結果を整数で返します。
580 
581   @param[in]    x  真数
582 
583   @return       整数の 2 を底とする対数を整数で返します。
584  *---------------------------------------------------------------------------*/
ILog2(u32 x)585 inline u32 ILog2(u32 x) { return 31 - CntLz(x); }
586 
587 /*!--------------------------------------------------------------------------*
588   @brief        与えられた整数以下の最大の 2 の累乗を計算します。
589 
590   @param[in]    x  対象の整数
591 
592   @return       x 以下の最大の2の累乗を返します。
593  *---------------------------------------------------------------------------*/
FloorPwr2(u32 x)594 inline u32 FloorPwr2(u32 x) { return 0x80000000 >> CntLz(x); }
595 
596 /*!--------------------------------------------------------------------------*
597   @brief        与えられた整数以上の最小の 2 の累乗を計算します。
598 
599   @param[in]    x  対象の整数
600 
601   @return       x 以上の最小の 2 の累乗を返します。
602  *---------------------------------------------------------------------------*/
CeilPwr2(u32 x)603 inline u32 CeilPwr2(u32 x) { return 0x80000000 >> (CntLz(x - 1) - 1); }
604 
605 /*!
606     @}
607 */
608 
609 }}  // nn::math
610 
611 #pragma pop
612 
613 /* NN_MATH_ARITHMETIC_H_ */
614 #endif
615