|
1 /* |
|
2 * Copyright 2011 Google Inc. |
|
3 * |
|
4 * Use of this source code is governed by a BSD-style license that can be |
|
5 * found in the LICENSE file. |
|
6 */ |
|
7 |
|
8 #include "SkFloatBits.h" |
|
9 #include "SkMathPriv.h" |
|
10 |
|
11 /****************************************************************************** |
|
12 SkFloatBits_toInt[Floor, Round, Ceil] are identical except for what they |
|
13 do right before they return ... >> exp; |
|
14 Floor - adds nothing |
|
15 Round - adds 1 << (exp - 1) |
|
16 Ceil - adds (1 << exp) - 1 |
|
17 |
|
18 Floor and Cast are very similar, but Cast applies its sign after all other |
|
19 computations on value. Also, Cast does not need to check for negative zero, |
|
20 as that value (0x80000000) "does the right thing" for Ceil. Note that it |
|
21 doesn't for Floor/Round/Ceil, hence the explicit check. |
|
22 ******************************************************************************/ |
|
23 |
|
24 #define EXP_BIAS (127+23) |
|
25 #define MATISSA_MAGIC_BIG (1 << 23) |
|
26 |
|
27 static inline int unpack_exp(uint32_t packed) { |
|
28 return (packed << 1 >> 24); |
|
29 } |
|
30 |
|
31 #if 0 |
|
32 // the ARM compiler generates an extra BIC, so I use the dirty version instead |
|
33 static inline int unpack_matissa(uint32_t packed) { |
|
34 // we could mask with 0x7FFFFF, but that is harder for ARM to encode |
|
35 return (packed & ~0xFF000000) | MATISSA_MAGIC_BIG; |
|
36 } |
|
37 #endif |
|
38 |
|
39 // returns the low 24-bits, so we need to OR in the magic_bit afterwards |
|
40 static inline int unpack_matissa_dirty(uint32_t packed) { |
|
41 return packed & ~0xFF000000; |
|
42 } |
|
43 |
|
44 // same as (int)float |
|
45 int32_t SkFloatBits_toIntCast(int32_t packed) { |
|
46 int exp = unpack_exp(packed) - EXP_BIAS; |
|
47 int value = unpack_matissa_dirty(packed) | MATISSA_MAGIC_BIG; |
|
48 |
|
49 if (exp >= 0) { |
|
50 if (exp > 7) { // overflow |
|
51 value = SK_MaxS32; |
|
52 } else { |
|
53 value <<= exp; |
|
54 } |
|
55 } else { |
|
56 exp = -exp; |
|
57 if (exp > 25) { // underflow |
|
58 exp = 25; |
|
59 } |
|
60 value >>= exp; |
|
61 } |
|
62 return SkApplySign(value, SkExtractSign(packed)); |
|
63 } |
|
64 |
|
65 // same as (int)floor(float) |
|
66 int32_t SkFloatBits_toIntFloor(int32_t packed) { |
|
67 // curse you negative 0 |
|
68 if ((packed << 1) == 0) { |
|
69 return 0; |
|
70 } |
|
71 |
|
72 int exp = unpack_exp(packed) - EXP_BIAS; |
|
73 int value = unpack_matissa_dirty(packed) | MATISSA_MAGIC_BIG; |
|
74 |
|
75 if (exp >= 0) { |
|
76 if (exp > 7) { // overflow |
|
77 value = SK_MaxS32; |
|
78 } else { |
|
79 value <<= exp; |
|
80 } |
|
81 // apply the sign after we check for overflow |
|
82 return SkApplySign(value, SkExtractSign(packed)); |
|
83 } else { |
|
84 // apply the sign before we right-shift |
|
85 value = SkApplySign(value, SkExtractSign(packed)); |
|
86 exp = -exp; |
|
87 if (exp > 25) { // underflow |
|
88 exp = 25; |
|
89 } |
|
90 // int add = 0; |
|
91 return value >> exp; |
|
92 } |
|
93 } |
|
94 |
|
95 // same as (int)floor(float + 0.5) |
|
96 int32_t SkFloatBits_toIntRound(int32_t packed) { |
|
97 // curse you negative 0 |
|
98 if ((packed << 1) == 0) { |
|
99 return 0; |
|
100 } |
|
101 |
|
102 int exp = unpack_exp(packed) - EXP_BIAS; |
|
103 int value = unpack_matissa_dirty(packed) | MATISSA_MAGIC_BIG; |
|
104 |
|
105 if (exp >= 0) { |
|
106 if (exp > 7) { // overflow |
|
107 value = SK_MaxS32; |
|
108 } else { |
|
109 value <<= exp; |
|
110 } |
|
111 // apply the sign after we check for overflow |
|
112 return SkApplySign(value, SkExtractSign(packed)); |
|
113 } else { |
|
114 // apply the sign before we right-shift |
|
115 value = SkApplySign(value, SkExtractSign(packed)); |
|
116 exp = -exp; |
|
117 if (exp > 25) { // underflow |
|
118 exp = 25; |
|
119 } |
|
120 int add = 1 << (exp - 1); |
|
121 return (value + add) >> exp; |
|
122 } |
|
123 } |
|
124 |
|
125 // same as (int)ceil(float) |
|
126 int32_t SkFloatBits_toIntCeil(int32_t packed) { |
|
127 // curse you negative 0 |
|
128 if ((packed << 1) == 0) { |
|
129 return 0; |
|
130 } |
|
131 |
|
132 int exp = unpack_exp(packed) - EXP_BIAS; |
|
133 int value = unpack_matissa_dirty(packed) | MATISSA_MAGIC_BIG; |
|
134 |
|
135 if (exp >= 0) { |
|
136 if (exp > 7) { // overflow |
|
137 value = SK_MaxS32; |
|
138 } else { |
|
139 value <<= exp; |
|
140 } |
|
141 // apply the sign after we check for overflow |
|
142 return SkApplySign(value, SkExtractSign(packed)); |
|
143 } else { |
|
144 // apply the sign before we right-shift |
|
145 value = SkApplySign(value, SkExtractSign(packed)); |
|
146 exp = -exp; |
|
147 if (exp > 25) { // underflow |
|
148 exp = 25; |
|
149 } |
|
150 int add = (1 << exp) - 1; |
|
151 return (value + add) >> exp; |
|
152 } |
|
153 } |
|
154 |
|
155 float SkIntToFloatCast(int32_t value) { |
|
156 if (0 == value) { |
|
157 return 0; |
|
158 } |
|
159 |
|
160 int shift = EXP_BIAS; |
|
161 |
|
162 // record the sign and make value positive |
|
163 int sign = SkExtractSign(value); |
|
164 value = SkApplySign(value, sign); |
|
165 |
|
166 if (value >> 24) { // value is too big (has more than 24 bits set) |
|
167 int bias = 8 - SkCLZ(value); |
|
168 SkDebugf("value = %d, bias = %d\n", value, bias); |
|
169 SkASSERT(bias > 0 && bias < 8); |
|
170 value >>= bias; // need to round? |
|
171 shift += bias; |
|
172 } else { |
|
173 int zeros = SkCLZ(value << 8); |
|
174 SkASSERT(zeros >= 0 && zeros <= 23); |
|
175 value <<= zeros; |
|
176 shift -= zeros; |
|
177 } |
|
178 |
|
179 // now value is left-aligned to 24 bits |
|
180 SkASSERT((value >> 23) == 1); |
|
181 SkASSERT(shift >= 0 && shift <= 255); |
|
182 |
|
183 SkFloatIntUnion data; |
|
184 data.fSignBitInt = (sign << 31) | (shift << 23) | (value & ~MATISSA_MAGIC_BIG); |
|
185 return data.fFloat; |
|
186 } |
|
187 |
|
188 float SkIntToFloatCast_NoOverflowCheck(int32_t value) { |
|
189 if (0 == value) { |
|
190 return 0; |
|
191 } |
|
192 |
|
193 int shift = EXP_BIAS; |
|
194 |
|
195 // record the sign and make value positive |
|
196 int sign = SkExtractSign(value); |
|
197 value = SkApplySign(value, sign); |
|
198 |
|
199 int zeros = SkCLZ(value << 8); |
|
200 value <<= zeros; |
|
201 shift -= zeros; |
|
202 |
|
203 SkFloatIntUnion data; |
|
204 data.fSignBitInt = (sign << 31) | (shift << 23) | (value & ~MATISSA_MAGIC_BIG); |
|
205 return data.fFloat; |
|
206 } |