Material Definition Language 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 2020 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 using mi::base::min;
339 using mi::base::max;
340 using mi::base::abs;
341 
342 
354 inline Float32 fast_sqrt( Float32 i)
356 {
357  int tmp = base::binary_cast<int>( i);
358  tmp -= 1 << 23; // Remove last bit to not let it go to mantissa
359  // tmp is now an approximation to logbase2(i)
360  tmp = tmp >> 1; // Divide by 2
361  tmp += 1 << 29; // Add 64 to the exponent: (e+127)/2 = (e/2)+63
362  // that represents (e/2)-64 but we want e/2
363  return base::binary_cast<Float32>( tmp);
364 }
365 
368 {
369  const Float32 EXP_C = 8388608.0f; // 2^23
370  const Float32 LOG_2_E = 1.4426950408889634073599246810019f; // 1 / log(2)
371 
372  x *= LOG_2_E;
373  Float32 y = x - std::floor(x);
374  y = (y - y*y) * 0.33971f;
375  const Float32 z = max MI_PREVENT_MACRO_EXPAND ((x + 127.0f - y) * EXP_C, 0.f);
376  return base::binary_cast<Float32>( static_cast<int>( z));
377 }
378 
381 {
382  const Float32 EXP_C = 8388608.0f; // 2^23
383 
384  Float32 y = x - std::floor(x);
385  y = (y - y*y) * 0.33971f;
386  const Float32 z = max MI_PREVENT_MACRO_EXPAND ((x + 127.0f - y) * EXP_C, 0.f);
387  return base::binary_cast<Float32>( static_cast<int>( z));
388 }
389 
392 {
393  const Float32 LOG_C = 0.00000011920928955078125f; // 2^(-23)
394 
395  const Float32 x = static_cast<Float32>( base::binary_cast<int>( i)) * LOG_C - 127.f;
396  const Float32 y = x - std::floor(x);
397  return x + (y - y*y) * 0.346607f;
398 }
399 
402  Float32 b,
403  Float32 e)
404 {
405  if( b == 0.0f)
406  return 0.0f;
407 
408  const Float32 LOG_C = 0.00000011920928955078125f; // 2^(-23)
409  const Float32 EXP_C = 8388608.0f; // 2^23
410 
411  const Float32 x = static_cast<Float32>( base::binary_cast<int>( b)) * LOG_C - 127.f;
412  const Float32 y = x - std::floor(x);
413  const Float32 fl = e * (x + (y - y*y) * 0.346607f);
414  const Float32 y2 = fl - std::floor(fl);
415  const Float32 z = max(
416  fl*EXP_C + static_cast<Float32>( 127.0*EXP_C)
417  - (y2 - y2*y2) * static_cast<Float32>( 0.33971*EXP_C), 0.f);
418 
419  return base::binary_cast<Float32>( static_cast<int>( z));
420 }
421  // end group mi_math_approx_function
423 
424 
426 inline Float32 acos( Float32 s) { return std::acos(s); }
428 inline Float64 acos( Float64 s) { return std::acos(s); }
429 
431 inline bool all( Uint8 v) { return Uint8 (0) != v; }
433 inline bool all( Uint16 v) { return Uint16 (0) != v; }
435 inline bool all( Uint32 v) { return Uint32 (0) != v; }
437 inline bool all( Uint64 v) { return Uint64 (0) != v; }
439 inline bool all( Sint8 v) { return Sint8 (0) != v; }
441 inline bool all( Sint16 v) { return Sint16 (0) != v; }
443 inline bool all( Sint32 v) { return Sint32 (0) != v; }
445 inline bool all( Sint64 v) { return Sint64 (0) != v; }
447 inline bool all( Float32 v) { return Float32(0) != v; }
449 inline bool all( Float64 v) { return Float64(0) != v; }
450 
452 inline bool any( Uint8 v) { return Uint8 (0) != v; } //-V524 PVS
454 inline bool any( Uint16 v) { return Uint16 (0) != v; } //-V524 PVS
456 inline bool any( Uint32 v) { return Uint32 (0) != v; } //-V524 PVS
458 inline bool any( Uint64 v) { return Uint64 (0) != v; } //-V524 PVS
460 inline bool any( Sint8 v) { return Sint8 (0) != v; } //-V524 PVS
462 inline bool any( Sint16 v) { return Sint16 (0) != v; } //-V524 PVS
464 inline bool any( Sint32 v) { return Sint32 (0) != v; } //-V524 PVS
466 inline bool any( Sint64 v) { return Sint64 (0) != v; } //-V524 PVS
468 inline bool any( Float32 v) { return Float32(0) != v; } //-V524 PVS
470 inline bool any( Float64 v) { return Float64(0) != v; } //-V524 PVS
471 
473 inline Float32 asin( Float32 s) { return std::asin(s); }
475 inline Float64 asin( Float64 s) { return std::asin(s); }
476 
478 inline Float32 atan( Float32 s) { return std::atan(s); }
480 inline Float64 atan( Float64 s) { return std::atan(s); }
481 
485 inline Float32 atan2( Float32 s, Float32 t) { return std::atan2(s,t); }
489 inline Float64 atan2( Float64 s, Float64 t) { return std::atan2(s,t); }
490 
492 inline Float32 ceil( Float32 s) { return std::ceil(s); }
494 inline Float64 ceil( Float64 s) { return std::ceil(s); }
495 
498 inline Uint8 clamp( Uint8 s, Uint8 low, Uint8 high)
499 {
500  return ( s < low) ? low : ( s > high) ? high : s;
501 }
504 inline Uint16 clamp( Uint16 s, Uint16 low, Uint16 high)
505 {
506  return ( s < low) ? low : ( s > high) ? high : s;
507 }
510 inline Uint32 clamp( Uint32 s, Uint32 low, Uint32 high)
511 {
512  return ( s < low) ? low : ( s > high) ? high : s;
513 }
516 inline Uint64 clamp( Uint64 s, Uint64 low, Uint64 high)
517 {
518  return ( s < low) ? low : ( s > high) ? high : s;
519 }
522 inline Sint8 clamp( Sint8 s, Sint8 low, Sint8 high)
523 {
524  return ( s < low) ? low : ( s > high) ? high : s;
525 }
528 inline Sint16 clamp( Sint16 s, Sint16 low, Sint16 high)
529 {
530  return ( s < low) ? low : ( s > high) ? high : s;
531 }
534 inline Sint32 clamp( Sint32 s, Sint32 low, Sint32 high)
535 {
536  return ( s < low) ? low : ( s > high) ? high : s;
537 }
540 inline Sint64 clamp( Sint64 s, Sint64 low, Sint64 high)
541 {
542  return ( s < low) ? low : ( s > high) ? high : s;
543 }
546 inline Float32 clamp( Float32 s, Float32 low, Float32 high)
547 {
548  return ( s < low) ? low : ( s > high) ? high : s;
549 }
552 inline Float64 clamp( Float64 s, Float64 low, Float64 high)
553 {
554  return ( s < low) ? low : ( s > high) ? high : s;
555 }
556 
558 inline Float32 cos( Float32 a) { return std::cos(a); }
560 inline Float64 cos( Float64 a) { return std::cos(a); }
561 
563 inline Float32 degrees( Float32 r) { return r * Float32(180.0/MI_PI); }
565 inline Float64 degrees( Float64 r) { return r * Float64(180.0/MI_PI); }
566 
568 inline Float32 exp2( Float32 s) { return fast_pow2(s); }
570 inline Float64 exp2( Float64 s)
571 {
572  return std::exp(s * 0.69314718055994530941723212145818 /* log(2) */ );
573 }
574 
576 inline Float32 floor( Float32 s) { return std::floor(s); }
578 inline Float64 floor( Float64 s) { return std::floor(s); }
579 
583 inline Float32 fmod( Float32 a, Float32 b) { return std::fmod(a,b); }
587 inline Float64 fmod( Float64 a, Float64 b) { return std::fmod(a,b); }
588 
590 inline Float32 frac( Float32 s)
591 {
592  Float32 dummy;
593  if( s >= 0.0f)
594  return std::modf( s, &dummy);
595  else
596  return 1.0f + std::modf( s, &dummy);
597 }
599 inline Float64 frac( Float64 s)
600 {
601  Float64 dummy;
602  if( s >= 0.0f)
603  return std::modf( s, &dummy);
604  else
605  return 1.0f + std::modf( s, &dummy);
606 }
607 
609 inline bool is_approx_equal(
610  Float32 left,
611  Float32 right,
612  Float32 e)
613 {
614  return abs( left - right ) <= e;
615 }
616 
618 inline bool is_approx_equal(
619  Float64 left,
620  Float64 right,
621  Float64 e)
622 {
623  return abs( left - right ) <= e;
624 }
625 
628  // This implementation tries to use built-in functions if available. For the fallback
629  // method, see Henry Warren: "Hacker's Delight" for reference.
630 #if defined(MI_COMPILER_MSC)
631  unsigned long index;
632  const unsigned char valid = _BitScanReverse(&index, v);
633  return (valid != 0) ? 31 - index : 32;
634 #elif defined(MI_COMPILER_ICC) || defined(MI_COMPILER_GCC)
635  return (v != 0) ? __builtin_clz(v) : 32;
636 #else
637  // use fallback
638  if (v == 0) return 32;
639  Uint32 n = 1;
640  if ((v >> 16) == 0) { n += 16; v <<= 16; };
641  if ((v >> 24) == 0) { n += 8; v <<= 8; };
642  if ((v >> 28) == 0) { n += 4; v <<= 4; };
643  if ((v >> 30) == 0) { n += 2; v <<= 2; };
644  n -= Uint32(v >> 31);
645  return n;
646 #endif
647 }
648 
651  // This implementation tries to use built-in functions if available. For the fallback
652  // method, see Henry Warren: "Hacker's Delight" for reference.
653 #if defined(MI_COMPILER_MSC)
654 #if defined(MI_ARCH_64BIT)
655  unsigned long index;
656  const unsigned char valid = _BitScanReverse64(&index, v);
657  return (valid != 0) ? 63 - index : 64;
658 #else
659  unsigned long index_h, index_l;
660  const unsigned char valid_h = _BitScanReverse(&index_h,(Uint32)(v >> 32));
661  const unsigned char valid_l = _BitScanReverse(&index_l,(Uint32)(v & 0xFFFFFFFF));
662  if (valid_h == 0)
663  return (valid_l != 0) ? 63 - index_l : 64;
664  return 63 - index_h + 32;
665 #endif
666 #elif defined(MI_COMPILER_ICC) || defined(MI_COMPILER_GCC)
667  return (v != 0) ? __builtin_clzll(v) : 64;
668 #else
669  // use fallback, e.g. on Solaris
670  if (v == 0) return 64;
671  Uint32 n = 1;
672  if ((v >> 32) == 0) { n += 32; v <<= 32; };
673  if ((v >> 48) == 0) { n += 16; v <<= 16; };
674  if ((v >> 56) == 0) { n += 8; v <<= 8; };
675  if ((v >> 60) == 0) { n += 4; v <<= 4; };
676  if ((v >> 62) == 0) { n += 2; v <<= 2; };
677  n -= Uint32(v >> 63);
678  return n;
679 #endif
680 }
681 
684 inline Float32 lerp(
685  Float32 s1,
686  Float32 s2,
687  Float32 t)
688 {
689  return s1 * (Float32(1)-t) + s2 * t;
690 }
691 
694 inline Float64 lerp(
695  Float64 s1,
696  Float64 s2,
697  Float64 t)
698 {
699  return s1 * (Float64(1)-t) + s2 * t;
700 }
701 
704 { return std::log(s) * 1.4426950408889634073599246810019f /* log(2) */; }
707 { return std::log(s) * 1.4426950408889634073599246810019 /* log(2) */; }
708 
710 inline Sint32 log2_int( const Uint32 v) { return (v != 0) ? 31 - leading_zeros(v) : 0; }
711 
713 inline Sint32 log2_int( const Uint64 v) { return (v != 0) ? 63 - leading_zeros(v) : 0; }
714 
716 inline Sint32 log2_int( const Float32 v) {
717  return (mi::base::binary_cast<Uint32>(v) >> 23) - 127;
718 }
719 
721 inline Sint32 log2_int( const Float64 v) {
722  return static_cast<Sint32>(mi::base::binary_cast<Uint64>(v) >> 52) - 1023;
723 }
724 
726 template<typename Integer>
727 inline Sint32 log2_int_ceil( const Integer v) {
728  // See Henry Warren: "Hacker's Delight" for reference.
729  return (v > 1) ? log2_int(v - 1) + 1 : 0;
730 }
731 
733 inline Float32 log10( Float32 s) { return std::log10(s); }
735 inline Float64 log10( Float64 s) { return std::log10(s); }
736 
740 inline Float32 modf( Float32 s, Float32& i) { return std::modf( s, &i); }
744 inline Float64 modf( Float64 s, Float64& i) { return std::modf( s, &i); }
745 
747 inline Uint32 pow( Uint32 a, Uint32 b) { return Uint32(std::pow(double(a), int(b))); }
749 inline Uint64 pow( Uint64 a, Uint64 b) { return Uint64(std::pow(double(a), int(b))); }
751 inline Sint32 pow( Sint32 a, Sint32 b) { return Sint32(std::pow(double(a), int(b))); }
753 inline Sint64 pow( Sint64 a, Sint64 b) { return Sint64(std::pow(double(a), int(b))); }
755 inline Float32 pow( Float32 a, Float32 b) { return std::pow( a, b); }
757 inline Float64 pow( Float64 a, Float64 b) { return std::pow( a, b); }
758 
760 inline Float32 radians( Float32 d) { return d * Float32(MI_PI/180.0); }
762 inline Float64 radians( Float64 d) { return d * Float64(MI_PI/180.0); }
763 
765 inline Float32 round( Float32 s) { return std::floor(s + 0.5f); }
767 inline Float64 round( Float64 s) { return std::floor(s + 0.5); }
768 
770 inline Float32 rsqrt( Float32 s) { return 1.0f / std::sqrt(s); }
772 inline Float64 rsqrt( Float64 s) { return 1.0 / std::sqrt(s); }
773 
775 inline Float32 saturate( Float32 s) { return (s < 0.f) ? 0.f : (s > 1.f) ? 1.f : s;}
777 inline Float64 saturate( Float64 s) { return (s < 0.) ? 0. : (s > 1. ) ? 1. : s;}
778 
780 inline Sint8 sign( Sint8 s)
781 { int r = (s < 0 ) ? -1 : (s > 0) ? 1 : 0; return static_cast<Sint8>( r); }
783 inline Sint16 sign( Sint16 s)
784 { int r = (s < 0 ) ? -1 : (s > 0) ? 1 : 0; return static_cast<Sint16>( r); }
786 inline Sint32 sign( Sint32 s) { return (s < 0 ) ? -1 : (s > 0) ? 1 : 0; }
788 inline Sint64 sign( Sint64 s) { return (s < 0 ) ? -1 : (s > 0) ? 1 : 0; }
790 inline Float32 sign( Float32 s) { return (s < 0.f) ? -1.f: (s > 0.f) ? 1.f : 0.f; }
792 inline Float64 sign( Float64 s) { return (s < 0. ) ? -1. : (s > 0.) ? 1. : 0.; }
793 
795 inline bool sign_bit( Sint8 s) { return s < 0; }
797 inline bool sign_bit( Sint16 s) { return s < 0; }
799 inline bool sign_bit( Sint32 s) { return s < 0; }
801 inline bool sign_bit( Sint64 s) { return s < 0; }
802 
807 inline bool sign_bit( Float32 s)
808 {
809  return (base::binary_cast<Uint32>(s) & (1U << 31)) != 0U;
810 }
811 
816 inline bool sign_bit( Float64 s)
817 {
818  return (base::binary_cast<Uint64>(s) & (1ULL << 63)) != 0ULL;
819 }
820 
821 #if (__cplusplus < 201103L)
822 inline bool isnan MI_PREVENT_MACRO_EXPAND (const Float32 x)
826 {
827  // interpret as Uint32 value
828  const Uint32 f = base::binary_cast<Uint32>(x);
829 
830  // check bit pattern
831  return (f << 1) > 0xFF000000U; // shift sign bit, 8bit exp == 2^8-1, fraction != 0
832 }
833 
837 inline bool isnan MI_PREVENT_MACRO_EXPAND (const Float64 x)
838 {
839  // interpret as Uint64 value
840  const Uint64 f = base::binary_cast<Uint64>(x);
841 
842  return (f << 1) > 0xFFE0000000000000ULL; // shift sign bit, 11bit exp == 2^11-1, fraction != 0
843 }
844 #else
845 using std::isnan;
846 #endif
847 
848 
853 {
854  const Uint32 exponent_mask = 0x7F800000; // 8 bit exponent
855  const Uint32 fraction_mask = 0x7FFFFF; // 23 bit fraction
856 
857  // interpret as Uint32 value
858  const Uint32 f = base::binary_cast<Uint32>(x);
859 
860  // check bit pattern
861  return ((f & exponent_mask) == exponent_mask) && // exp == 2^8 - 1
862  ((f & fraction_mask) == 0); // fraction == 0
863 }
864 
869 {
870  const Uint64 exponent_mask = 0x7FF0000000000000ULL; // 11 bit exponent
871  const Uint64 fraction_mask = 0xFFFFFFFFFFFFFULL; // 52 bit fraction
872 
873  // interpret as Uint64 value
874  const Uint64 f = base::binary_cast<Uint64>(x);
875 
876  // check bit pattern
877  return ((f & exponent_mask) == exponent_mask) && // exp == 2^11 - 1
878  ((f & fraction_mask) == 0); // fraction == 0
879 }
880 
881 
882 #if (__cplusplus < 201103L)
883 inline bool isfinite MI_PREVENT_MACRO_EXPAND (const Float32 x)
889 {
890  const Uint32 exponent_mask = 0x7F800000; // 8 bit exponent
891 
892  // interpret as Uint32 value
893  const Uint32 f = base::binary_cast<Uint32>(x);
894 
895  // check exponent bits
896  return ((f & exponent_mask) != exponent_mask); // exp != 2^8 - 1
897 }
898 
904 inline bool isfinite MI_PREVENT_MACRO_EXPAND (const Float64 x)
905 {
906  const Uint64 exponent_mask = 0x7FF0000000000000ULL; // 11 bit exponent
907 
908  // interpret as Uint64 value
909  const Uint64 f = base::binary_cast<Uint64>(x);
910 
911  // check exponent bits
912  return ((f & exponent_mask) != exponent_mask); // exp != 2^11 - 1
913 }
914 #else
915 using std::isfinite;
916 #endif
917 
918 
920 inline Float32 sin( Float32 a) { return std::sin(a); }
922 inline Float64 sin( Float64 a) { return std::sin(a); }
923 
927 inline void sincos( Float32 a, Float32& s, Float32& c)
928 {
929  s = std::sin(a);
930  c = std::cos(a);
931 }
935 inline void sincos( Float64 a, Float64& s, Float64& c)
936 {
937  s = std::sin(a);
938  c = std::cos(a);
939 }
940 
946 {
947  if(x < a)
948  return 0.0f;
949  if(b < x)
950  return 1.0f;
951  Float32 t = (x - a) / (b - a);
952  return t * t * (3.0f - 2.0f * t);
953 }
959 {
960  if(x < a)
961  return 0.0;
962  if(b < x)
963  return 1.0;
964  Float64 t = (x - a) / (b - a);
965  return t * t * (3.0 - 2.0 * t);
966 }
967 
969 inline Float32 sqrt( Float32 s) { return std::sqrt(s); }
971 inline Float64 sqrt( Float64 s) { return std::sqrt(s); }
972 
974 inline Float32 step( Float32 a, Float32 x) { return (x < a) ? 0.0f : 1.0f; }
976 inline Float64 step( Float64 a, Float64 x) { return (x < a) ? 0.0 : 1.0; }
977 
979 inline Float32 tan( Float32 a) { return std::tan(a); }
981 inline Float64 tan( Float64 a) { return std::tan(a); }
982 
983 
985 inline void to_rgbe( const Float32 color[3], Uint32& rgbe)
986 {
987  Float32 c[3];
988  c[0] = mi::base::max( color[0], 0.0f);
989  c[1] = mi::base::max( color[1], 0.0f);
990  c[2] = mi::base::max( color[2], 0.0f);
991 
992  const Float32 max = mi::base::max( mi::base::max( c[0], c[1]), c[2]);
993 
994  // should actually be -126 or even -128, but avoid precision problems / denormalized numbers
995  if( max <= 7.5231631727e-37f) // ~2^(-120)
996  rgbe = 0;
997  else if( max >= 1.7014118346046923173168730371588e+38f) // 2^127
998  rgbe = 0xFFFFFFFFu;
999  else {
1000  const Uint32 e = base::binary_cast<Uint32>( max) & 0x7F800000u;
1001  const Float32 v = base::binary_cast<Float32>( 0x82800000u - e);
1002 
1003  rgbe = Uint32( c[0] * v)
1004  | (Uint32( c[1] * v) << 8)
1005  | (Uint32( c[2] * v) << 16)
1006  | (e * 2 + (2 << 24));
1007  }
1008 }
1009 
1011 inline void to_rgbe( const Float32 color[3], Uint8 rgbe[4])
1012 {
1013  Float32 c[3];
1014  c[0] = mi::base::max( color[0], 0.0f);
1015  c[1] = mi::base::max( color[1], 0.0f);
1016  c[2] = mi::base::max( color[2], 0.0f);
1017 
1018  const Float32 max = mi::base::max( mi::base::max( c[0], c[1]), c[2]);
1019 
1020  // should actually be -126 or even -128, but avoid precision problems / denormalized numbers
1021  if( max <= 7.5231631727e-37f) // ~2^(-120)
1022  rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
1023  else if( max >= 1.7014118346046923173168730371588e+38f) // 2^127
1024  rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 255;
1025  else {
1026  const Uint32 e = base::binary_cast<Uint32>( max) & 0x7F800000u;
1027  const Float32 v = base::binary_cast<Float32>( 0x82800000u - e);
1028 
1029  rgbe[0] = Uint8( c[0] * v);
1030  rgbe[1] = Uint8( c[1] * v);
1031  rgbe[2] = Uint8( c[2] * v);
1032  rgbe[3] = Uint8( (e >> 23) + 2);
1033  }
1034 }
1035 
1037 inline void from_rgbe( const Uint8 rgbe[4], Float32 color[3])
1038 {
1039  if( rgbe[3] == 0) {
1040  color[0] = color[1] = color[2] = 0.0f;
1041  return;
1042  }
1043 
1044  const Uint32 e = (static_cast<Uint32>( rgbe[3]) << 23) - 0x800000u;
1045  const Float32 v = base::binary_cast<Float32>( e);
1046  const Float32 c = static_cast<Float32>( 1.0 - 0.5/256.0) * v;
1047 
1048  color[0] = base::binary_cast<Float32>( e | (static_cast<Uint32>( rgbe[0]) << 15)) - c;
1049  color[1] = base::binary_cast<Float32>( e | (static_cast<Uint32>( rgbe[1]) << 15)) - c;
1050  color[2] = base::binary_cast<Float32>( e | (static_cast<Uint32>( rgbe[2]) << 15)) - c;
1051 }
1052 
1054 inline void from_rgbe( const Uint32 rgbe, Float32 color[3])
1055 {
1056  const Uint32 rgbe3 = rgbe & 0xFF000000u;
1057  if( rgbe3 == 0) {
1058  color[0] = color[1] = color[2] = 0.0f;
1059  return;
1060  }
1061 
1062  const Uint32 e = (rgbe3 >> 1) - 0x800000u;
1063  const Float32 v = base::binary_cast<Float32>( e);
1064  const Float32 c = static_cast<Float32>( 1.0 - 0.5/256.0) * v;
1065 
1066  color[0] = base::binary_cast<Float32>( e | ((rgbe << 15) & 0x7F8000u)) - c;
1067  color[1] = base::binary_cast<Float32>( e | ((rgbe << 7) & 0x7F8000u)) - c;
1068  color[2] = base::binary_cast<Float32>( e | ((rgbe >> 1) & 0x7F8000u)) - c;
1069 }
1070 
1071 
1072 //------ Generic Vector Algorithms --------------------------------------------
1073 
1074 // overloads for 1D vectors (scalars)
1075 
1077 inline Sint32 dot( Sint32 a, Sint32 b) { return a * b; }
1079 inline Float32 dot( Float32 a, Float32 b) { return a * b; }
1081 inline Float64 dot( Float64 a, Float64 b) { return a * b; }
1082 
1084 template <class V>
1085 inline typename V::value_type dot( const V& lhs, const V& rhs)
1086 {
1087  typename V::value_type v(0);
1088  for( Size i(0u); i < V::SIZE; ++i)
1089  v += lhs.get(i) * rhs.get(i);
1090  return v;
1091 }
1092 
1094 template <class V>
1095 inline typename V::value_type square_length( const V& v)
1096 {
1097  return dot( v, v);
1098 }
1099 
1100 // base case for scalars
1101 
1103 inline Float32 length( Float32 a) { return abs(a); }
1105 inline Float64 length( Float64 a) { return abs(a); }
1106 
1107 
1111 template <class V>
1112 inline typename V::value_type length( const V& v)
1113 {
1114  return sqrt( square_length(v));
1115 }
1116 
1118 template <class V>
1119 inline typename V::value_type square_euclidean_distance( const V& lhs, const V& rhs)
1120 {
1121  return square_length( lhs - rhs);
1122 }
1123 
1127 template <class V>
1128 inline typename V::value_type euclidean_distance(
1129  const V& lhs, const V& rhs)
1130 {
1131  return length( lhs - rhs);
1132 }
1133 
1135 template <class V>
1136 inline void set_bounds( V& v, const V& low, const V& high)
1137 {
1138  for( Size i(0u); i < V::SIZE; ++i)
1139  v[i] = min MI_PREVENT_MACRO_EXPAND (
1140  max MI_PREVENT_MACRO_EXPAND (v.get(i), low.get(i)), high.get(i));
1141 }
1142 
1145 template <class V>
1146 inline bool is_equal( const V& lhs, const V& rhs)
1147 {
1148  for( Size i(0u); i < V::SIZE; ++i)
1149  if( ! (lhs.get(i) == rhs.get(i)))
1150  return false;
1151  return true;
1152 }
1153 
1156 template <class V>
1157 inline bool is_not_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 true;
1162  return false;
1163 }
1164 
1169 template <class V>
1170 inline bool lexicographically_less( const V& lhs, const V& rhs)
1171 {
1172  for( Size i(0u); i < V::SIZE-1; ++i) {
1173  if( lhs.get(i) < rhs.get(i))
1174  return true;
1175  if( lhs.get(i) > rhs.get(i))
1176  return false;
1177  }
1178  return lhs.get(V::SIZE-1) < rhs.get(V::SIZE-1);
1179 }
1180 
1185 template <class V>
1186 inline bool lexicographically_less_or_equal( const V& lhs, const V& rhs)
1187 {
1188  for( Size i(0u); i < V::SIZE-1; ++i) {
1189  if( lhs.get(i) < rhs.get(i))
1190  return true;
1191  if( lhs.get(i) > rhs.get(i))
1192  return false;
1193  }
1194  return lhs.get(V::SIZE-1) <= rhs.get(V::SIZE-1);
1195 }
1196 
1201 template <class V>
1202 inline bool lexicographically_greater( const V& lhs, const V& rhs)
1203 {
1204  for( Size i(0u); i < V::SIZE-1; ++i) {
1205  if( lhs.get(i) > rhs.get(i))
1206  return true;
1207  if( lhs.get(i) < rhs.get(i))
1208  return false;
1209  }
1210  return lhs.get(V::SIZE-1) > rhs.get(V::SIZE-1);
1211 }
1212 
1217 template <class V>
1218 inline bool lexicographically_greater_or_equal( const V& lhs, const V& rhs)
1219 {
1220  for( Size i(0u); i < V::SIZE-1; ++i) {
1221  if( lhs.get(i) > rhs.get(i))
1222  return true;
1223  if( lhs.get(i) < rhs.get(i))
1224  return false;
1225  }
1226  return lhs.get(V::SIZE-1) >= rhs.get(V::SIZE-1);
1227 }
1228 
1238 template <class V>
1239 inline Comparison_result lexicographically_compare( const V& lhs, const V& rhs)
1240 {
1241  for( Size i(0u); i < V::SIZE; ++i) {
1242  Comparison_result result = three_valued_compare( lhs.get(i), rhs.get(i));
1243  if( result != EQUAL)
1244  return result;
1245  }
1246  return EQUAL;
1247 }
1248  // end group mi_math_function
1250 
1251 } // namespace math
1252 
1253 } // namespace mi
1254 
1255 #endif // MI_MATH_FUNCTION_H