source: libcfa/src/math.hfa @ 0deeaad

ADTast-experimental
Last change on this file since 0deeaad was 0deeaad, checked in by Thierry Delisle <tdelisle@…>, 23 months ago

Added fixed point log2 calculation, which is not that useful but kind of cool.

  • Property mode set to 100644
File size: 25.2 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// math.hfa --
8//
9// Author           : Peter A. Buhr
10// Created On       : Mon Apr 18 23:37:04 2016
11// Last Modified By : Peter A. Buhr
12// Last Modified On : Thu Apr 15 11:47:56 2021
13// Update Count     : 132
14//
15
16#pragma once
17
18#include <math.h>
19#include <complex.h>
20
21//---------------------------------------
22
23#include "common.hfa"
24#include "bits/debug.hfa"
25
26//---------------------- General ----------------------
27
28static inline {
29        float ?%?( float x, float y ) { return fmodf( x, y ); }
30        float fmod( float x, float y ) { return fmodf( x, y ); }
31        double ?%?( double x, double y ) { return fmod( x, y ); }
32        // extern "C" { double fmod( double, double ); }
33        long double ?%?( long double x, long double y ) { return fmodl( x, y ); }
34        long double fmod( long double x, long double y ) { return fmodl( x, y ); }
35
36        float remainder( float x, float y ) { return remainderf( x, y ); }
37        // extern "C" { double remainder( double, double ); }
38        long double remainder( long double x, long double y ) { return remainderl( x, y ); }
39
40        float remquo( float x, float y, int * quo ) { return remquof( x, y, quo ); }
41        // extern "C" { double remquo( double x, double y, int * quo ); }
42        long double remquo( long double x, long double y, int * quo ) { return remquol( x, y, quo ); }
43        [ int, float ] remquo( float x, float y ) { int quo; x = remquof( x, y, &quo ); return [ quo, x ]; }
44        [ int, double ] remquo( double x, double y ) { int quo; x = remquo( x, y, &quo ); return [ quo, x ]; }
45        [ int, long double ] remquo( long double x, long double y ) { int quo; x = remquol( x, y, &quo ); return [ quo, x ]; }
46
47        [ float, float ] div( float x, float y ) { y = modff( x / y, &x ); return [ x, y ]; }
48        [ double, double ] div( double x, double y ) { y = modf( x / y, &x ); return [ x, y ]; }
49        [ long double, long double ] div( long double x, long double y ) { y = modfl( x / y, &x ); return [ x, y ]; }
50
51        float fma( float x, float y, float z ) { return fmaf( x, y, z ); }
52        // extern "C" { double fma( double, double, double ); }
53        long double fma( long double x, long double y, long double z ) { return fmal( x, y, z ); }
54
55        float fdim( float x, float y ) { return fdimf( x, y ); }
56        // extern "C" { double fdim( double, double ); }
57        long double fdim( long double x, long double y ) { return fdiml( x, y ); }
58
59        float nan( const char tag[] ) { return nanf( tag ); }
60        // extern "C" { double nan( const char [] ); }
61        long double nan( const char tag[] ) { return nanl( tag ); }
62} // distribution
63
64//---------------------- Exponential ----------------------
65
66static inline {
67        float exp( float x ) { return expf( x ); }
68        // extern "C" { double exp( double ); }
69        long double exp( long double x ) { return expl( x ); }
70        float _Complex exp( float _Complex x ) { return cexpf( x ); }
71        double _Complex exp( double _Complex x ) { return cexp( x ); }
72        long double _Complex exp( long double _Complex x ) { return cexpl( x ); }
73
74        float exp2( float x ) { return exp2f( x ); }
75        // extern "C" { double exp2( double ); }
76        long double exp2( long double x ) { return exp2l( x ); }
77        //float _Complex exp2( float _Complex x ) { return cexp2f( x ); }
78        //double _Complex exp2( double _Complex x ) { return cexp2( x ); }
79        //long double _Complex exp2( long double _Complex x ) { return cexp2l( x ); }
80
81        float expm1( float x ) { return expm1f( x ); }
82        // extern "C" { double expm1( double ); }
83        long double expm1( long double x ) { return expm1l( x ); }
84
85        float pow( float x, float y ) { return powf( x, y ); }
86        // extern "C" { double pow( double, double ); }
87        long double pow( long double x, long double y ) { return powl( x, y ); }
88        float _Complex pow( float _Complex x, float _Complex y ) { return cpowf( x, y ); }
89        double _Complex pow( double _Complex x, double _Complex y ) { return cpow( x, y ); }
90        long double _Complex pow( long double _Complex x, long double _Complex y ) { return cpowl( x, y ); }
91} // distribution
92
93//---------------------- Logarithm ----------------------
94
95static inline {
96        float log( float x ) { return logf( x ); }
97        // extern "C" { double log( double ); }
98        long double log( long double x ) { return logl( x ); }
99        float _Complex log( float _Complex x ) { return clogf( x ); }
100        double _Complex log( double _Complex x ) { return clog( x ); }
101        long double _Complex log( long double _Complex x ) { return clogl( x ); }
102
103        // O(1) polymorphic integer log2, using clz, which returns the number of leading 0-bits, starting at the most
104        // significant bit (single instruction on x86)
105        int log2( unsigned int n ) { return n == 0 ? -1 : sizeof(n) * __CHAR_BIT__ - 1 - __builtin_clz( n ); }
106        long int log2( unsigned long int n ) { return n == 0 ? -1 : sizeof(n) * __CHAR_BIT__ - 1 - __builtin_clzl( n ); }
107        long long int log2( unsigned long long int n ) { return n == 0 ? -1 : sizeof(n) * __CHAR_BIT__ - 1 - __builtin_clzll( n ); }
108        float log2( float x ) { return log2f( x ); }
109        // extern "C" { double log2( double ); }
110        long double log2( long double x ) { return log2l( x ); }
111        // float _Complex log2( float _Complex x ) { return clog2f( x ); }
112        // double _Complex log2( double _Complex x ) { return clog2( x ); }
113        // long double _Complex log2( long double _Complex x ) { return clog2l( x ); }
114
115        float log10( float x ) { return log10f( x ); }
116        // extern "C" { double log10( double ); }
117        long double log10( long double x ) { return log10l( x ); }
118        // float _Complex log10( float _Complex x ) { return clog10f( x ); }
119        // double _Complex log10( double _Complex x ) { return clog10( x ); }
120        // long double _Complex log10( long double _Complex x ) { return clog10l( x ); }
121
122        float log1p( float x ) { return log1pf( x ); }
123        // extern "C" { double log1p( double ); }
124        long double log1p( long double x ) { return log1pl( x ); }
125
126        int ilogb( float x ) { return ilogbf( x ); }
127        // extern "C" { int ilogb( double ); }
128        int ilogb( long double x ) { return ilogbl( x ); }
129
130        float logb( float x ) { return logbf( x ); }
131        // extern "C" { double logb( double ); }
132        long double logb( long double x ) { return logbl( x ); }
133
134        float sqrt( float x ) { return sqrtf( x ); }
135        // extern "C" { double sqrt( double ); }
136        long double sqrt( long double x ) { return sqrtl( x ); }
137        float _Complex sqrt( float _Complex x ) { return csqrtf( x ); }
138        double _Complex sqrt( double _Complex x ) { return csqrt( x ); }
139        long double _Complex sqrt( long double _Complex x ) { return csqrtl( x ); }
140
141        float cbrt( float x ) { return cbrtf( x ); }
142        // extern "C" { double cbrt( double ); }
143        long double cbrt( long double x ) { return cbrtl( x ); }
144
145        float hypot( float x, float y ) { return hypotf( x, y ); }
146        // extern "C" { double hypot( double, double ); }
147        long double hypot( long double x, long double y ) { return hypotl( x, y ); }
148} // distribution
149
150//---------------------- Trigonometric ----------------------
151
152static inline {
153        float sin( float x ) { return sinf( x ); }
154        // extern "C" { double sin( double ); }
155        long double sin( long double x ) { return sinl( x ); }
156        float _Complex sin( float _Complex x ) { return csinf( x ); }
157        double _Complex sin( double _Complex x ) { return csin( x ); }
158        long double _Complex sin( long double _Complex x ) { return csinl( x ); }
159
160        float cos( float x ) { return cosf( x ); }
161        // extern "C" { double cos( double ); }
162        long double cos( long double x ) { return cosl( x ); }
163        float _Complex cos( float _Complex x ) { return ccosf( x ); }
164        double _Complex cos( double _Complex x ) { return ccos( x ); }
165        long double _Complex cos( long double _Complex x ) { return ccosl( x ); }
166
167        float tan( float x ) { return tanf( x ); }
168        // extern "C" { double tan( double ); }
169        long double tan( long double x ) { return tanl( x ); }
170        float _Complex tan( float _Complex x ) { return ctanf( x ); }
171        double _Complex tan( double _Complex x ) { return ctan( x ); }
172        long double _Complex tan( long double _Complex x ) { return ctanl( x ); }
173
174        float asin( float x ) { return asinf( x ); }
175        // extern "C" { double asin( double ); }
176        long double asin( long double x ) { return asinl( x ); }
177        float _Complex asin( float _Complex x ) { return casinf( x ); }
178        double _Complex asin( double _Complex x ) { return casin( x ); }
179        long double _Complex asin( long double _Complex x ) { return casinl( x ); }
180
181        float acos( float x ) { return acosf( x ); }
182        // extern "C" { double acos( double ); }
183        long double acos( long double x ) { return acosl( x ); }
184        float _Complex acos( float _Complex x ) { return cacosf( x ); }
185        double _Complex acos( double _Complex x ) { return cacos( x ); }
186        long double _Complex acos( long double _Complex x ) { return cacosl( x ); }
187
188        float atan( float x ) { return atanf( x ); }
189        // extern "C" { double atan( double ); }
190        long double atan( long double x ) { return atanl( x ); }
191        float _Complex atan( float _Complex x ) { return catanf( x ); }
192        double _Complex atan( double _Complex x ) { return catan( x ); }
193        long double _Complex atan( long double _Complex x ) { return catanl( x ); }
194
195        float atan2( float x, float y ) { return atan2f( x, y ); }
196        // extern "C" { double atan2( double, double ); }
197        long double atan2( long double x, long double y ) { return atan2l( x, y ); }
198
199        // alternative name for atan2
200        float atan( float x, float y ) { return atan2f( x, y ); }
201        double atan( double x, double y ) { return atan2( x, y ); }
202        long double atan( long double x, long double y ) { return atan2l( x, y ); }
203} // distribution
204
205//---------------------- Hyperbolic ----------------------
206
207static inline {
208        float sinh( float x ) { return sinhf( x ); }
209        // extern "C" { double sinh( double ); }
210        long double sinh( long double x ) { return sinhl( x ); }
211        float _Complex sinh( float _Complex x ) { return csinhf( x ); }
212        double _Complex sinh( double _Complex x ) { return csinh( x ); }
213        long double _Complex sinh( long double _Complex x ) { return csinhl( x ); }
214
215        float cosh( float x ) { return coshf( x ); }
216        // extern "C" { double cosh( double ); }
217        long double cosh( long double x ) { return coshl( x ); }
218        float _Complex cosh( float _Complex x ) { return ccoshf( x ); }
219        double _Complex cosh( double _Complex x ) { return ccosh( x ); }
220        long double _Complex cosh( long double _Complex x ) { return ccoshl( x ); }
221
222        float tanh( float x ) { return tanhf( x ); }
223        // extern "C" { double tanh( double ); }
224        long double tanh( long double x ) { return tanhl( x ); }
225        float _Complex tanh( float _Complex x ) { return ctanhf( x ); }
226        double _Complex tanh( double _Complex x ) { return ctanh( x ); }
227        long double _Complex tanh( long double _Complex x ) { return ctanhl( x ); }
228
229        float asinh( float x ) { return asinhf( x ); }
230        // extern "C" { double asinh( double ); }
231        long double asinh( long double x ) { return asinhl( x ); }
232        float _Complex asinh( float _Complex x ) { return casinhf( x ); }
233        double _Complex asinh( double _Complex x ) { return casinh( x ); }
234        long double _Complex asinh( long double _Complex x ) { return casinhl( x ); }
235
236        float acosh( float x ) { return acoshf( x ); }
237        // extern "C" { double acosh( double ); }
238        long double acosh( long double x ) { return acoshl( x ); }
239        float _Complex acosh( float _Complex x ) { return cacoshf( x ); }
240        double _Complex acosh( double _Complex x ) { return cacosh( x ); }
241        long double _Complex acosh( long double _Complex x ) { return cacoshl( x ); }
242
243        float atanh( float x ) { return atanhf( x ); }
244        // extern "C" { double atanh( double ); }
245        long double atanh( long double x ) { return atanhl( x ); }
246        float _Complex atanh( float _Complex x ) { return catanhf( x ); }
247        double _Complex atanh( double _Complex x ) { return catanh( x ); }
248        long double _Complex atanh( long double _Complex x ) { return catanhl( x ); }
249} // distribution
250
251//---------------------- Error / Gamma ----------------------
252
253static inline {
254        float erf( float x ) { return erff( x ); }
255        // extern "C" { double erf( double ); }
256        long double erf( long double x ) { return erfl( x ); }
257        // float _Complex erf( float _Complex );
258        // double _Complex erf( double _Complex );
259        // long double _Complex erf( long double _Complex );
260
261        float erfc( float x ) { return erfcf( x ); }
262        // extern "C" { double erfc( double ); }
263        long double erfc( long double x ) { return erfcl( x ); }
264        // float _Complex erfc( float _Complex );
265        // double _Complex erfc( double _Complex );
266        // long double _Complex erfc( long double _Complex );
267
268        float lgamma( float x ) { return lgammaf( x ); }
269        // extern "C" { double lgamma( double ); }
270        long double lgamma( long double x ) { return lgammal( x ); }
271        float lgamma( float x, int * sign ) { return lgammaf_r( x, sign ); }
272        double lgamma( double x, int * sign ) { return lgamma_r( x, sign ); }
273        long double lgamma( long double x, int * sign ) { return lgammal_r( x, sign ); }
274
275        float tgamma( float x ) { return tgammaf( x ); }
276        // extern "C" { double tgamma( double ); }
277        long double tgamma( long double x ) { return tgammal( x ); }
278} // distribution
279
280//---------------------- Nearest Integer ----------------------
281
282static inline {
283        signed char floor( signed char n, signed char align ) { return n / align * align; }
284        unsigned char floor( unsigned char n, unsigned char align ) { return n / align * align; }
285        short int floor( short int n, short int align ) { return n / align * align; }
286        unsigned short int floor( unsigned short int n, unsigned short int align ) { return n / align * align; }
287        int floor( int n, int align ) { return n / align * align; }
288        unsigned int floor( unsigned int n, unsigned int align ) { return n / align * align; }
289        long int floor( long int n, long int align ) { return n / align * align; }
290        unsigned long int floor( unsigned long int n, unsigned long int align ) { return n / align * align; }
291        long long int floor( long long int n, long long int align ) { return n / align * align; }
292        unsigned long long int floor( unsigned long long int n, unsigned long long int align ) { return n / align * align; }
293
294        // forall( T | { T ?/?( T, T ); T ?*?( T, T ); } )
295        // T floor( T n, T align ) { return n / align * align; }
296
297        signed char ceiling_div( signed char n, char align ) { return (n + (align - 1)) / align; }
298        unsigned char ceiling_div( unsigned char n, unsigned char align ) { return (n + (align - 1)) / align; }
299        short int ceiling_div( short int n, short int align ) { return (n + (align - 1)) / align; }
300        unsigned short int ceiling_div( unsigned short int n, unsigned short int align ) { return (n + (align - 1)) / align; }
301        int ceiling_div( int n, int align ) { return (n + (align - 1)) / align; }
302        unsigned int ceiling_div( unsigned int n, unsigned int align ) { return (n + (align - 1)) / align; }
303        long int ceiling_div( long int n, long int align ) { return (n + (align - 1)) / align; }
304        unsigned long int ceiling_div( unsigned long int n, unsigned long int align ) { return (n + (align - 1)) / align; }
305        long long int ceiling_div( long long int n, long long int align ) { return (n + (align - 1)) / align; }
306        unsigned long long int ceiling_div( unsigned long long int n, unsigned long long int align ) { return (n + (align - 1)) / align; }
307
308        // forall( T | { T ?+?( T, T ); T ?-?( T, T ); T ?%?( T, T ); } )
309        // T ceiling_div( T n, T align ) { verify( is_pow2( align ) );return (n + (align - 1)) / align; }
310
311        // gcc notices the div/mod pair and saves both so only one div.
312        signed char ceiling( signed char n, signed char align ) { return floor( n + (n % align != 0 ? align - 1 : 0), align ); }
313        unsigned char ceiling( unsigned char n, unsigned char align ) { return floor( n + (n % align != 0 ? align - 1 : 0), align ); }
314        short int ceiling( short int n, short int align ) { return floor( n + (n % align != 0 ? align - 1 : 0), align ); }
315        unsigned short int ceiling( unsigned short int n, unsigned short int align ) { return floor( n + (n % align != 0 ? align - 1 : 0), align ); }
316        int ceiling( int n, int align ) { return floor( n + (n % align != 0 ? align - 1 : 0), align ); }
317        unsigned int ceiling( unsigned int n, unsigned int align ) { return floor( n + (n % align != 0 ? align - 1 : 0), align ); }
318        long int ceiling( long int n, long int align ) { return floor( n + (n % align != 0 ? align - 1 : 0), align ); }
319        unsigned long int ceiling( unsigned long int n, unsigned long int align ) { return floor( n + (n % align != 0 ? align - 1 : 0) , align); }
320        long long int ceiling( long long int n, long long int align ) { return floor( n + (n % align != 0 ? align - 1 : 0), align ); }
321        unsigned long long int ceiling( unsigned long long int n, unsigned long long int align ) { return floor( n + (n % align != 0 ? align - 1 : 0), align ); }
322
323        // forall( T | { void ?{}( T &, one_t ); T ?+?( T, T ); T ?-?( T, T ); T ?/?( T, T ); } )
324        // T ceiling( T n, T align ) { return return floor( n + (n % align != 0 ? align - 1 : 0), align ); *}
325
326        float floor( float x ) { return floorf( x ); }
327        // extern "C" { double floor( double ); }
328        long double floor( long double x ) { return floorl( x ); }
329
330        float ceil( float x ) { return ceilf( x ); }
331        // extern "C" { double ceil( double ); }
332        long double ceil( long double x ) { return ceill( x ); }
333
334        float trunc( float x ) { return truncf( x ); }
335        // extern "C" { double trunc( double ); }
336        long double trunc( long double x ) { return truncl( x ); }
337
338        float rint( float x ) { return rintf( x ); }
339        // extern "C" { double rint( double x ); }
340        long double rint( long double x ) { return rintl( x ); }
341        long int rint( float x ) { return lrintf( x ); }
342        long int rint( double x ) { return lrint( x ); }
343        long int rint( long double x ) { return lrintl( x ); }
344        long long int rint( float x ) { return llrintf( x ); }
345        long long int rint( double x ) { return llrint( x ); }
346        long long int rint( long double x ) { return llrintl( x ); }
347
348        long int lrint( float x ) { return lrintf( x ); }
349        // extern "C" { long int lrint( double ); }
350        long int lrint( long double x ) { return lrintl( x ); }
351        long long int llrint( float x ) { return llrintf( x ); }
352        // extern "C" { long long int llrint( double ); }
353        long long int llrint( long double x ) { return llrintl( x ); }
354
355        float nearbyint( float x ) { return nearbyintf( x ); }
356        // extern "C" { double nearbyint( double ); }
357        long double nearbyint( long double x ) { return nearbyintl( x ); }
358
359        float round( float x ) { return roundf( x ); }
360        // extern "C" { double round( double x ); }
361        long double round( long double x ) { return roundl( x ); }
362        long int round( float x ) { return lroundf( x ); }
363        long int round( double x ) { return lround( x ); }
364        long int round( long double x ) { return lroundl( x ); }
365        long long int round( float x ) { return llroundf( x ); }
366        long long int round( double x ) { return llround( x ); }
367        long long int round( long double x ) { return llroundl( x ); }
368
369        long int lround( float x ) { return lroundf( x ); }
370        // extern "C" { long int lround( double ); }
371        long int lround( long double x ) { return lroundl( x ); }
372        long long int llround( float x ) { return llroundf( x ); }
373        // extern "C" { long long int llround( double ); }
374        long long int llround( long double x ) { return llroundl( x ); }
375} // distribution
376
377//---------------------- Manipulation ----------------------
378
379static inline {
380        float copysign( float x, float y ) { return copysignf( x, y ); }
381        // extern "C" { double copysign( double, double ); }
382        long double copysign( long double x, long double y ) { return copysignl( x, y ); }
383
384        float frexp( float x, int * ip ) { return frexpf( x, ip ); }
385        // extern "C" { double frexp( double, int * ); }
386        long double frexp( long double x, int * ip ) { return frexpl( x, ip ); }
387
388        float ldexp( float x, int exp2 ) { return ldexpf( x, exp2 ); }
389        // extern "C" { double ldexp( double, int ); }
390        long double ldexp( long double x, int exp2 ) { return ldexpl( x, exp2 ); }
391
392        [ float, float ] modf( float x ) { float i; x = modff( x, &i ); return [ i, x ]; }
393        float modf( float x, float * i ) { return modff( x, i ); }
394        [ double, double ] modf( double x ) { double i; x = modf( x, &i ); return [ i, x ]; }
395        // extern "C" { double modf( double, double * ); }
396        [ long double, long double ] modf( long double x ) { long double i; x = modfl( x, &i ); return [ i, x ]; }
397        long double modf( long double x, long double * i ) { return modfl( x, i ); }
398
399        float nextafter( float x, float y ) { return nextafterf( x, y ); }
400        // extern "C" { double nextafter( double, double ); }
401        long double nextafter( long double x, long double y ) { return nextafterl( x, y ); }
402
403        float nexttoward( float x, long double y ) { return nexttowardf( x, y ); }
404        // extern "C" { double nexttoward( double, long double ); }
405        long double nexttoward( long double x, long double y ) { return nexttowardl( x, y ); }
406
407        float scalbn( float x, int exp ) { return scalbnf( x, exp ); }
408        // extern "C" { double scalbn( double, int ); }
409        long double scalbn( long double x, int exp ) { return scalbnl( x, exp ); }
410        float scalbn( float x, long int exp ) { return scalblnf( x, exp ); }
411        double scalbn( double x, long int exp ) { return scalbln( x, exp ); }
412        long double scalbn( long double x, long int exp ) { return scalblnl( x, exp ); }
413
414        float scalbln( float x, long int exp ) { return scalblnf( x, exp ); }
415        // extern "C" { double scalbln( double, long int ); }
416        long double scalbln( long double x, long int exp ) { return scalblnl( x, exp ); }
417} // distribution
418
419//---------------------------------------
420
421static inline {
422        forall( T | { void ?{}( T &, one_t ); T ?+?( T, T ); T ?-?( T, T );T ?*?( T, T ); } )
423        T lerp( T x, T y, T a ) { return x * ((T){1} - a) + y * a; }
424
425        forall( T | { void ?{}( T &, zero_t ); void ?{}( T &, one_t ); int ?<?( T, T ); } )
426        T step( T edge, T x ) { return x < edge ? (T){0} : (T){1}; }
427
428        forall( T | { void ?{}( T &, int ); T clamp( T, T, T ); T ?-?( T, T ); T ?*?( T, T ); T ?/?( T, T ); } )
429        T smoothstep( T edge0, T edge1, T x ) { T t = clamp( (x - edge0) / (edge1 - edge0), (T){0}, (T){1} ); return t * t * ((T){3} - (T){2} * t); }
430} // distribution
431
432static inline unsigned long long log2_u32_32(unsigned long long val) {
433        enum {
434                TABLE_BITS = 6,
435                TABLE_SIZE = (1 << TABLE_BITS) + 2,
436        };
437        // for(i; TABLE_SIZE) {
438        //      table[i] = (unsigned long long)(log2(1.0 + i / pow(2, TABLE_BITS)) * pow(2, 32)));
439        // }
440        static const unsigned long long table[] = {
441                0x0000000000, 0x0005b9e5a1, 0x000b5d69ba, 0x0010eb389f,
442                0x001663f6fa, 0x001bc84240, 0x002118b119, 0x002655d3c4,
443                0x002b803473, 0x00309857a0, 0x00359ebc5b, 0x003a93dc98,
444                0x003f782d72, 0x00444c1f6b, 0x0049101eac, 0x004dc4933a,
445                0x005269e12f, 0x00570068e7, 0x005b888736, 0x006002958c,
446                0x00646eea24, 0x0068cdd829, 0x006d1fafdc, 0x007164beb4,
447                0x00759d4f80, 0x0079c9aa87, 0x007dea15a3, 0x0081fed45c,
448                0x0086082806, 0x008a064fd5, 0x008df988f4, 0x0091e20ea1,
449                0x0095c01a39, 0x009993e355, 0x009d5d9fd5, 0x00a11d83f4,
450                0x00a4d3c25e, 0x00a8808c38, 0x00ac241134, 0x00afbe7fa0,
451                0x00b3500472, 0x00b6d8cb53, 0x00ba58feb2, 0x00bdd0c7c9,
452                0x00c1404ead, 0x00c4a7ba58, 0x00c80730b0, 0x00cb5ed695,
453                0x00ceaecfea, 0x00d1f73f9c, 0x00d53847ac, 0x00d8720935,
454                0x00dba4a47a, 0x00ded038e6, 0x00e1f4e517, 0x00e512c6e5,
455                0x00e829fb69, 0x00eb3a9f01, 0x00ee44cd59, 0x00f148a170,
456                0x00f446359b, 0x00f73da38d, 0x00fa2f045e, 0x00fd1a708b,
457                0x0100000000, 0x0102dfca16,
458        };
459        _Static_assert((sizeof(table) / sizeof(table[0])) == TABLE_SIZE, "TABLE_SIZE should be accurate");
460        // starting from val = (2 ** i)*(1 + f) where 0 <= f < 1
461        // log identities mean log2(val) = log2((2 ** i)*(1 + f)) = log2(2**i) + log2(1+f)
462        //
463        // getting i is easy to do using builtin_clz (count leading zero)
464        //
465        // we want to calculate log2(1+f) independently to have a many bits of precision as possible.
466        //     val = (2 ** i)*(1 + f) = 2 ** i   +   f * 2 ** i
467        // isolating f we get
468        //     val - 2 ** i = f * 2 ** i
469        //     (val - 2 ** i) / 2 ** i = f
470        //
471        // we want to interpolate from the table to get the values
472        // and compromise by doing quadratic interpolation (rather than higher degree interpolation)
473        //
474        // for the interpolation we want to shift everything the fist sample point
475        // so our parabola becomes x = 0
476        // this further simplifies the equations
477        //
478        // the consequence is that we need f in 2 forms:
479        //  - finding the index of x0
480        //  - finding the distance between f and x0
481        //
482        // since sample points are equidistant we can significantly simplify the equations
483
484        // get i
485        const unsigned long long bits = sizeof(val) * __CHAR_BIT__;
486        const unsigned long long lz = __builtin_clzl(val);
487        const unsigned long long i = bits - 1 - lz;
488
489        // get the fractinal part as a u32.32
490        const unsigned long long frac = (val << (lz + 1)) >> 32;
491
492        // get high order bits for the index into the table
493        const unsigned long long idx0 = frac >> (32 - TABLE_BITS);
494
495        // get the x offset, i.e., the difference between the first sample point and the actual fractional part
496        const long long udx = frac - (idx0 << (32 - TABLE_BITS));
497        /* paranoid */ verify((idx0 + 2) < TABLE_SIZE);
498
499        const long long y0 = table[idx0 + 0];
500        const long long y1 = table[idx0 + 1];
501        const long long y2 = table[idx0 + 2];
502
503        // from there we can quadraticly interpolate to get the data, using the lagrange polynomial
504        // normally it would look like:
505        //     double r0 = y0 * ((x - x1) / (x0 - x1)) * ((x - x2) / (x0 - x2));
506        //     double r1 = y1 * ((x - x0) / (x1 - x0)) * ((x - x2) / (x1 - x2));
507        //     double r2 = y2 * ((x - x0) / (x2 - x0)) * ((x - x1) / (x2 - x1));
508        // but since the spacing between sample points is fixed, we can simplify it and extract common expressions
509        const long long f1 = (y1 - y0);
510        const long long f2 = (y2 - y0);
511        const long long a = f2 - (f1 * 2l);
512        const long long b = (f1 * 2l) - a;
513
514        // Now we can compute it in the form (ax + b)x + c (which avoid repeating steps)
515        long long sum = ((a*udx) >> (32 - TABLE_BITS))  + b;
516        sum = (sum*udx) >> (32 - TABLE_BITS + 1);
517        sum = y0 + sum;
518
519        return (i << 32) + (sum);
520}
521
522// Local Variables: //
523// mode: c //
524// tab-width: 4 //
525// End: //
Note: See TracBrowser for help on using the repository browser.