Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
math.h
Go to the documentation of this file.
1/*
2 * This file is part of darktable,
3 * Copyright (C) 2016 johannes hanika.
4 * Copyright (C) 2016, 2018 Tobias Ellinghaus.
5 * Copyright (C) 2018-2019 Heiko Bauke.
6 * Copyright (C) 2020-2021 Pascal Obry.
7 * Copyright (C) 2020-2021 Ralf Brown.
8 * Copyright (C) 2021 Andreas Schneider.
9 * Copyright (C) 2021, 2023-2025 Aurélien PIERRE.
10 * Copyright (C) 2022 Martin Bařinka.
11 * Copyright (C) 2023 Luca Zulberti.
12 *
13 * darktable is free software: you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation, either version 3 of the License, or
16 * (at your option) any later version.
17 *
18 * darktable is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with darktable. If not, see <http://www.gnu.org/licenses/>.
25 */
26
27#ifndef DT_MATH_MATH_H
28#define DT_MATH_MATH_H
29
30#include <stddef.h>
31#include <math.h>
32#include <stdint.h>
33
34#include "system/openmp.h"
35#include "system/simd.h"
36
37#define NORM_MIN 1.52587890625e-05f // norm can't be < to 2^(-16)
38
39// work around missing standard math.h symbols
41#ifndef M_LN10
42#define M_LN10 2.30258509299404568402
43#endif /* !M_LN10 */
44
46#ifndef M_PI
47#define M_PI 3.14159265358979323846
48#endif /* !M_PI */
49#ifndef M_PI_F
50#define M_PI_F 3.14159265358979324f
51#endif /* !M_PI_F */
52
53
54#define DT_M_PI_F (3.14159265358979324f)
55#define DT_M_PI (3.14159265358979324)
56
57#define DT_M_LN2f (0.6931471805599453f)
58
59// If platform supports hardware-accelerated fused-multiply-add
60// This is not only faster but more accurate because rounding happens at the right place
61#ifdef FP_FAST_FMAF
62 #define DT_FMA(x, y, z) fmaf(x, y, z)
63#else
64 #define DT_FMA(x, y, z) ((x) * (y) + (z))
65#endif
66
67// Golden number (1+sqrt(5))/2
68#ifndef PHI
69#define PHI 1.61803398874989479F
70#endif
71
72// 1/PHI
73#ifndef INVPHI
74#define INVPHI 0.61803398874989479F
75#endif
76
77// NaN-safe clamping (NaN compares false, and will thus result in H)
78#define CLAMPS(A, L, H) ((A) > (L) ? ((A) < (H) ? (A) : (H)) : (L))
79
80// clip channel value to be between 0 and 1
81// NaN-safe: NaN compares false and will result in 0.0
82// also does not force promotion of floats to doubles, but will use the type of its argument
83#define CLIP(x) (((x) >= 0) ? ((x) <= 1 ? (x) : 1) : 0)
84#define MM_CLIP_PS(X) (_mm_min_ps(_mm_max_ps((X), _mm_setzero_ps()), _mm_set1_ps(1.0)))
85
86// clip luminance values to be between 0 and 100
87#define LCLIP(x) ((x < 0) ? 0.0 : (x > 100.0) ? 100.0 : x)
88
89// clamp value to lie between mn and mx
90// Nan-safe: NaN compares false and will result in mn
91#define CLAMPF(a, mn, mx) ((a) >= (mn) ? ((a) <= (mx) ? (a) : (mx)) : (mn))
92//#define CLAMPF(a, mn, mx) ((a) < (mn) ? (mn) : ((a) > (mx) ? (mx) : (a)))
93
94#if defined(__x86_64__) || defined(__i386__)
95#define MMCLAMPPS(a, mn, mx) (_mm_min_ps((mx), _mm_max_ps((a), (mn))))
96#endif
97
98static inline float clamp_range_f(const float x, const float low, const float high)
99{
100 return x > high ? high : (x < low ? low : x);
101}
102
103// Kahan summation algorithm
104__OMP_DECLARE_SIMD__(aligned(c))
105static inline float Kahan_sum(const float m, float *const __restrict__ c, const float add)
106{
107 const float t1 = add - (*c);
108 const float t2 = m + t1;
109 *c = (t2 - m) - t1;
110 return t2;
111}
112
113static inline float Log2(float x)
114{
115 return (x > 0.0f) ? (logf(x) / DT_M_LN2f) : x;
116}
117
118static inline float Log2Thres(float x, float Thres)
119{
120 return logf(x > Thres ? x : Thres) / DT_M_LN2f;
121}
122
123// ensure that any changes here are synchronized with data/kernels/extended.cl
124static inline float fastlog2(float x)
125{
126 union { float f; uint32_t i; } vx = { x };
127 union { uint32_t i; float f; } mx = { (vx.i & 0x007FFFFF) | 0x3f000000 };
128
129 float y = vx.i;
130
131 y *= 1.1920928955078125e-7f;
132
133 return y - 124.22551499f
134 - 1.498030302f * mx.f
135 - 1.72587999f / (0.3520887068f + mx.f);
136}
137
138// ensure that any changes here are synchronized with data/kernels/extended.cl
139static inline float
140fastlog (float x)
141{
142 return DT_M_LN2f * fastlog2(x);
143}
144
145// multiply 3x3 matrix with 3x1 vector
146// dest needs to be different from v
148static inline void mat3mulv(float *const __restrict__ dest, const float *const mat, const float *const __restrict__ v)
149{
150 for(int k = 0; k < 3; k++)
151 {
152 float x = 0.0f;
153 for(int i = 0; i < 3; i++)
154 x += mat[3 * k + i] * v[i];
155 dest[k] = x;
156 }
157}
158
159// multiply two 3x3 matrices
160// dest needs to be different from m1 and m2
161// dest = m1 * m2 in this order
163static inline void mat3mul(float *const __restrict__ dest, const float *const __restrict__ m1, const float *const __restrict__ m2)
164{
165 for(int k = 0; k < 3; k++)
166 {
167 for(int i = 0; i < 3; i++)
168 {
169 float x = 0.0f;
170 for(int j = 0; j < 3; j++)
171 x += m1[3 * k + j] * m2[3 * j + i];
172 dest[3 * k + i] = x;
173 }
174 }
175}
176
178static inline void mul_mat_vec_2(const float *m, const float *p, float *o)
179{
180 o[0] = p[0] * m[0] + p[1] * m[1];
181 o[1] = p[0] * m[2] + p[1] * m[3];
182}
183
184__OMP_DECLARE_SIMD__(uniform(v_2) aligned(v_1, v_2:16))
185static inline float scalar_product(const dt_aligned_pixel_t v_1, const dt_aligned_pixel_t v_2)
186{
187 // specialized 3x1 dot products 2 4x1 RGB-alpha pixels.
188 // v_2 needs to be uniform along loop increments, e.g. independent from current pixel values
189 // we force an order of computation similar to SSE4 _mm_dp_ps() hoping the compiler will get the clue
190 float acc = 0.f;
191 __OMP_SIMD__(aligned(v_1, v_2:16) reduction(+:acc))
192 for(size_t c = 0; c < 3; c++) acc += v_1[c] * v_2[c];
193
194 return acc;
195}
196
197
199static inline float sqf(const float x)
200{
201 return x * x;
202}
203
204
205__OMP_DECLARE_SIMD__(aligned(vector:16))
206static inline float euclidean_norm(const dt_aligned_pixel_t vector)
207{
208 return fmaxf(sqrtf(sqf(vector[0]) + sqf(vector[1]) + sqf(vector[2])), NORM_MIN);
209}
210
211
212__OMP_DECLARE_SIMD__(aligned(vector:16))
213static inline void downscale_vector(dt_aligned_pixel_t vector, const float scaling)
214{
215 // check zero or NaN
216 const int valid = (scaling > NORM_MIN) && !isnan(scaling);
217 for(size_t c = 0; c < 3; c++) vector[c] = (valid) ? vector[c] / (scaling + NORM_MIN) : vector[c] / NORM_MIN;
218}
219
220
221__OMP_DECLARE_SIMD__(aligned(vector:16))
222static inline void upscale_vector(dt_aligned_pixel_t vector, const float scaling)
223{
224 const int valid = (scaling > NORM_MIN) && !isnan(scaling);
225 for(size_t c = 0; c < 3; c++) vector[c] = (valid) ? vector[c] * (scaling + NORM_MIN) : vector[c] * NORM_MIN;
226}
227
228
230static inline float dt_log2f(const float f)
231{
232#ifdef __GLIBC__
233 return log2f(f);
234#else
235 return logf(f) / logf(2.0f);
236#endif
237}
238
239union float_int {
240 float f;
241 int k;
242};
243
244// a faster, vectorizable version of hypotf() when we know that there won't be overflow, NaNs, or infinities
246static inline float dt_fast_hypotf(const float x, const float y)
247{
248 return sqrtf(x * x + y * y);
249}
250
251// fast approximation of expf()
252/****** if you change this function, you need to make the same change in data/kernels/{basecurve,basic}.cl ***/
254static inline float dt_fast_expf(const float x)
255{
256 // meant for the range [-100.0f, 0.0f]. largest error ~ -0.06 at 0.0f.
257 // will get _a_lot_ worse for x > 0.0f (9000 at 10.0f)..
258 const int i1 = 0x3f800000u;
259 // e^x, the comment would be 2^x
260 const int i2 = 0x402DF854u; // 0x40000000u;
261 // const int k = CLAMPS(i1 + x * (i2 - i1), 0x0u, 0x7fffffffu);
262 // without max clamping (doesn't work for large x, but is faster):
263 const int k0 = i1 + x * (i2 - i1);
264 union float_int u;
265 u.k = k0 > 0 ? k0 : 0;
266 return u.f;
267}
268
269static inline void dt_fast_expf_4wide(const float x[4], float result[4])
270{
271 // meant for the range [-100.0f, 0.0f]. largest error ~ -0.06 at 0.0f.
272 // will get _a_lot_ worse for x > 0.0f (9000 at 10.0f)..
273 const int i1 = 0x3f800000u;
274 // e^x, the comment would be 2^x
275 const int i2 = 0x402DF854u; // 0x40000000u;
276 // const int k = CLAMPS(i1 + x * (i2 - i1), 0x0u, 0x7fffffffu);
277 // without max clamping (doesn't work for large x, but is faster):
278 union float_int u[4];
279 __OMP_SIMD__(aligned(x, result))
280 for(size_t c = 0; c < 4; c++)
281 {
282 const int k0 = i1 + (int)(x[c] * (i2 - i1));
283 u[c].k = k0 > 0 ? k0 : 0;
284 result[c] = u[c].f;
285 }
286}
287
288// fast approximation of 2^-x for 0<x<126
289/****** if you change this function, you need to make the same change in data/kernels/{denoiseprofile,nlmeans}.cl ***/
290static inline float dt_fast_mexp2f(const float x)
291{
292 const int i1 = 0x3f800000; // bit representation of 2^0
293 const int i2 = 0x3f000000; // bit representation of 2^-1
294 const int k0 = i1 + (int)(x * (i2 - i1));
295 union {
296 float f;
297 int i;
298 } k;
299 k.i = k0 >= 0x800000 ? k0 : 0;
300 return k.f;
301}
302
303// The below version is incorrect, suffering from reduced precision.
304// It is used by the non-local means code in both nlmeans.c and
305// denoiseprofile.c, and fixing it would cause a change in output.
306static inline float fast_mexp2f(const float x)
307{
308 const float i1 = (float)0x3f800000u; // 2^0
309 const float i2 = (float)0x3f000000u; // 2^-1
310 const float k0 = i1 + x * (i2 - i1);
311 union {
312 float f;
313 int i;
314 } k;
315 k.i = k0 >= (float)0x800000u ? k0 : 0;
316 return k.f;
317}
318
324static inline float ceil_fast(float x)
325{
326 if(x <= 0.f)
327 {
328 return (float)(int)x;
329 }
330 else
331 {
332 return -((float)(int)-x) + 1.f;
333 }
334}
335
336#if defined(__x86_64__) || defined(__i386__)
static inline __m128 _mm_abs_ps(__m128 t)
341{
342 static const uint32_t signmask[4] __attribute__((aligned(64)))
343 = { 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff };
344 return _mm_and_ps(*(__m128 *)signmask, t);
345}
346#endif
347
360static inline float sinf_fast(float t)
361{
362 /***** if you change this function, you must also change the copy in data/kernels/basic.cl *****/
363 static const float a = 4 / (M_PI * M_PI);
364 static const float p = 0.225f;
365
366 t = a * t * (M_PI_F - fabsf(t));
367
368 return t * (p * (fabsf(t) - 1) + 1);
369}
370
371#if defined(__x86_64__) || defined(__i386__)
384static inline __m128 sinf_fast_sse(__m128 t)
385{
386 static const __m128 a
387 = { 4.f / (M_PI * M_PI), 4.f / (M_PI * M_PI), 4.f / (M_PI * M_PI), 4.f / (M_PI * M_PI) };
388 static const __m128 p = { 0.225f, 0.225f, 0.225f, 0.225f };
389 static const __m128 pi = { M_PI, M_PI, M_PI, M_PI };
390
391 // m4 = a*t*(M_PI - fabsf(t));
392 const __m128 m1 = _mm_abs_ps(t);
393 const __m128 m2 = _mm_sub_ps(pi, m1);
394 const __m128 m3 = _mm_mul_ps(t, m2);
395 const __m128 m4 = _mm_mul_ps(a, m3);
396
397 // p*(m4*fabsf(m4) - m4) + m4;
398 const __m128 n1 = _mm_abs_ps(m4);
399 const __m128 n2 = _mm_mul_ps(m4, n1);
400 const __m128 n3 = _mm_sub_ps(n2, m4);
401 const __m128 n4 = _mm_mul_ps(p, n3);
402
403 return _mm_add_ps(n4, m4);
404}
405#endif
406
407
415static inline int ipow(int base, int exp)
416{
417 // Shifting a negative exponent right never reaches zero, so the loop below would spin
418 // forever. There is no integer answer for one anyway; callers use this for decimal
419 // precision, where "fewer than zero digits" is just "no fractional part".
420 if(exp <= 0) return 1;
421
422 int result = 1;
423 for(;;)
424 {
425 if (exp & 1)
426 result *= base;
427 exp >>= 1;
428 if (!exp)
429 break;
430 base *= base;
431 }
432 return result;
433}
434
447static inline void dt_vector_sin(const dt_aligned_pixel_t arg,
449{
450 static const dt_aligned_pixel_t pi = { M_PI_F, M_PI_F, M_PI_F, M_PI_F };
451 static const dt_aligned_pixel_t a
452 = { 4 / (M_PI_F * M_PI_F),
453 4 / (M_PI_F * M_PI_F),
454 4 / (M_PI_F * M_PI_F),
455 4 / (M_PI_F * M_PI_F) };
456 static const dt_aligned_pixel_t p = { 0.225f, 0.225f, 0.225f, 0.225f };
457 static const dt_aligned_pixel_t one = { 1.0f, 1.0f, 1.0f, 1.0f };
458
459 dt_aligned_pixel_t abs_arg;
461 abs_arg[c] = (arg[c] < 0.0f) ? -arg[c] : arg[c];
462 dt_aligned_pixel_t scaled;
464 scaled[c] = a[c] * arg[c] * (pi[c] - abs_arg[c]);
465 dt_aligned_pixel_t abs_scaled;
467 abs_scaled[c] = (scaled[c] < 0.0f) ? -scaled[c] : scaled[c];
469 sine[c] = scaled[c] * (p[c] * (abs_scaled[c] - one[c]) + one[c]);
470}
471
476static inline float f_inv_sqrtf(const float x)
477{
478 if(x <= 1e-16f) return 0.0f;
479
480 union
481 {
482 float f;
483 uint32_t i;
484 } conv = { x };
485
486 conv.i = 0x5f3759dfu - (conv.i >> 1);
487 float y = conv.f;
488 // One Newton-Raphson iteration is accurate enough for geometry offsets.
489 y = y * (1.5f - 0.5f * x * y * y);
490 return y;
491}
492
493#endif // DT_MATH_MATH_H
494
495// clang-format off
496// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
497// vim: shiftwidth=2 expandtab tabstop=2 cindent
498// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
499// clang-format on
#define m
Definition basecurve.c:283
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
static const float scaling
static const float x
const float f
const int t
const float v
for(size_t c=0;c< 3;c++) sRGB[c]
float *const restrict const size_t k
static float Kahan_sum(const float m, float *const __restrict__ c, const float add)
Definition math.h:105
static float ceil_fast(float x)
Definition math.h:324
static float clamp_range_f(const float x, const float low, const float high)
Definition math.h:98
#define DT_M_LN2f
Definition math.h:57
static int ipow(int base, int exp)
Fast integer power, computing base^exp.
Definition math.h:415
static void mul_mat_vec_2(const float *m, const float *p, float *o)
Definition math.h:178
#define NORM_MIN
Definition math.h:37
static float f_inv_sqrtf(const float x)
Definition math.h:476
static float fast_mexp2f(const float x)
Definition math.h:306
static float sinf_fast(float t)
Definition math.h:360
c< 3;c++) acc+=v_1[c] *v_2[c];return acc;}static inline float sqf(const float x){ return x *x;}static inline float euclidean_norm(const dt_aligned_pixel_t vector){ return fmaxf(sqrtf(sqf(vector[0])+sqf(vector[1])+sqf(vector[2])), 1.52587890625e-05f);}static inline void downscale_vector(dt_aligned_pixel_t vector, const float scaling){ const int valid=(scaling > 1.52587890625e-05f) &&!isnan(scaling);for(size_t c=0;c< 3;c++) vector[c]=(valid) ? vector[c]/(scaling+1.52587890625e-05f) :vector[c]/1.52587890625e-05f ;}static inline void upscale_vector(dt_aligned_pixel_t vector, const float scaling){ const int valid=(scaling > 1.52587890625e-05f) &&!isnan(scaling);for(size_t c=0;c< 3;c++) vector[c]=(valid) ? vector[c] *(scaling+1.52587890625e-05f) :vector[c] *1.52587890625e-05f ;}static inline float dt_log2f(const float f){ return logf(f)/logf(2.0f);}union float_int { float f;int k;};static inline float dt_fast_hypotf(const float x, const float y){ return sqrtf(x *x+y *y);}static inline float dt_fast_expf(const float x){ const int i1=0x3f800000u;const int i2=0x402DF854u;const int k0=i1+x *(i2 - i1);union float_int u;u.k=k0 > k0
Definition math.h:265
return u f
Definition math.h:266
static float dt_fast_mexp2f(const float x)
Definition math.h:290
static void mat3mul(float *const __restrict__ dest, const float *const __restrict__ m1, const float *const __restrict__ m2)
Definition math.h:163
const dt_aligned_pixel_t v_2
Definition math.h:186
static void dt_vector_sin(const dt_aligned_pixel_t arg, dt_aligned_pixel_t sine)
Definition math.h:447
#define M_PI_F
Definition math.h:50
static float fastlog2(float x)
Definition math.h:124
static float fastlog(float x)
Definition math.h:140
static float Log2(float x)
Definition math.h:113
static float Log2Thres(float x, float Thres)
Definition math.h:118
static void dt_fast_expf_4wide(const float x[4], float result[4])
Definition math.h:269
#define M_PI
Definition math.h:47
static void mat3mulv(float *const __restrict__ dest, const float *const mat, const float *const __restrict__ v)
Definition math.h:148
#define __OMP_SIMD__(...)
Definition openmp.h:99
#define __OMP_DECLARE_SIMD__(...)
Definition openmp.h:100
DT_ALIGNED_PIXEL float dt_aligned_pixel_t[4]
Definition simd.h:53
float dt_aligned_pixel_simd_t __attribute__((vector_size(16), aligned(16)))
Apply one channel's tone curve to each of the three colour channels, or pass the channel through unto...
Definition simd.h:55
#define for_four_channels(_var,...)
Definition simd.h:89