AFBR-S50 API Reference Manual  v1.6.5
AFBR-S50 Time-of-Flight Sensor SDK for Embedded Software
fp_div.h
Go to the documentation of this file.
1 /*************************************************************************/
37 #ifndef FP_DIV_H
38 #define FP_DIV_H
39 #ifdef __cplusplus
40 extern "C" {
41 #endif
42 
43 /*!***************************************************************************
44  * @addtogroup argus_fp
45  * @{
46  *****************************************************************************/
47 
48 #include "fp_def.h"
49 #include "int_math.h"
50 
51 /*!***************************************************************************
52  * Set to use hardware division (Cortex-M3/4) over software division (Cortex-M0/1).
53  *****************************************************************************/
54 #ifndef FP_USE_HW_DIV
55 #define FP_USE_HW_DIV 0
56 #endif
57 
58 /*!***************************************************************************
59  * @brief 32-bit implementation of an Q15.16 division.
60  *
61  * @details Algorithm to evaluate a/b, where b is in Q15.16 format, on a 32-bit
62  * architecture with maximum precision.
63  * The result is correctly rounded and given as the input format.
64  * Division by 0 yields max. values determined by signs of numerator.
65  * Too high/low results are truncated to max/min values.
66  *
67  * Depending on the architecture, the division is implemented with a 64-bit
68  * division and shifting (Cortex-M3/4) or as a fast software algorithm
69  * (Cortex-M0/1) wich runs fast on processors without hardware division.
70  *
71  * @see https://code.google.com/archive/p/libfixmath
72  *
73  * @param a Numerator in any Qx.y format
74  * @param b Denominator in Q15.16 format
75  * @return Result = a/b in the same Qx.y format as the input parameter a.
76  *****************************************************************************/
77 inline int32_t fp_div16(int32_t a, q15_16_t b)
78 {
79  //assert(b);
80  if (b == 0) return a < 0 ? INT32_MIN : INT32_MAX;
81 
82 #if FP_USE_HW_DIV
83  // Tested on Cortex-M4, it takes approx. 75% of the
84  // software algorithm below.
85  int64_t c = ((int64_t) a) << 30U;
86  if ((uint32_t) (a ^ b) & 0x80000000U)
87  {
88  c = (((-c) / b) + (1 << 13U)) >> 14U;
89  if (c > 0x80000000U) return INT32_MIN;
90  return (int32_t)-c;
91  }
92  else
93  {
94  c = ((c / b) + (1 << 13U)) >> 14U;
95  if (c > (int64_t)INT32_MAX) return INT32_MAX;
96  return (int32_t)c;
97  }
98 
99 #else
100  // This uses the basic binary restoring division algorithm.
101  // It appears to be faster to do the whole division manually than
102  // trying to compose a 64-bit divide out of 32-bit divisions on
103  // platforms without hardware divide.
104  // Tested on Cortex-M0, it takes approx. 33% of the time of the
105  // 64-bit version above.
106 
107  uint32_t remainder = absval(a);
108  uint32_t divider = absval(b);
109 
110  uint32_t quotient = 0;
111  uint32_t bit = 0x10000U;
112 
113  /* The algorithm requires D >= R */
114  while (divider < remainder)
115  {
116  divider <<= 1U;
117  bit <<= 1U;
118  }
119 
120  if (!bit)
121  {
122  if ((uint32_t)(a ^ b) & 0x80000000U) // return truncated values
123  {
124  return INT32_MIN;
125  }
126  else
127  {
128  return INT32_MAX;
129  }
130  }
131 
132  if (divider & 0x80000000U)
133  {
134  // Perform one step manually to avoid overflows later.
135  // We know that divider's bottom bit is 0 here.
136  if (remainder >= divider)
137  {
138  quotient |= bit;
139  remainder -= divider;
140  }
141  divider >>= 1U;
142  bit >>= 1U;
143  }
144 
145  /* Main division loop */
146  while (bit && remainder)
147  {
148  if (remainder >= divider)
149  {
150  quotient |= bit;
151  remainder -= divider;
152  }
153  remainder <<= 1U;
154  bit >>= 1U;
155  }
156 
157  if (remainder >= divider)
158  {
159  quotient++;
160  }
161 
162  uint32_t result = quotient;
163 
164  /* Figure out the sign of result */
165  if ((uint32_t)(a ^ b) & 0x80000000U)
166  {
167  return (int32_t)-result;
168  }
169  else
170  {
171  // fix 05.10.2023; the corner case, when result == INT32_MAX + 1:
172  // Catch the wraparound (to INT32_MIN) and truncate instead.
173  if (quotient > INT32_MAX) return INT32_MAX;
174  return (int32_t)result;
175  }
176 
177 #endif
178 }
179 
181 #ifdef __cplusplus
182 } // extern "C"
183 #endif
184 #endif /* FP_DIV_H */
int_math.h
This file is part of the AFBR-S50 API.
fp_div16
int32_t fp_div16(int32_t a, q15_16_t b)
32-bit implementation of an Q15.16 division.
Definition: fp_div.h:77
fp_def.h
This file is part of the AFBR-S50 API.
absval
uint32_t absval(int32_t x)
Calculates the absolute value.
Definition: int_math.h:155
q15_16_t
int32_t q15_16_t
Signed fixed point number: Q15.16.
Definition: fp_def.h:515