Simple Graphics Library 1.0.0.0
Runtime-independent image processing primitives
Loading...
Searching...
No Matches
generic.h
1/*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright (c) 2025 Dylan Hong
5 *
6 * This code is released under the MIT License.
7 * For conditions of distribution and use, see the LICENSE file.
8 */
9#ifndef SGL_FIXED_POINT_GENERIC_H_
10#define SGL_FIXED_POINT_GENERIC_H_
11
24
26#define SGL_Q11_FRAC_BITS (11U)
28#define SGL_Q11_ONE (2048)
30#define SGL_Q11_HALF (1024)
32#define SGL_Q11_MASK (2047U)
34#define SGL_Q16_FRAC_BITS (16U)
36#define SGL_Q16_ONE (65536)
38#define SGL_Q16_HALF (32768)
40#define SGL_Q16_MASK (65535U)
42#define SGL_FIXED_I64_BITS (64U)
44#define SGL_FIXED_INT32_MAX (2147483647)
46#define SGL_FIXED_INT32_MIN (-2147483647 - 1)
48#define SGL_FIXED_INT16_MAX (32767)
50#define SGL_FIXED_INT16_MIN (-32767 - 1)
51
58 sgl_int64_t value)
59{
60 sgl_int32_t result;
61
62 if (value > (sgl_int64_t)SGL_FIXED_INT32_MAX) {
63 result = SGL_FIXED_INT32_MAX;
64 }
65 else if (value < SGL_FIXED_INT32_MIN) {
66 result = SGL_FIXED_INT32_MIN;
67 }
68 else {
69 result = (sgl_int32_t)value;
70 }
71
72 return result;
73}
74
81 sgl_int32_t value)
82{
83 sgl_int16_t result;
84
85 if (value > SGL_FIXED_INT16_MAX) {
86 result = SGL_FIXED_INT16_MAX;
87 }
88 else if (value < SGL_FIXED_INT16_MIN) {
89 result = SGL_FIXED_INT16_MIN;
90 }
91 else {
92 result = (sgl_int16_t)value;
93 }
94
95 return result;
96}
97
109 sgl_int64_t value,
110 sgl_uint32_t shift)
111{
112 sgl_int64_t result = 0;
113
114 if (shift < SGL_FIXED_I64_BITS) {
115 sgl_uint64_t magnitude;
116 sgl_uint64_t shifted;
117
118 if (value < 0) {
119 magnitude = (sgl_uint64_t)(-(value + 1)) + 1U;
120 shifted = magnitude >> shift;
121 result = -(sgl_int64_t)shifted;
122 }
123 else {
124 magnitude = (sgl_uint64_t)value;
125 shifted = magnitude >> shift;
126 result = (sgl_int64_t)shifted;
127 }
128 }
129
130 return result;
131}
132
140 sgl_int64_t value,
141 sgl_uint32_t shift)
142{
143 sgl_int64_t result = 0;
144
145 if (shift < SGL_FIXED_I64_BITS) {
146 sgl_uint64_t magnitude;
147 sgl_uint64_t shifted;
148
149 if (value < 0) {
150 magnitude = (sgl_uint64_t)(-(value + 1)) + 1U;
151 /* The low-bit mask rounds any negative remainder toward -infinity. */
152 magnitude += (((sgl_uint64_t)1U << shift) - 1U);
153 shifted = magnitude >> shift;
154 result = -(sgl_int64_t)shifted;
155 }
156 else {
157 magnitude = (sgl_uint64_t)value;
158 shifted = magnitude >> shift;
159 result = (sgl_int64_t)shifted;
160 }
161 }
162 else if (value < 0) {
163 result = -1;
164 }
165 else {
166 result = 0;
167 }
168
169 return result;
170}
171
178{
179 sgl_int64_t scaled;
180 sgl_q11_ext_t result;
181
182 scaled = (sgl_int64_t)value * (sgl_int64_t)SGL_Q11_ONE;
183 result = sgl_fixed_clamp_i64_to_i32(scaled);
184
185 return result;
186}
187
194{
195 sgl_q11_ext_t result;
196
197 /* Q11 -> integer: remove eleven fractional bits. */
200
201 return result;
202}
203
210{
211 sgl_q11_ext_t integer_part;
212 sgl_q11_ext_t result;
213
214 integer_part = sgl_q11_get_int_part(value);
215 result = value - (integer_part * SGL_Q11_ONE);
216
217 return result;
218}
219
226{
227 sgl_int64_t rounded;
228 sgl_q11_ext_t result;
229
230 rounded = (sgl_int64_t)value + (sgl_int64_t)SGL_Q11_HALF;
231 result = sgl_fixed_clamp_i64_to_i32(rounded);
232
233 return result;
234}
235
242{
243 sgl_q11_ext_t result;
244
245 if (value >= 0) {
246 sgl_uint32_t shifted;
247
248 /* Q11 -> integer: remove eleven fractional bits. */
249 shifted = (sgl_uint32_t)value >> SGL_Q11_FRAC_BITS;
250 result = (sgl_q11_ext_t)shifted;
251 }
252 else {
253 sgl_uint32_t magnitude;
254
255 magnitude = (sgl_uint32_t)(-(value + 1)) + 1U;
256 /* Add a Q11 mask before shifting to implement floor for negatives. */
257 magnitude = (magnitude + SGL_Q11_MASK) >> SGL_Q11_FRAC_BITS;
258 result = -(sgl_q11_ext_t)magnitude;
259 }
260
261 return result;
262}
263
271{
272 sgl_q11_ext_t prod;
273 sgl_q11_ext_t shifted;
274 sgl_q11_t result;
275
276 prod = (sgl_q11_ext_t)a * (sgl_q11_ext_t)b; /* Q22 = Q11 x Q11. */
277 prod = sgl_q11_round_up(prod);
278 /* Remove eleven fractional product bits to restore Q11. */
279 shifted = sgl_q11_shift_down(prod);
280 result = sgl_fixed_clamp_i32_to_i16(shifted);
281
282 return result;
283}
284
292{
293 sgl_int64_t prod;
294 sgl_int64_t shifted;
295 sgl_q11_ext_t result;
296
297 prod = (sgl_int64_t)a * (sgl_int64_t)b; /* Q22 = Q11 x Q11. */
298 prod += (sgl_int64_t)SGL_Q11_HALF;
299 /* Remove eleven fractional product bits to restore Q11. */
301 result = sgl_fixed_clamp_i64_to_i32(shifted);
302
303 return result;
304}
305
312{
313 sgl_q16_ext_t result;
314
315 result = (sgl_q16_ext_t)value * (sgl_q16_ext_t)SGL_Q16_ONE;
316
317 return result;
318}
319
326 sgl_q16_ext_t value)
327{
328 sgl_uint64_t magnitude;
329 sgl_int32_t result;
330
331 if (value < 0) {
332 magnitude = (sgl_uint64_t)(-(value + 1)) + 1U;
333 /* Add half, then remove sixteen fractional bits for nearest rounding. */
334 magnitude += (sgl_uint64_t)SGL_Q16_HALF;
335 magnitude >>= SGL_Q16_FRAC_BITS;
336 if (magnitude >= ((sgl_uint64_t)SGL_FIXED_INT32_MAX + 1U)) {
337 result = SGL_FIXED_INT32_MIN;
338 }
339 else {
340 result = -(sgl_int32_t)magnitude;
341 }
342 }
343 else {
344 magnitude = (sgl_uint64_t)value;
345 /* Add half, then remove sixteen fractional bits for nearest rounding. */
346 magnitude += (sgl_uint64_t)SGL_Q16_HALF;
347 magnitude >>= SGL_Q16_FRAC_BITS;
348 if (magnitude > (sgl_uint64_t)SGL_FIXED_INT32_MAX) {
349 result = SGL_FIXED_INT32_MAX;
350 }
351 else {
352 result = (sgl_int32_t)magnitude;
353 }
354 }
355
356 return result;
357}
358
365{
366 sgl_uint8_t u8_val = (sgl_uint8_t)val;
367
368 /* Any set bit outside the low eight bits means val is outside 0..255. */
369 if ((val & ~0xFF) != 0) {
370 if (val < 0) {
371 u8_val = 0U;
372 }
373 else {
374 u8_val = 255U;
375 }
376 }
377
378 return u8_val;
379}
380
383#endif /* !SGL_FIXED_POINT_GENERIC_H_ */
#define SGL_ALWAYS_INLINE
Requests compiler-enforced inlining.
static sgl_uint8_t sgl_clamp_u8_i32(sgl_int32_t val)
Saturates a signed 32-bit channel value to 0 through 255.
Definition generic.h:364
static sgl_int16_t sgl_fixed_clamp_i32_to_i16(sgl_int32_t value)
Saturates a signed 32-bit value to the signed 16-bit range.
Definition generic.h:80
static sgl_int64_t sgl_fixed_floor_pow2_i64(sgl_int64_t value, sgl_uint32_t shift)
Divides by a power of two while rounding toward negative infinity.
Definition generic.h:139
#define SGL_Q16_ONE
Q16 representation of 1.0 (1 << 16).
Definition generic.h:36
static sgl_q11_t sgl_q11_mul(sgl_q11_t a, sgl_q11_t b)
Multiplies two Q11 values with rounding and saturation.
Definition generic.h:270
static sgl_q11_ext_t sgl_int_to_q11(sgl_q11_ext_t value)
Converts an integer to extended Q11 with saturation.
Definition generic.h:177
#define SGL_FIXED_INT16_MIN
Minimum signed 16-bit value without standard-library constants.
Definition generic.h:50
static sgl_q11_ext_t sgl_q11_get_int_part(sgl_q11_ext_t value)
Extracts the integer part of an extended Q11 value.
Definition generic.h:193
sgl_int64_t sgl_q16_ext_t
Extended signed Q16 value stored in 64 bits.
Definition generic.h:23
#define SGL_Q11_FRAC_BITS
Number of fractional bits in a Q11 value.
Definition generic.h:26
static sgl_q11_ext_t sgl_q11_round_up(sgl_q11_ext_t value)
Adds the Q11 half-unit used before rounded conversion.
Definition generic.h:225
static sgl_int32_t sgl_q16_round_to_int32(sgl_q16_ext_t value)
Rounds an extended Q16 value to the nearest signed 32-bit integer.
Definition generic.h:325
#define SGL_FIXED_INT32_MAX
Maximum signed 32-bit value without standard-library constants.
Definition generic.h:44
#define SGL_Q16_HALF
Q16 representation of 0.5.
Definition generic.h:38
#define SGL_Q11_ONE
Q11 representation of 1.0 (1 << 11).
Definition generic.h:28
#define SGL_Q11_HALF
Q11 representation of 0.5.
Definition generic.h:30
#define SGL_Q11_MASK
Mask selecting all eleven Q11 fractional bits.
Definition generic.h:32
sgl_int32_t sgl_q11_ext_t
Extended signed Q11 value stored in 32 bits.
Definition generic.h:19
#define SGL_FIXED_INT32_MIN
Minimum signed 32-bit value without standard-library constants.
Definition generic.h:46
#define SGL_Q16_FRAC_BITS
Number of fractional bits in a Q16 value.
Definition generic.h:34
static sgl_q11_ext_t sgl_q11_ext_mul(sgl_q11_ext_t a, sgl_q11_ext_t b)
Multiplies two extended Q11 values with rounding and saturation.
Definition generic.h:291
static sgl_int64_t sgl_fixed_div_pow2_i64(sgl_int64_t value, sgl_uint32_t shift)
Divides by a power of two with C99 signed-division semantics.
Definition generic.h:108
static sgl_q11_ext_t sgl_q11_shift_down(sgl_q11_ext_t value)
Removes Q11 fractional bits while rounding toward negative infinity.
Definition generic.h:241
static sgl_int32_t sgl_fixed_clamp_i64_to_i32(sgl_int64_t value)
Saturates a signed 64-bit value to the signed 32-bit range.
Definition generic.h:57
static sgl_q16_ext_t sgl_int_to_q16(sgl_int32_t value)
Converts a signed 32-bit integer to extended Q16.
Definition generic.h:311
#define SGL_FIXED_I64_BITS
Bit width used by the portable signed-division helpers.
Definition generic.h:42
sgl_int32_t sgl_q16_t
Signed Q16 value stored in 32 bits.
Definition generic.h:21
#define SGL_FIXED_INT16_MAX
Maximum signed 16-bit value without standard-library constants.
Definition generic.h:48
sgl_int16_t sgl_q11_t
Signed Q11 value stored in 16 bits.
Definition generic.h:17
static sgl_q11_ext_t sgl_q11_get_frac_part(sgl_q11_ext_t value)
Extracts the signed fractional part of an extended Q11 value.
Definition generic.h:209
signed short sgl_int16_t
Signed integer with exactly 16 value bits.
Definition sgl-type.h:28
unsigned long long sgl_uint64_t
Unsigned integer with exactly 64 value bits.
Definition sgl-type.h:38
signed long long sgl_int64_t
Signed integer with exactly 64 value bits.
Definition sgl-type.h:36
signed int sgl_int32_t
Signed integer with exactly 32 value bits.
Definition sgl-type.h:32
unsigned int sgl_uint32_t
Unsigned integer with exactly 32 value bits.
Definition sgl-type.h:34
unsigned char sgl_uint8_t
Unsigned integer with exactly 8 value bits.
Definition sgl-type.h:26