HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UT_SafeFloat.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: UT_SafeFloat.h (UT Library, C++)
7  *
8  * COMMENTS: Functions for packing integers into "safe" float values,
9  * i.e. not denormal, infinite, or NaN; just normal values.
10  *
11  * - Integers in the range
12  * abs(i) <= (2^24) = 16,777,216
13  * will be represented exactly by the floats of the same value.
14  * - Integers in the range
15  * 16,777,216 < abs(i) < (2^24) + 104*(2^23) = 889,192,448
16  * will be represented by larger, non-infinite floats.
17  * - Integers in the range
18  * 889,192,448 <= abs(i) < (2^24) + 230*(2^23) = 1,946,157,056
19  * will be represented by small, non-denormal floats.
20  * - Any other integers, abs(i) >= 1,946,157,056, will not be
21  * represented correctly.
22  */
23 
24 #ifndef __UT_SafeFloat__
25 #define __UT_SafeFloat__
26 
27 #include <SYS/SYS_Types.h>
28 #include "UT_Assert.h"
29 
30 static inline float
31 UTpackIntToSafeFloat(int input)
32 {
33  SYS_FPRealUnionF output;
34  // If -(2^24) <= input <= (2^24), just convert directly,
35  // so that the float value will be the same as the int value.
36  if (SYSabs(input) <= (1 << (output.MANTISSA_BITS+1)))
37  {
38  UT_ASSERT_P(int(float(input)) == input);
39  return float(input);
40  }
41 
42  // Else, things get more complicated.
43 
44  // Add in the sign bit.
45  output.uval = 0;
46  if (input < 0)
47  {
48  output.uval |= (1 << (output.MANTISSA_BITS+output.EXPONENT_BITS));
49  input = -input;
50  }
51 
52  // Subtract off 2^24.
53  input -= (1 << (output.MANTISSA_BITS+1));
54 
55  // If the number is small enough, use large numbers first, so that
56  // we'll have valid integers for the first while.
57  const int zeroexp = (1 << (output.EXPONENT_BITS-1)) - 1; // 0 (excess 127) = 127
58  const int infiniteexp = (1 << output.EXPONENT_BITS) - 1; // 255
59  const int startexp = zeroexp + (output.MANTISSA_BITS+1); // 24 (excess 127) = 151
60  const int explength = infiniteexp - startexp; // 255-151 = 104
61  const int length = explength*(1 << output.MANTISSA_BITS);// 104*(2^23)
62  const int startencoded = (startexp << output.MANTISSA_BITS);
63 
64  if (input < length)
65  {
66  output.uval |= (startencoded + input);
67  return output.fval;
68  }
69 
70  // Subtract off length.
71  input -= length;
72 
73  // Avoid denormal numbers by adding one to the exponent
74  input += (1 << output.MANTISSA_BITS);
75 
76  // Check for overflowing back around to 1
77  const int oneencoded = (zeroexp << output.MANTISSA_BITS);
78  UT_ASSERT_P(input < oneencoded);
79  // Clamp if went past maximum
80  // (Even though this doesn't necessarily make sense, it may avoid a
81  // crash if a user hits it, and we have an assert for it above.)
82  if (input >= oneencoded)
83  input = oneencoded - 1;
84 
85  output.uval |= input;
86  return output.fval;
87 }
88 
89 static inline int
90 UTunpackIntFromSafeFloat(float input)
91 {
92  // Special case for zero, for simplicity
93  if (input == 0)
94  return 0;
95 
96  SYS_FPRealUnionF output;
97  output.fval = input;
98 
99  bool negative = (output.uval >> (output.MANTISSA_BITS+output.EXPONENT_BITS));
100  output.uval &= ~(1 << (output.MANTISSA_BITS+output.EXPONENT_BITS));
101 
102  const int zeroexp = (1 << (output.EXPONENT_BITS-1)) - 1; // 0 (excess 127) = 127
103  const int infiniteexp = (1 << output.EXPONENT_BITS) - 1; // 255
104  const int startexp = zeroexp + (output.MANTISSA_BITS+1); // 24 (excess 127) = 151
105  const int explength = infiniteexp - startexp; // 255-151 = 104
106  const int length = explength*(1 << output.MANTISSA_BITS);// 104*(2^23)
107  const int startencoded = (startexp << output.MANTISSA_BITS);
108  const int oneencoded = (zeroexp << output.MANTISSA_BITS);
109 
110  // If we're in the int block, just convert to int
111  if (output.uval >= oneencoded && output.uval <= startencoded)
112  {
113  UT_ASSERT_P(float(int(input)) == input);
114  return int(input);
115  }
116 
117  if (output.uval > startencoded)
118  {
119  output.uval -= startencoded;
120  // Check for infinite/NaN numbers
121  UT_ASSERT_P(output.uval < length);
122  // Clamp to just below infinite if infinite or NaN
123  if (output.uval >= length)
124  output.uval = length-1;
125  output.uval += (1 << (output.MANTISSA_BITS+1));
126  return negative ? -output.ival : output.ival;
127  }
128 
129  // Check for denormal numbers or overflowing back around to 1
130  UT_ASSERT_P(output.uval >= (1 << output.MANTISSA_BITS) && output.uval < oneencoded);
131  // Clamp if denormal or went past maximum
132  // (Even though this doesn't necessarily make sense, it may avoid a
133  // crash if a user hits it, and we have an assert for it above.)
134  if (output.uval < (1 << output.MANTISSA_BITS))
135  return 0;
136  if (output.uval >= oneencoded)
137  output.uval = oneencoded - 1;
138 
139  // Undo adjustments from UTpackIntFromSafeFloat in denormal case
140  output.uval += length+((1 << (output.MANTISSA_BITS+1))-(1 << output.MANTISSA_BITS));
141 
142  if (negative)
143  output.ival = -output.ival;
144 
145  return output.ival;
146 }
147 
148 #endif
typedef int(APIENTRYP RE_PFNGLXSWAPINTERVALSGIPROC)(int)
T negative(const T &val)
Return the unary negation of the given value.
Definition: Math.h:128
#define SYSabs(a)
Definition: SYS_Math.h:1540
GLuint GLsizei GLsizei * length
Definition: glcorearb.h:795
#define UT_ASSERT_P(ZZ)
Definition: UT_Assert.h:155