MDL SDK API nvidia_logo_transpbg.gif Up
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
function.h
Go to the documentation of this file.
1 /***************************************************************************************************
2  * Copyright 2022 NVIDIA Corporation. All rights reserved.
3  **************************************************************************************************/
9 
10 #ifndef MI_MATH_FUNCTION_H
11 #define MI_MATH_FUNCTION_H
12 
13 #include <mi/base/assert.h>
14 #include <mi/base/types.h>
15 
16 #ifdef MI_PLATFORM_WINDOWS
17 #include <intrin.h>
18 #pragma intrinsic(_BitScanReverse)
19 #ifdef MI_ARCH_64BIT
20 #pragma intrinsic(_BitScanReverse64)
21 #endif
22 #endif
23 
24 namespace mi {
25 
26 namespace math {
27 
59 namespace functor {
75 struct Operator_equal_equal {
78  template <typename T1, typename T2>
79  inline bool operator()( const T1& t1, const T2& t2) const { return t1 == t2; }
80 };
81 
85  template <typename T1, typename T2>
86  inline bool operator()( const T1& t1, const T2& t2) const { return t1 != t2; }
87 };
88 
90 struct Operator_less {
92  template <typename T1, typename T2>
93  inline bool operator()( const T1& t1, const T2& t2) const { return t1 < t2; }
94 };
95 
99  template <typename T1, typename T2>
100  inline bool operator()( const T1& t1, const T2& t2) const { return t1 <= t2; }
101 };
102 
106  template <typename T1, typename T2>
107  inline bool operator()( const T1& t1, const T2& t2) const { return t1 > t2; }
108 };
109 
113  template <typename T1, typename T2>
114  inline bool operator()( const T1& t1, const T2& t2) const { return t1 >= t2; }
115 };
116 
120  template <typename T>
121  inline T operator()( const T& t1, const T& t2) const { return t1 + t2; }
122 };
123 
127  template <typename T>
128  inline T operator()( const T& t) const { return - t; }
130  template <typename T>
131  inline T operator()( const T& t1, const T& t2) const { return t1 - t2; }
132 };
133 
137  template <typename T>
138  inline T operator()( const T& t1, const T& t2) const { return t1 * t2; }
139 };
140 
144  template <typename T>
145  inline T operator()( const T& t1, const T& t2) const { return t1 / t2; }
146 };
147 
151  template <typename T>
152  inline bool operator()( const T& t1, const T& t2) const { return t1 && t2; }
153 };
154 
158  template <typename T>
159  inline bool operator()( const T& t1, const T& t2) const { return t1 || t2; }
160 };
161 
163 struct Operator_xor {
165  template <typename T>
166  inline bool operator()( const T& t1, const T& t2) const { return t1 ^ t2; }
167 };
168 
170 struct Operator_not {
172  template <typename T>
173  inline bool operator()( const T& t) const { return ! t; }
174 };
175 
179  template <typename T>
180  inline T operator()( T& t) const { return ++ t; }
181 };
182 
186  template <typename T>
187  inline T operator()( T& t) const { return t ++; }
188 };
189 
193  template <typename T>
194  inline T operator()( T& t) const { return -- t; }
195 };
196 
200  template <typename T>
201  inline T operator()( T& t) const { return t --; }
202 };
203  // end group mi_math_functor
205 
206 } // namespace functor
207 
209 namespace general {
226 template <class Vector, class ResultVector, class UnaryFunctor>
234 inline void transform( const Vector& vec, ResultVector& result, UnaryFunctor f)
235 {
236  mi_static_assert( Vector::SIZE == ResultVector::SIZE);
237  for( Size i = 0; i != Vector::SIZE; ++i)
238  result.set( i, f( vec.get(i)));
239 }
240 
249 template <class Vector1, class Vector2, class ResultVector, class BinaryFunctor>
250 inline void transform(
251  const Vector1& vec1, const Vector2& vec2, ResultVector& result, BinaryFunctor f)
252 {
253  mi_static_assert( Vector1::SIZE == Vector2::SIZE);
254  mi_static_assert( Vector1::SIZE == ResultVector::SIZE);
255  for( Size i = 0; i != Vector1::SIZE; ++i)
256  result.set( i, f( vec1.get(i), vec2.get(i)));
257 }
258 
268 template <class Scalar, class Vector, class ResultVector, class BinaryFunctor>
270  const Scalar& s, const Vector& vec, ResultVector& result, BinaryFunctor f)
271 {
272  mi_static_assert( Vector::SIZE == ResultVector::SIZE);
273  for( Size i = 0; i != Vector::SIZE; ++i)
274  result.set( i, f( s, vec.get(i)));
275 }
276 
286 template <class Scalar, class Vector, class ResultVector, class BinaryFunctor>
288  const Vector& vec, const Scalar& s, ResultVector& result, BinaryFunctor f)
289 {
290  mi_static_assert( Vector::SIZE == ResultVector::SIZE);
291  for( Size i = 0; i != Vector::SIZE; ++i)
292  result.set( i, f( vec.get(i), s));
293 }
294 
301 template <class Vector, class UnaryFunctor>
302 inline void for_each( Vector& vec, UnaryFunctor f)
303 {
304  for( Size i = 0; i != Vector::SIZE; ++i)
305  f( vec.begin()[i]);
306 }
307 
315 template <class Vector1, class Vector2, class BinaryFunctor>
316 inline void for_each( Vector1& vec1, const Vector2& vec2, BinaryFunctor f)
317 {
318  mi_static_assert( Vector1::SIZE == Vector2::SIZE);
319  for( Size i = 0; i != Vector1::SIZE; ++i)
320  f( vec1.begin()[i], vec2.begin()[i]);
321 }
322  // end group mi_math_functor
324 
325 } // namespace general
326 
328 inline Float32 exp( Float32 s) { return std::exp(s); }
330 inline Float64 exp( Float64 s) { return std::exp(s); }
331 
333 inline Float32 log( Float32 s) { return std::log(s); }
335 inline Float64 log( Float64 s) { return std::log(s); }
336 
337 
338 #ifndef __CUDACC__
339 using mi::base::min;
340 using mi::base::max;
341 #endif
342 using mi::base::abs;
343 
344 
356 inline Float32 fast_sqrt( Float32 i)
358 {
359  int tmp = base::binary_cast<int>( i);
360  tmp -= 1 << 23; // Remove last bit to not let it go to mantissa
361  // tmp is now an approximation to logbase2(i)
362  tmp = tmp >> 1; // Divide by 2
363  tmp += 1 << 29; // Add 64 to the exponent: (e+127)/2 = (e/2)+63
364  // that represents (e/2)-64 but we want e/2
365  return base::binary_cast<Float32>( tmp);
366 }
367 
370 {
371  const Float32 EXP_C = 8388608.0f; // 2^23
372  const Float32 LOG_2_E = 1.4426950408889634073599246810019f; // 1 / log(2)
373 
374  x *= LOG_2_E;
375  Float32 y = x - std::floor(x);
376  y = (y - y*y) * 0.33971f;
377  const Float32 z = max MI_PREVENT_MACRO_EXPAND ((x + 127.0f - y) * EXP_C, 0.f);
378  return base::binary_cast<Float32>( static_cast<int>( z));
379 }
380 
383 {
384  const Float32 EXP_C = 8388608.0f; // 2^23
385 
386  Float32 y = x - std::floor(x);
387  y = (y - y*y) * 0.33971f;
388  const Float32 z = max MI_PREVENT_MACRO_EXPAND ((x + 127.0f - y) * EXP_C, 0.f);
389  return base::binary_cast<Float32>( static_cast<int>( z));
390 }
391 
394 {
395  const Float32 LOG_C = 0.00000011920928955078125f; // 2^(-23)
396 
397  const Float32 x = static_cast<Float32>( base::binary_cast<int>( i)) * LOG_C - 127.f;
398  const Float32 y = x - std::floor(x);
399  return x + (y - y*y) * 0.346607f;
400 }
401 
404  Float32 b,
405  Float32 e)
406 {
407  if( b == 0.0f)
408  return 0.0f;
409 
410  const Float32 LOG_C = 0.00000011920928955078125f; // 2^(-23)
411  const Float32 EXP_C = 8388608.0f; // 2^23
412 
413  const Float32 x = static_cast<Float32>( base::binary_cast<int>( b)) * LOG_C - 127.f;
414  const Float32 y = x - std::floor(x);
415  const Float32 fl = e * (x + (y - y*y) * 0.346607f);
416  const Float32 y2 = fl - std::floor(fl);
417  const Float32 z = max(
418  fl*EXP_C + static_cast<Float32>( 127.0*EXP_C)
419  - (y2 - y2*y2) * static_cast<Float32>( 0.33971*EXP_C), 0.f);
420 
421  return base::binary_cast<Float32>( static_cast<int>( z));
422 }
423  // end group mi_math_approx_function
425 
426 
428 inline Float32 acos( Float32 s) { return std::acos(s); }
430 inline Float64 acos( Float64 s) { return std::acos(s); }
431 
433 inline bool all( Uint8 v) { return Uint8 (0) != v; }
435 inline bool all( Uint16 v) { return Uint16 (0) != v; }
437 inline bool all( Uint32 v) { return Uint32 (0) != v; }
439 inline bool all( Uint64 v) { return Uint64 (0) != v; }
441 inline bool all( Sint8 v) { return Sint8 (0) != v; }
443 inline bool all( Sint16 v) { return Sint16 (0) != v; }
445 inline bool all( Sint32 v) { return Sint32 (0) != v; }
447 inline bool all( Sint64 v) { return Sint64 (0) != v; }
449 inline bool all( Float32 v) { return Float32(0) != v; }
451 inline bool all( Float64 v) { return Float64(0) != v; }
452 
454 inline bool any( Uint8 v) { return Uint8 (0) != v; } //-V524 PVS
456 inline bool any( Uint16 v) { return Uint16 (0) != v; } //-V524 PVS
458 inline bool any( Uint32 v) { return Uint32 (0) != v; } //-V524 PVS
460 inline bool any( Uint64 v) { return Uint64 (0) != v; } //-V524 PVS
462 inline bool any( Sint8 v) { return Sint8 (0) != v; } //-V524 PVS
464 inline bool any( Sint16 v) { return Sint16 (0) != v; } //-V524 PVS
466 inline bool any( Sint32 v) { return Sint32 (0) != v; } //-V524 PVS
468 inline bool any( Sint64 v) { return Sint64 (0) != v; } //-V524 PVS
470 inline bool any( Float32 v) { return Float32(0) != v; } //-V524 PVS
472 inline bool any( Float64 v) { return Float64(0) != v; } //-V524 PVS
473 
475 inline Float32 asin( Float32 s) { return std::asin(s); }
477 inline Float64 asin( Float64 s) { return std::asin(s); }
478 
480 inline Float32 atan( Float32 s) { return std::atan(s); }
482 inline Float64 atan( Float64 s) { return std::atan(s); }
483 
487 inline Float32 atan2( Float32 s, Float32 t) { return std::atan2(s,t); }
491 inline Float64 atan2( Float64 s, Float64 t) { return std::atan2(s,t); }
492 
494 inline Float32 ceil( Float32 s) { return std::ceil(s); }
496 inline Float64 ceil( Float64 s) { return std::ceil(s); }
497 
500 inline Uint8 clamp( Uint8 s, Uint8 low, Uint8 high)
501 {
502  return ( s < low) ? low : ( s > high) ? high : s;
503 }
506 inline Uint16 clamp( Uint16 s, Uint16 low, Uint16 high)
507 {
508  return ( s < low) ? low : ( s > high) ? high : s;
509 }
512 inline Uint32 clamp( Uint32 s, Uint32 low, Uint32 high)
513 {
514  return ( s < low) ? low : ( s > high) ? high : s;
515 }
518 inline Uint64 clamp( Uint64 s, Uint64 low, Uint64 high)
519 {
520  return ( s < low) ? low : ( s > high) ? high : s;
521 }
524 inline Sint8 clamp( Sint8 s, Sint8 low, Sint8 high)
525 {
526  return ( s < low) ? low : ( s > high) ? high : s;
527 }
530 inline Sint16 clamp( Sint16 s, Sint16 low, Sint16 high)
531 {
532  return ( s < low) ? low : ( s > high) ? high : s;
533 }
536 inline Sint32 clamp( Sint32 s, Sint32 low, Sint32 high)
537 {
538  return ( s < low) ? low : ( s > high) ? high : s;
539 }
542 inline Sint64 clamp( Sint64 s, Sint64 low, Sint64 high)
543 {
544  return ( s < low) ? low : ( s > high) ? high : s;
545 }
548 inline Float32 clamp( Float32 s, Float32 low, Float32 high)
549 {
550  return ( s < low) ? low : ( s > high) ? high : s;
551 }
554 inline Float64 clamp( Float64 s, Float64 low, Float64 high)
555 {
556  return ( s < low) ? low : ( s > high) ? high : s;
557 }
558 
560 inline Float32 cos( Float32 a) { return std::cos(a); }
562 inline Float64 cos( Float64 a) { return std::cos(a); }
563 
565 inline Float32 degrees( Float32 r) { return r * Float32(180.0/MI_PI); }
567 inline Float64 degrees( Float64 r) { return r * Float64(180.0/MI_PI); }
568 
570 inline Float32 exp2( Float32 s) { return fast_pow2(s); }
572 inline Float64 exp2( Float64 s)
573 {
574  return std::exp(s * 0.69314718055994530941723212145818 /* log(2) */ );
575 }
576 
578 inline Float32 floor( Float32 s) { return std::floor(s); }
580 inline Float64 floor( Float64 s) { return std::floor(s); }
581 
585 inline Float32 fmod( Float32 a, Float32 b) { return std::fmod(a,b); }
589 inline Float64 fmod( Float64 a, Float64 b) { return std::fmod(a,b); }
590 
592 inline Float32 frac( Float32 s)
593 {
594  Float32 dummy;
595  if( s >= 0.0f)
596  return std::modf( s, &dummy);
597  else
598  return 1.0f + std::modf( s, &dummy);
599 }
601 inline Float64 frac( Float64 s)
602 {
603  Float64 dummy;
604  if( s >= 0.0f)
605  return std::modf( s, &dummy);
606  else
607  return 1.0f + std::modf( s, &dummy);
608 }
609 
611 inline bool is_approx_equal(
612  Float32 left,
613  Float32 right,
614  Float32 e)
615 {
616  return abs( left - right ) <= e;
617 }
618 
620 inline bool is_approx_equal(
621  Float64 left,
622  Float64 right,
623  Float64 e)
624 {
625  return abs( left - right ) <= e;
626 }
627 
630  // This implementation tries to use built-in functions if available. For the fallback
631  // method, see Henry Warren: "Hacker's Delight" for reference.
632 #if defined(MI_COMPILER_MSC)
633  unsigned long index;
634  const unsigned char valid = _BitScanReverse(&index, v);
635  return (valid != 0) ? 31 - index : 32;
636 #elif defined(MI_COMPILER_ICC) || defined(MI_COMPILER_GCC)
637  return (v != 0) ? __builtin_clz(v) : 32;
638 #else
639  // use fallback
640  if (v == 0) return 32;
641  Uint32 n = 1;
642  if ((v >> 16) == 0) { n += 16; v <<= 16; };
643  if ((v >> 24) == 0) { n += 8; v <<= 8; };
644  if ((v >> 28) == 0) { n += 4; v <<= 4; };
645  if ((v >> 30) == 0) { n += 2; v <<= 2; };
646  n -= Uint32(v >> 31);
647  return n;
648 #endif
649 }
650 
653  // This implementation tries to use built-in functions if available. For the fallback
654  // method, see Henry Warren: "Hacker's Delight" for reference.
655 #if defined(MI_COMPILER_MSC)
656 #if defined(MI_ARCH_64BIT)
657  unsigned long index;
658  const unsigned char valid = _BitScanReverse64(&index, v);
659  return (valid != 0) ? 63 - index : 64;
660 #else
661  unsigned long index_h, index_l;
662  const unsigned char valid_h = _BitScanReverse(&index_h,(Uint32)(v >> 32));
663  const unsigned char valid_l = _BitScanReverse(&index_l,(Uint32)(v & 0xFFFFFFFF));
664  if (valid_h == 0)
665  return (valid_l != 0) ? 63 - index_l : 64;
666  return 63 - index_h + 32;
667 #endif
668 #elif defined(MI_COMPILER_ICC) || defined(MI_COMPILER_GCC)
669  return (v != 0) ? __builtin_clzll(v) : 64;
670 #else
671  // use fallback
672  if (v == 0) return 64;
673  Uint32 n = 1;
674  if ((v >> 32) == 0) { n += 32; v <<= 32; };
675  if ((v >> 48) == 0) { n += 16; v <<= 16; };
676  if ((v >> 56) == 0) { n += 8; v <<= 8; };
677  if ((v >> 60) == 0) { n += 4; v <<= 4; };
678  if ((v >> 62) == 0) { n += 2; v <<= 2; };
679  n -= Uint32(v >> 63);
680  return n;
681 #endif
682 }
683 
686 inline Float32 lerp(
687  Float32 s1,
688  Float32 s2,
689  Float32 t)
690 {
691  return s1 * (Float32(1)-t) + s2 * t;
692 }
693 
696 inline Float64 lerp(
697  Float64 s1,
698  Float64 s2,
699  Float64 t)
700 {
701  return s1 * (Float64(1)-t) + s2 * t;
702 }
703 
706 { return std::log(s) * 1.4426950408889634073599246810019f /* log(2) */; }
709 { return std::log(s) * 1.4426950408889634073599246810019 /* log(2) */; }
710 
712 inline Sint32 log2_int( const Uint32 v) { return (v != 0) ? 31 - leading_zeros(v) : 0; }
713 
715 inline Sint32 log2_int( const Uint64 v) { return (v != 0) ? 63 - leading_zeros(v) : 0; }
716 
718 inline Sint32 log2_int( const Float32 v) {
719  return (mi::base::binary_cast<Uint32>(v) >> 23) - 127;
720 }
721 
723 inline Sint32 log2_int( const Float64 v) {
724  return static_cast<Sint32>(mi::base::binary_cast<Uint64>(v) >> 52) - 1023;
725 }
726 
728 template<typename Integer>
729 inline Sint32 log2_int_ceil( const Integer v) {
730  // See Henry Warren: "Hacker's Delight" for reference.
731  return (v > 1) ? log2_int(v - 1) + 1 : 0;
732 }
733 
735 inline Float32 log10( Float32 s) { return std::log10(s); }
737 inline Float64 log10( Float64 s) { return std::log10(s); }
738 
742 inline Float32 modf( Float32 s, Float32& i) { return std::modf( s, &i); }
746 inline Float64 modf( Float64 s, Float64& i) { return std::modf( s, &i); }
747 
749 inline Uint32 pow( Uint32 a, Uint32 b) { return Uint32(std::pow(double(a), int(b))); }
751 inline Uint64 pow( Uint64 a, Uint64 b) { return Uint64(std::pow(double(a), int(b))); }
753 inline Sint32 pow( Sint32 a, Sint32 b) { return Sint32(std::pow(double(a), int(b))); }
755 inline Sint64 pow( Sint64 a, Sint64 b) { return Sint64(std::pow(double(a), int(b))); }
757 inline Float32 pow( Float32 a, Float32 b) { return std::pow( a, b); }
759 inline Float64 pow( Float64 a, Float64 b) { return std::pow( a, b); }
760 
762 inline Float32 radians( Float32 d) { return d * Float32(MI_PI/180.0); }
764 inline Float64 radians( Float64 d) { return d * Float64(MI_PI/180.0); }
765 
767 inline Float32 round( Float32 s) { return std::floor(s + 0.5f); }
769 inline Float64 round( Float64 s) { return std::floor(s + 0.5); }
770 
772 inline Float32 rsqrt( Float32 s) { return 1.0f / std::sqrt(s); }
774 inline Float64 rsqrt( Float64 s) { return 1.0 / std::sqrt(s); }
775 
777 inline Float32 saturate( Float32 s) { return (s < 0.f) ? 0.f : (s > 1.f) ? 1.f : s;}
779 inline Float64 saturate( Float64 s) { return (s < 0.) ? 0. : (s > 1. ) ? 1. : s;}
780 
782 inline Sint8 sign( Sint8 s)
783 { int r = (s < 0 ) ? -1 : (s > 0) ? 1 : 0; return static_cast<Sint8>( r); }
785 inline Sint16 sign( Sint16 s)
786 { int r = (s < 0 ) ? -1 : (s > 0) ? 1 : 0; return static_cast<Sint16>( r); }
788 inline Sint32 sign( Sint32 s) { return (s < 0 ) ? -1 : (s > 0) ? 1 : 0; }
790 inline Sint64 sign( Sint64 s) { return (s < 0 ) ? -1 : (s > 0) ? 1 : 0; }
792 inline Float32 sign( Float32 s) { return (s < 0.f) ? -1.f: (s > 0.f) ? 1.f : 0.f; }
794 inline Float64 sign( Float64 s) { return (s < 0. ) ? -1. : (s > 0.) ? 1. : 0.; }
795 
797 inline bool sign_bit( Sint8 s) { return s < 0; }
799 inline bool sign_bit( Sint16 s) { return s < 0; }
801 inline bool sign_bit( Sint32 s) { return s < 0; }
803 inline bool sign_bit( Sint64 s) { return s < 0; }
804 
809 inline bool sign_bit( Float32 s)
810 {
811  return (base::binary_cast<Uint32>(s) & (1U << 31)) != 0U;
812 }
813 
818 inline bool sign_bit( Float64 s)
819 {
820  return (base::binary_cast<Uint64>(s) & (1ULL << 63)) != 0ULL;
821 }
822 
823 #if (__cplusplus < 201103L)
824 inline bool isnan MI_PREVENT_MACRO_EXPAND (const Float32 x)
828 {
829  // interpret as Uint32 value
830  const Uint32 f = base::binary_cast<Uint32>(x);
831 
832  // check bit pattern
833  return (f << 1) > 0xFF000000U; // shift sign bit, 8bit exp == 2^8-1, fraction != 0
834 }
835 
839 inline bool isnan MI_PREVENT_MACRO_EXPAND (const Float64 x)
840 {
841  // interpret as Uint64 value
842  const Uint64 f = base::binary_cast<Uint64>(x);
843 
844  return (f << 1) > 0xFFE0000000000000ULL; // shift sign bit, 11bit exp == 2^11-1, fraction != 0
845 }
846 #else
847 using std::isnan;
848 #endif
849 
850 
851 #ifndef __CUDA_ARCH__
852 inline float __uint_as_float(const unsigned v)
853 { return base::binary_cast<float>(v);}
854 
855 inline unsigned __float_as_uint(const float v)
856 { return base::binary_cast<unsigned>(v);}
857 #endif
858 
859 
864 {
865  const Uint32 exponent_mask = 0x7F800000; // 8 bit exponent
866  const Uint32 fraction_mask = 0x7FFFFF; // 23 bit fraction
867 
868  // interpret as Uint32 value
869  const Uint32 f = base::binary_cast<Uint32>(x);
870 
871  // check bit pattern
872  return ((f & exponent_mask) == exponent_mask) && // exp == 2^8 - 1
873  ((f & fraction_mask) == 0); // fraction == 0
874 }
875 
880 {
881  const Uint64 exponent_mask = 0x7FF0000000000000ULL; // 11 bit exponent
882  const Uint64 fraction_mask = 0xFFFFFFFFFFFFFULL; // 52 bit fraction
883 
884  // interpret as Uint64 value
885  const Uint64 f = base::binary_cast<Uint64>(x);
886 
887  // check bit pattern
888  return ((f & exponent_mask) == exponent_mask) && // exp == 2^11 - 1
889  ((f & fraction_mask) == 0); // fraction == 0
890 }
891 
892 
893 #if (__cplusplus < 201103L)
894 inline bool isfinite MI_PREVENT_MACRO_EXPAND (const Float32 x)
900 {
901  const Uint32 exponent_mask = 0x7F800000; // 8 bit exponent
902 
903  // interpret as Uint32 value
904  const Uint32 f = base::binary_cast<Uint32>(x);
905 
906  // check exponent bits
907  return ((f & exponent_mask) != exponent_mask); // exp != 2^8 - 1
908 }
909 
915 inline bool isfinite MI_PREVENT_MACRO_EXPAND (const Float64 x)
916 {
917  const Uint64 exponent_mask = 0x7FF0000000000000ULL; // 11 bit exponent
918 
919  // interpret as Uint64 value
920  const Uint64 f = base::binary_cast<Uint64>(x);
921 
922  // check exponent bits
923  return ((f & exponent_mask) != exponent_mask); // exp != 2^11 - 1
924 }
925 #else
926 using std::isfinite;
927 #endif
928 
929 
931 inline Float32 sin( Float32 a) { return std::sin(a); }
933 inline Float64 sin( Float64 a) { return std::sin(a); }
934 
938 inline void sincos( Float32 a, Float32& s, Float32& c)
939 {
940  s = std::sin(a);
941  c = std::cos(a);
942 }
946 inline void sincos( Float64 a, Float64& s, Float64& c)
947 {
948  s = std::sin(a);
949  c = std::cos(a);
950 }
951 
957 {
958  if(x < a)
959  return 0.0f;
960  if(b < x)
961  return 1.0f;
962  Float32 t = (x - a) / (b - a);
963  return t * t * (3.0f - 2.0f * t);
964 }
970 {
971  if(x < a)
972  return 0.0;
973  if(b < x)
974  return 1.0;
975  Float64 t = (x - a) / (b - a);
976  return t * t * (3.0 - 2.0 * t);
977 }
978 
980 inline Float32 sqrt( Float32 s) { return std::sqrt(s); }
982 inline Float64 sqrt( Float64 s) { return std::sqrt(s); }
983 
985 inline Float32 step( Float32 a, Float32 x) { return (x < a) ? 0.0f : 1.0f; }
987 inline Float64 step( Float64 a, Float64 x) { return (x < a) ? 0.0 : 1.0; }
988 
990 inline Float32 tan( Float32 a) { return std::tan(a); }
992 inline Float64 tan( Float64 a) { return std::tan(a); }
993 
994 
996 MI_HOST_DEVICE_INLINE void to_rgbe( const Float32 color[3], Uint32& rgbe)
997 {
998  Float32 c[3];
999  c[0] = max( color[0], 0.0f);
1000  c[1] = max( color[1], 0.0f);
1001  c[2] = max( color[2], 0.0f);
1002 
1003  const Float32 m = max( max( c[0], c[1]), c[2]);
1004 
1005  // should actually be -126 or even -128, but avoid precision problems / denormalized numbers
1006  if( m <= 7.5231631727e-37f) // ~2^(-120)
1007  rgbe = 0;
1008  else if( m >= 1.7014118346046923173168730371588e+38f) // 2^127
1009  rgbe = 0xFFFFFFFFu;
1010  else {
1011  const Uint32 e = __float_as_uint( m) & 0x7F800000u;
1012  const Float32 v = __uint_as_float( 0x82800000u - e);
1013 
1014  rgbe = Uint32( c[0] * v)
1015  | (Uint32( c[1] * v) << 8)
1016  | (Uint32( c[2] * v) << 16)
1017  | (e * 2 + (2 << 24));
1018  }
1019 }
1020 
1022 MI_HOST_DEVICE_INLINE void to_rgbe( const Float32 color[3], Uint8 rgbe[4])
1023 {
1024  Float32 c[3];
1025  c[0] = max( color[0], 0.0f);
1026  c[1] = max( color[1], 0.0f);
1027  c[2] = max( color[2], 0.0f);
1028 
1029  const Float32 m = max( max( c[0], c[1]), c[2]);
1030 
1031  // should actually be -126 or even -128, but avoid precision problems / denormalized numbers
1032  if( m <= 7.5231631727e-37f) // ~2^(-120)
1033  rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
1034  else if( m >= 1.7014118346046923173168730371588e+38f) // 2^127
1035  rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 255;
1036  else {
1037  const Uint32 e = __float_as_uint( m) & 0x7F800000u;
1038  const Float32 v = __uint_as_float( 0x82800000u - e);
1039 
1040  rgbe[0] = Uint8( c[0] * v);
1041  rgbe[1] = Uint8( c[1] * v);
1042  rgbe[2] = Uint8( c[2] * v);
1043  rgbe[3] = Uint8( (e >> 23) + 2);
1044  }
1045 }
1046 
1048 MI_HOST_DEVICE_INLINE void from_rgbe( const Uint8 rgbe[4], Float32 color[3])
1049 {
1050  if( rgbe[3] == 0) {
1051  color[0] = color[1] = color[2] = 0.0f;
1052  return;
1053  }
1054 
1055  const Uint32 e = (static_cast<Uint32>( rgbe[3]) << 23) - 0x800000u;
1056  const Float32 v = __uint_as_float( e);
1057  const Float32 c = static_cast<Float32>( 1.0 - 0.5/256.0) * v;
1058 
1059  color[0] = __uint_as_float( e | (static_cast<Uint32>( rgbe[0]) << 15)) - c;
1060  color[1] = __uint_as_float( e | (static_cast<Uint32>( rgbe[1]) << 15)) - c;
1061  color[2] = __uint_as_float( e | (static_cast<Uint32>( rgbe[2]) << 15)) - c;
1062 }
1063 
1065 MI_HOST_DEVICE_INLINE void from_rgbe( const Uint32 rgbe, Float32 color[3])
1066 {
1067  const Uint32 rgbe3 = rgbe & 0xFF000000u;
1068  if( rgbe3 == 0) {
1069  color[0] = color[1] = color[2] = 0.0f;
1070  return;
1071  }
1072 
1073  const Uint32 e = (rgbe3 >> 1) - 0x800000u;
1074  const Float32 v = __uint_as_float( e);
1075  const Float32 c = static_cast<Float32>( 1.0 - 0.5/256.0) * v;
1076 
1077  color[0] = __uint_as_float( e | ((rgbe << 15) & 0x7F8000u)) - c;
1078  color[1] = __uint_as_float( e | ((rgbe << 7) & 0x7F8000u)) - c;
1079  color[2] = __uint_as_float( e | ((rgbe >> 1) & 0x7F8000u)) - c;
1080 }
1081 
1082 
1083 //------ Generic Vector Algorithms --------------------------------------------
1084 
1085 // overloads for 1D vectors (scalars)
1086 
1088 inline Sint32 dot( Sint32 a, Sint32 b) { return a * b; }
1090 inline Float32 dot( Float32 a, Float32 b) { return a * b; }
1092 inline Float64 dot( Float64 a, Float64 b) { return a * b; }
1093 
1095 template <class V>
1096 inline typename V::value_type dot( const V& lhs, const V& rhs)
1097 {
1098  typename V::value_type v(0);
1099  for( Size i(0u); i < V::SIZE; ++i)
1100  v += lhs.get(i) * rhs.get(i);
1101  return v;
1102 }
1103 
1105 template <class V>
1106 inline typename V::value_type square_length( const V& v)
1107 {
1108  return dot( v, v);
1109 }
1110 
1111 // base case for scalars
1112 
1114 inline Float32 length( Float32 a) { return abs(a); }
1116 inline Float64 length( Float64 a) { return abs(a); }
1117 
1118 
1122 template <class V>
1123 inline typename V::value_type length( const V& v)
1124 {
1125  return sqrt( square_length(v));
1126 }
1127 
1129 template <class V>
1130 inline typename V::value_type square_euclidean_distance( const V& lhs, const V& rhs)
1131 {
1132  return square_length( lhs - rhs);
1133 }
1134 
1138 template <class V>
1139 inline typename V::value_type euclidean_distance(
1140  const V& lhs, const V& rhs)
1141 {
1142  return length( lhs - rhs);
1143 }
1144 
1146 template <class V>
1147 inline void set_bounds( V& v, const V& low, const V& high)
1148 {
1149  for( Size i(0u); i < V::SIZE; ++i)
1150  v[i] = min MI_PREVENT_MACRO_EXPAND (
1151  max MI_PREVENT_MACRO_EXPAND (v.get(i), low.get(i)), high.get(i));
1152 }
1153 
1156 template <class V>
1157 inline bool is_equal( const V& lhs, const V& rhs)
1158 {
1159  for( Size i(0u); i < V::SIZE; ++i)
1160  if( ! (lhs.get(i) == rhs.get(i)))
1161  return false;
1162  return true;
1163 }
1164 
1167 template <class V>
1168 inline bool is_not_equal( const V& lhs, const V& rhs)
1169 {
1170  for( Size i(0u); i < V::SIZE; ++i)
1171  if( lhs.get(i) != rhs.get(i))
1172  return true;
1173  return false;
1174 }
1175 
1180 template <class V>
1181 inline bool lexicographically_less( const V& lhs, const V& rhs)
1182 {
1183  for( Size i(0u); i < V::SIZE-1; ++i) {
1184  if( lhs.get(i) < rhs.get(i))
1185  return true;
1186  if( lhs.get(i) > rhs.get(i))
1187  return false;
1188  }
1189  return lhs.get(V::SIZE-1) < rhs.get(V::SIZE-1);
1190 }
1191 
1196 template <class V>
1197 inline bool lexicographically_less_or_equal( const V& lhs, const V& rhs)
1198 {
1199  for( Size i(0u); i < V::SIZE-1; ++i) {
1200  if( lhs.get(i) < rhs.get(i))
1201  return true;
1202  if( lhs.get(i) > rhs.get(i))
1203  return false;
1204  }
1205  return lhs.get(V::SIZE-1) <= rhs.get(V::SIZE-1);
1206 }
1207 
1212 template <class V>
1213 inline bool lexicographically_greater( const V& lhs, const V& rhs)
1214 {
1215  for( Size i(0u); i < V::SIZE-1; ++i) {
1216  if( lhs.get(i) > rhs.get(i))
1217  return true;
1218  if( lhs.get(i) < rhs.get(i))
1219  return false;
1220  }
1221  return lhs.get(V::SIZE-1) > rhs.get(V::SIZE-1);
1222 }
1223 
1228 template <class V>
1229 inline bool lexicographically_greater_or_equal( const V& lhs, const V& rhs)
1230 {
1231  for( Size i(0u); i < V::SIZE-1; ++i) {
1232  if( lhs.get(i) > rhs.get(i))
1233  return true;
1234  if( lhs.get(i) < rhs.get(i))
1235  return false;
1236  }
1237  return lhs.get(V::SIZE-1) >= rhs.get(V::SIZE-1);
1238 }
1239 
1249 template <class V>
1250 inline Comparison_result lexicographically_compare( const V& lhs, const V& rhs)
1251 {
1252  for( Size i(0u); i < V::SIZE; ++i) {
1253  Comparison_result result = three_valued_compare( lhs.get(i), rhs.get(i));
1254  if( result != EQUAL)
1255  return result;
1256  }
1257  return EQUAL;
1258 }
1259  // end group mi_math_function
1261 
1262 } // namespace math
1263 
1264 } // namespace mi
1265 
1266 #endif // MI_MATH_FUNCTION_H