Loading...
Searching...
No Matches
float.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#ifndef _PICO_FLOAT_H
8#define _PICO_FLOAT_H
9
148
149#include "pico.h"
150
151// PICO_CONFIG: PICO_FLOAT_IN_RAM, Force placement of SDK provided single-precision floating point code into RAM, type=bool, default=0, group=pico_float
152#ifndef PICO_FLOAT_IN_RAM
153#define PICO_FLOAT_IN_RAM 0
154#endif
155
156#if !(LIB_PICO_FLOAT_COMPILER || defined(__riscv)) || PICO_DOCS
157// private define to simplify this header only - it is undefined at the end
158#define __PICO_FLOAT_ARM_OPTIMIZED 1
159#endif
160
163
164// we always define these for C code, but they are inline
165// funcs except for __PICO_FLOAT_ARM_OPTIMIZED so wouldn't
166// be callable for assembly
167#if __PICO_FLOAT_ARM_OPTIMIZED || !defined(__ASSEMBLER__)
169#define PICO_FLOAT_HAS_INT32_TO_FLOAT_CONVERSIONS 1
171#define PICO_FLOAT_HAS_INT64_TO_FLOAT_CONVERSIONS 1
173#define PICO_FLOAT_HAS_FLOAT_TO_INT32_Z_CONVERSIONS 1
175#define PICO_FLOAT_HAS_FLOAT_TO_INT64_Z_CONVERSIONS 1
176#endif
177
178#if __PICO_FLOAT_ARM_OPTIMIZED
180#define PICO_FLOAT_HAS_FIX32_TO_FLOAT_CONVERSIONS 1
182#define PICO_FLOAT_HAS_FIX64_TO_FLOAT_CONVERSIONS 1
184#define PICO_FLOAT_HAS_FLOAT_TO_FIX32_Z_CONVERSIONS 1
186#define PICO_FLOAT_HAS_FLOAT_TO_FIX64_Z_CONVERSIONS 1
187
189#define PICO_FLOAT_HAS_FLOAT_TO_INT32_M_CONVERSIONS 1
191#define PICO_FLOAT_HAS_FLOAT_TO_INT64_M_CONVERSIONS 1
192
194#define PICO_FLOAT_HAS_FLOAT_TO_FIX32_M_CONVERSIONS 1
196#define PICO_FLOAT_HAS_FLOAT_TO_FIX64_M_CONVERSIONS 1
197#endif
198
199#if (PICO_RP2350 && LIB_PICO_FLOAT_PICO_DCP) || PICO_DOCS
201#define PICO_FLOAT_HAS_FDIV_FAST 1
203#define PICO_FLOAT_HAS_SQRTF_FAST 1
204#endif
205
206#if __PICO_FLOAT_ARM_OPTIMIZED || __builtin_powif || PICO_DOCS
208#define PICO_FLOAT_HAS_POWINTF 1
209#endif
211
212#ifndef __ASSEMBLER__
213#include <math.h>
214#include <float.h>
215
216#ifdef __cplusplus
217extern "C" {
218#endif
219
222#if PICO_FLOAT_HAS_INT32_TO_FLOAT_CONVERSIONS
223#if LIB_PICO_FLOAT_PICO_VFP || !__PICO_FLOAT_ARM_OPTIMIZED
224 // for VFP the C cast is an assembly instruction anyway, so we prefer that over a function call
225 // for non Arm-optimized we may as well provide the function and let the compiler handle it
226 static inline float int2float(int32_t i) { return (float)i; }
227 static inline float uint2float(uint32_t u) { return (float)u; }
228#else
230 float int2float(int32_t i);
232 float uint2float(uint32_t u);
233#endif
234#endif
235
236#if PICO_FLOAT_HAS_INT64_TO_FLOAT_CONVERSIONS
237#if !__PICO_FLOAT_ARM_OPTIMIZED
238 // for non Arm-optimized we may as well provide the function and let the compiler handle it
239 static inline float int642float(int64_t i) { return (float)i; }
240 static inline float uint642float(uint64_t u) { return (float)u; }
241#else
243 float int642float(int64_t i);
245 float uint642float(uint64_t u);
246#endif
247#endif
248
249#if PICO_FLOAT_HAS_FLOAT_TO_INT32_Z_CONVERSIONS
250#if !__PICO_FLOAT_ARM_OPTIMIZED
251 // for non Arm-optimized we may as well provide the function and let the compiler handle it
252 static inline int32_t float2int_z(float f) { return (int32_t)f; }
253 static inline uint32_t float2uint_z(float f) { return (uint32_t)f; }
254#else
257 int32_t float2int_z(float f);
260 uint32_t float2uint_z(float f);
261#endif
262#endif
263
264#if PICO_FLOAT_HAS_FLOAT_TO_INT64_Z_CONVERSIONS
265#if !__PICO_FLOAT_ARM_OPTIMIZED
266 // for non Arm-optimized we may as well provide the function and let the compiler handle it
267 static inline int64_t float2int64_z(float f) { return (int64_t)f; }
268 static inline uint64_t float2uint64_z(float f) { return (uint64_t)f; }
269#else
272 int64_t float2int64_z(float f);
275 uint64_t float2uint64_z(float f);
276#endif
277#endif
278
279#if PICO_FLOAT_HAS_FIX32_TO_FLOAT_CONVERSIONS
282float fix2float(int32_t m, int e);
285float ufix2float(uint32_t m, int e);
286#endif
287
288#if PICO_FLOAT_HAS_FIX64_TO_FLOAT_CONVERSIONS
291float fix642float(int64_t m, int e);
294float ufix642float(uint64_t m, int e);
295#endif
296
297#if PICO_FLOAT_HAS_FLOAT_TO_FIX32_Z_CONVERSIONS
300int32_t float2fix_z(float f, int e);
303uint32_t float2ufix_z(float f, int e);
304#endif
305
306#if PICO_FLOAT_HAS_FLOAT_TO_FIX64_Z_CONVERSIONS
309int64_t float2fix64_z(float f, int e);
312uint64_t float2ufix64_z(float f, int e);
313#endif
314
315// These methods round towards -Infinity - which IS NOT the C way for negative numbers;
316// as such the naming is not ideal, however is kept for backwards compatibility
317#if PICO_FLOAT_HAS_FLOAT_TO_INT32_M_CONVERSIONS
320int32_t float2int(float f);
323uint32_t float2uint(float f);
324#endif
325
326#if PICO_FLOAT_HAS_FLOAT_TO_INT64_M_CONVERSIONS
329int64_t float2int64(float f);
332uint64_t float2uint64(float f);
333#endif
334
335#if PICO_FLOAT_HAS_FLOAT_TO_FIX32_M_CONVERSIONS
338int32_t float2fix(float f, int e);
341uint32_t float2ufix(float f, int e);
342#endif
343
344#if PICO_FLOAT_HAS_FLOAT_TO_FIX64_M_CONVERSIONS
347int64_t float2fix64(float f, int e);
350uint64_t float2ufix64(float f, int e);
351#endif
352
353#if LIB_PICO_FLOAT_PICO_VFP
354// special handling of fixed-point conversions for VFP - we want to inline calls with fixed exponents
355// between 1 and 32, because they can use an assembly instruction. we leave the function in place
356// with its original name, however make a #define which will either do the inline instruction
357// or call the original function
358#if PICO_FLOAT_HAS_FIX32_TO_FLOAT_CONVERSIONS
359// a bit of a hack to inline VFP fixed-point conversion when exponent is constant and in range 1-32
360#define fix2float(m, e) (__builtin_constant_p(e) && (e) >= 1 && (e) <= 32 ? _fix2float_inline(m, e) : fix2 ## float(m, e))
361#define ufix2float(m, e) (__builtin_constant_p(e) && (e) >= 1 && (e) <= 32 ? _ufix2float_inline(m, e) : ufix2 ## float(m, e))
362
363#define _fix2float_inline(m, e) ({ \
364 int32_t _m = m; \
365 float f; \
366 pico_default_asm( \
367 "vmov %0, %1\n" \
368 "vcvt.f32.s32 %0, %0, %2\n" \
369 : "=t" (f) \
370 : "r" (_m), "i" (e) \
371 ); \
372 f; \
373})
374#define _ufix2float_inline(m, e) ({ \
375 uint32_t _m = m; \
376 float f; \
377 pico_default_asm( \
378 "vmov %0, %1\n" \
379 "vcvt.f32.u32 %0, %0, %2\n" \
380 : "=t" (f) \
381 : "r" (_m), "i" (e) \
382 ); \
383 f; \
384})
385
386#endif
387#if PICO_FLOAT_HAS_FLOAT_TO_FIX32_Z_CONVERSIONS
388#define float2fix_z(f, e) (__builtin_constant_p(e) && (e) >= 1 && (e) <= 32 ? _float2fix_z_inline(f, e) : float2 ## fix_z(f, e))
389#define float2ufix_z(f, e) (__builtin_constant_p(e) && (e) >= 1 && (e) <= 32 ? _float2ufix_z_inline(f, e) : float2 ## ufix_z(f, e))
390
391#define _float2fix_z_inline(f, e) ({ \
392 int32_t _m; \
393 float _f = (f); \
394 pico_default_asm( \
395 "vcvt.s32.f32 %0, %0, %2\n" \
396 "vmov %1, %0\n" \
397 : "+t" (_f), "=r" (_m) \
398 : "i" (e) \
399 ); \
400 _m; \
401})
402#define _float2ufix_z_inline(f, e) ({ \
403 uint32_t _m; \
404 float _f = (f); \
405 pico_default_asm( \
406 "vcvt.u32.f32 %0, %0, %2\n" \
407 "vmov %1, %0\n" \
408 : "+t" (_f), "=r" (_m) \
409 : "i" (e) \
410 ); \
411 _m; \
412})
413
414#endif
415#if PICO_FLOAT_HAS_FLOAT_TO_FIX32_M_CONVERSIONS
416#define float2fix(f, e) (__builtin_constant_p(e) && (e) >= 1 && (e) <= 32 ? _float2fix_inline(f, e) : float2 ## fix(f, e))
417#define float2ufix(f, e) (__builtin_constant_p(e) && (e) >= 1 && (e) <= 32 ? _float2ufix_inline(f, e) : float2 ## ufix(f, e))
418
419#define _float2fix_inline(f, e) ({ \
420 union { float _f; int32_t _i; } _u; \
421 _u._f = (f); \
422 uint rc, tmp; \
423 pico_default_asm( \
424 "vcvt.s32.f32 %0, %0, %4\n" \
425 "vmov %2, %0\n" \
426 "lsls %1, #1\n" \
427 "bls 2f\n" /* positive or zero or -zero are ok with the result we have */ \
428 "lsrs %3, %1, #24\n" \
429 "subs %3, #0x7f - %c4\n" \
430 "bcc 1f\n" /* 0 < abs(f) < 1 ^ e, so need to round down */ \
431 /* mask off all but fractional bits */ \
432 "lsls %1, %3\n" \
433 "lsls %1, #8\n" \
434 "beq 2f\n" /* integers can round towards zero */ \
435 "1:\n" \
436 /* need to subtract 1 from the result to round towards -infinity... */ \
437 /* this will never cause an overflow, because to get here we must have had a non integer/infinite value which */ \
438 /* therefore cannot have been equal to INT64_MIN when rounded towards zero */ \
439 "subs %2, #1\n" \
440 "2:\n" \
441 : "+t" (_u._f), "+r" (_u._i), "=r" (rc), "=r" (tmp) \
442 : "i" (e) \
443 ); \
444 rc; \
445})
446#define _float2ufix_inline(f, e) _float2ufix_z_inline((f), (e))
447#endif
448#endif
449
450 // exp10f doesn't always appear in math.h but is present on all our platforms even for LIB_PICO_FLOAT_COMPILER
451 // so we declare it here always
452
454 float exp10f(float x);
455
456 // sincosf doesn't always appear in math.h but is present on all our platforms even for LIB_PICO_FLOAT_COMPILER
457 // so we declare it here always
458#if __PICO_FLOAT_ARM_OPTIMIZED && PICO_C_COMPILER_IS_CLANG
459 // clang unhelpfully splits sincosf into explict calls to sin & cos
460 extern void WRAPPER_FUNC(sincosf)(float x, float *sinx, float *cosx);
461 #define sincosf(x, sinx, cosx) WRAPPER_FUNC(sincosf)(x, sinx, cosx)
462#else
464 void sincosf(float x, float *sinx, float *cosx);
465#endif
466
467#if PICO_FLOAT_HAS_POWINTF
468#if !__PICO_FLOAT_ARM_OPTIMIZED && __has_builtin(__builtin_powif)
469 static __force_inline float powintf(float f, int32_t p) {
470 return __builtin_powif(f, p);
471 }
472#else
474 float powintf(float x, int32_t y);
475#endif
476#endif
477
478#if PICO_FLOAT_HAS_FDIV_FAST
480float fdiv_fast(float n, float d);
481#endif
482
483#if PICO_FLOAT_HAS_SQRTF_FAST
485float sqrtf_fast(float f);
486#endif
488
489#undef __PICO_FLOAT_ARM_OPTIMIZED
490
491#ifdef __cplusplus
492}
493#endif
494
495#endif
496
497#endif
int32_t float2fix(float f, int e)
Convert a float to a signed 32-bit fixed-point integer with the given number of fractional bits,...
uint64_t float2uint64_z(float f)
Convert a float to an unsigned 64-bit integer, rounding towards zero. On Arm this conversion is satur...
float fdiv_fast(float n, float d)
Perform a fast floating point divide with reduced accuracy.
int32_t float2fix_z(float f, int e)
Convert a float to a signed 32-bit fixed-point integer with the given number of fractional bits,...
float uint642float(uint64_t u)
Convert an unsigned 64-bit integer to the nearest float.
float sqrtf_fast(float f)
Perform a fast floating point square-root with reduced accuracy.
uint64_t float2ufix64_z(float f, int e)
Convert a float to an unsigned 64-bit fixed-point integer with the given number of fractional bits,...
float fix642float(int64_t m, int e)
Convert a signed 64-bit fixed-point integer with the given number of fractional bits to the nearest f...
float uint2float(uint32_t u)
Convert an unsigned 32-bit integer to the nearest float.
uint32_t float2uint_z(float f)
Convert a float to an unsigned 32-bit integer, rounding towards zero On Arm this conversion is satura...
float int642float(int64_t i)
Convert a signed 64-bit integer to the nearest float.
int64_t float2fix64_z(float f, int e)
Convert a float to a signed 64-bit fixed-point integer with the given number of fractional bits,...
int64_t float2int64_z(float f)
Convert a float to a signed 64-bit integer, rounding towards zero. On Arm this conversion is saturati...
uint32_t float2ufix_z(float f, int e)
Convert a float to an unsigned 32-bit fixed-point integer with the given number of fractional bits,...
uint32_t float2uint(float f)
Convert a float to an unsigned 32-bit integer, rounding towards -Infinity. This conversion is saturat...
float ufix2float(uint32_t m, int e)
Convert an unsigned 32-bit fixed-point integer with the given number of fractional bits to the neares...
int64_t float2fix64(float f, int e)
Convert a float to a signed 64-bit fixed-point integer with the given number of fractional bits,...
uint32_t float2ufix(float f, int e)
Convert a float to an unsigned 32-bit fixed-point integer with the given number of fractional bits,...
void sincosf(float x, float *sinx, float *cosx)
Return both the sine and cosine of an angle efficiently.
float powintf(float x, int32_t y)
Raise a floating point number to an integer power.
uint64_t float2uint64(float f)
Convert a float to an unsigned 64-bit integer, rounding towards -Infinity. This conversion is saturat...
uint64_t float2ufix64(float f, int e)
Convert a float to an unsigned 64-bit fixed-point integer with the given number of fractional bits,...
int64_t float2int64(float f)
Convert a float to a signed 64-bit integer, rounding towards -Infinity. This conversion is saturating...
float ufix642float(uint64_t m, int e)
Convert an unsigned 64-bit fixed-point integer with the given number of fractional bits to the neares...
int32_t float2int(float f)
Convert a float to a signed 32-bit integer, rounding towards -Infinity. This conversion is saturating...
float fix2float(int32_t m, int e)
Convert a signed 32-bit fixed-point integer with the given number of fractional bits to the nearest f...
float exp10f(float x)
Evaluate 10.0f to the power of the given value.
Definition float_math.c:329
int32_t float2int_z(float f)
Convert a float to a signed 32-bit integer, rounding towards zero. On Arm this conversion is saturati...
float int2float(int32_t i)
Convert a signed 32-bit integer to the nearest float.
#define __force_inline
Attribute to force inlining of a function regardless of optimization level.
Definition compiler.h:128