ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
mdl_state_decimal.c
Go to the documentation of this file.
1
8#include <stdint.h>
9#include <string.h>
10
11#include "mdl_state_internal.h"
12#include "ra8_attributes.h"
13
15typedef enum : uint8_t {
18
32
34typedef struct {
36 uint8_t used;
38
47{
48 memset(big, 0, sizeof(*big));
49 big->word[0] = (uint32_t)value;
50 big->word[1] = (uint32_t)(value >> 32U);
51 big->used = (uint8_t)((big->word[1] != 0U) ? 2U : 1U);
52}
53
62{
63 while ((big->used > 1U) && (big->word[big->used - 1U] == 0U)) {
64 --big->used;
65 }
66}
67
76{
77 if ((big->used == 1U) && (big->word[0] == 0U)) {
78 return 0U;
79 }
80 uint32_t high = big->word[big->used - 1U];
81 uint8_t bits = 0U;
82 while (high != 0U) {
83 high >>= 1U;
84 ++bits;
85 }
86 return (uint16_t)(((uint16_t)(big->used - 1U) * 32U) + bits);
87}
88
97{
98 uint64_t carry = 0U;
99 for (uint8_t i = 0U; i < big->used; ++i) {
100 const uint64_t product = ((uint64_t)big->word[i] * factor) + carry;
101 big->word[i] = (uint32_t)product;
102 carry = product >> 32U;
103 }
104 if (carry != 0U) {
105 if (big->used >= (uint8_t)k_state_big_words) {
106 return false;
107 }
108 big->word[big->used] = (uint32_t)carry;
109 ++big->used;
110 }
111 return true;
112}
113
121RA8_INTERNAL static bool
123{
124 const uint16_t words = shift / 32U;
125 const uint8_t bits = (uint8_t)(shift % 32U);
126 if (((uint16_t)src->used + words + (bits != 0U ? 1U : 0U)) > k_state_big_words) {
127 return false;
128 }
129 memset(dst, 0, sizeof(*dst));
130 uint64_t carry = 0U;
131 for (uint8_t i = 0U; i < src->used; ++i) {
132 const uint64_t value = ((uint64_t)src->word[i] << bits) | carry;
133 dst->word[(uint16_t)i + words] = (uint32_t)value;
134 carry = value >> 32U;
135 }
136 dst->used = (uint8_t)((uint16_t)src->used + words);
137 if (carry != 0U) {
138 dst->word[dst->used] = (uint32_t)carry;
139 ++dst->used;
140 }
142 return true;
143}
144
153 const mdl_state_big_t* rhs)
154{
155 if (lhs->used != rhs->used) {
156 return lhs->used > rhs->used ? 1 : -1;
157 }
158 for (uint8_t i = lhs->used; i > 0U; --i) {
159 if (lhs->word[i - 1U] != rhs->word[i - 1U]) {
160 return lhs->word[i - 1U] > rhs->word[i - 1U] ? 1 : -1;
161 }
162 }
163 return 0;
164}
165
174 const mdl_state_big_t* rhs)
175{
176 uint64_t borrow = 0U;
177 for (uint8_t i = 0U; i < lhs->used; ++i) {
178 const uint64_t subtrahend = (uint64_t)(i < rhs->used ? rhs->word[i] : 0U) + borrow;
179 const uint64_t current = lhs->word[i];
180 lhs->word[i] = (uint32_t)(current - subtrahend);
181 borrow = current < subtrahend ? 1U : 0U;
182 }
184}
185
194 const mdl_state_big_t* denominator,
195 int32_t binary_scale,
196 int32_t exponent)
197{
198 mdl_state_big_t shifted = {};
199 const int32_t shift = binary_scale - exponent;
200 if (shift >= 0) {
201 if (!internal_mdl_state_big_shift(numerator, (uint16_t)shift, &shifted)) {
202 return 1;
203 }
204 return internal_mdl_state_big_compare(&shifted, denominator);
205 }
206 if (!internal_mdl_state_big_shift(denominator, (uint16_t)-shift, &shifted)) {
207 return -1;
208 }
209 return internal_mdl_state_big_compare(numerator, &shifted);
210}
211
220 const mdl_state_big_t* denominator,
221 int32_t binary_shift,
222 uint64_t* out)
223{
224 mdl_state_big_t work = {};
225 mdl_state_big_t divisor = {};
226 if (binary_shift >= 0) {
227 if (!internal_mdl_state_big_shift(numerator, (uint16_t)binary_shift, &work)) {
228 return false;
229 }
230 divisor = *denominator;
231 } else {
232 work = *numerator;
233 if (!internal_mdl_state_big_shift(denominator, (uint16_t)-binary_shift, &divisor)) {
234 return false;
235 }
236 }
237 uint64_t quotient = 0U;
238 const int32_t top =
239 (int32_t)internal_mdl_state_big_bits(&work) - (int32_t)internal_mdl_state_big_bits(&divisor);
240 if (top >= (int32_t)k_state_divide_bits) {
241 return false;
242 }
243 for (int32_t bit = top; bit >= 0; --bit) {
244 mdl_state_big_t trial = {};
245 if (!internal_mdl_state_big_shift(&divisor, (uint16_t)bit, &trial)) {
246 return false;
247 }
248 if (internal_mdl_state_big_compare(&work, &trial) >= 0) {
249 internal_mdl_state_big_subtract(&work, &trial);
250 quotient |= UINT64_C(1) << (uint32_t)bit;
251 }
252 }
253 mdl_state_big_t twice = {};
254 if (!internal_mdl_state_big_shift(&work, 1U, &twice)) {
255 return false;
256 }
257 const int comparison = internal_mdl_state_big_compare(&twice, &divisor);
258 if ((comparison > 0) || ((comparison == 0) && ((quotient & 1U) != 0U))) {
259 ++quotient;
260 }
261 *out = quotient;
262 return true;
263}
264
273 int32_t decimal_scale,
274 mdl_state_big_t* numerator,
275 mdl_state_big_t* denominator)
276{
277 internal_mdl_state_big_init(numerator, mantissa);
278 internal_mdl_state_big_init(denominator, 1U);
279 const uint32_t count = (uint32_t)(decimal_scale < 0 ? -decimal_scale : decimal_scale);
280 mdl_state_big_t* factor = decimal_scale < 0 ? denominator : numerator;
281 for (uint32_t i = 0U; i < count; ++i) {
282 if (!internal_mdl_state_big_mul(factor, (uint32_t)k_state_decimal_prime)) {
283 return false;
284 }
285 }
286 return true;
287}
288
296RA8_INTERNAL static bool internal_mdl_state_encode(uint64_t quotient,
297 int32_t exponent,
298 bool negative,
299 bool normal,
300 double* out)
301{
302 uint64_t bits = negative ? (UINT64_C(1) << (uint32_t)k_state_binary64_sign_shift) : 0U;
303 if (normal) {
304 if (quotient == (UINT64_C(1) << (uint32_t)k_state_binary64_precision_bits)) {
305 quotient >>= 1U;
306 ++exponent;
307 }
308 if ((exponent > (int32_t)k_state_binary64_exponent_max) ||
309 (quotient < (UINT64_C(1) << (uint32_t)k_state_binary64_fraction_bits))) {
310 return false;
311 }
312 bits |= (uint64_t)(exponent + (int32_t)k_state_binary64_exponent_bias)
314 bits |= quotient - (UINT64_C(1) << (uint32_t)k_state_binary64_fraction_bits);
315 } else {
316 if ((quotient == 0U) ||
317 (quotient > (UINT64_C(1) << (uint32_t)k_state_binary64_fraction_bits))) {
318 return false;
319 }
320 if (quotient == (UINT64_C(1) << (uint32_t)k_state_binary64_fraction_bits)) {
321 bits |= UINT64_C(1) << (uint32_t)k_state_binary64_fraction_bits;
322 } else {
323 bits |= quotient;
324 }
325 }
326 memcpy(out, &bits, sizeof(bits));
327 return true;
328}
329
331 int32_t decimal_scale,
332 bool negative,
333 double* out)
334{
335 if ((out == nullptr) || (decimal_scale < -(int32_t)k_state_decimal_scale_max) ||
336 (decimal_scale > (int32_t)k_state_decimal_scale_max)) {
337 return false;
338 }
339 if (mantissa == 0U) {
340 const uint64_t bits = negative ? (UINT64_C(1) << (uint32_t)k_state_binary64_sign_shift) : 0U;
341 memcpy(out, &bits, sizeof(bits));
342 return true;
343 }
344 mdl_state_big_t numerator = {};
345 mdl_state_big_t denominator = {};
346 if (!internal_mdl_state_build_rational(mantissa, decimal_scale, &numerator, &denominator)) {
347 return false;
348 }
349 int32_t exponent = (int32_t)internal_mdl_state_big_bits(&numerator) -
350 (int32_t)internal_mdl_state_big_bits(&denominator) + decimal_scale;
351 if (internal_mdl_state_compare_power(&numerator, &denominator, decimal_scale, exponent) < 0) {
352 --exponent;
353 }
354 if (exponent > (int32_t)k_state_binary64_exponent_max) {
355 return false;
356 }
357 const bool normal = exponent >= (int32_t)k_state_binary64_exponent_min;
358 const int32_t shift = normal
359 ? (decimal_scale + (int32_t)k_state_binary64_fraction_bits - exponent)
360 : (decimal_scale + (int32_t)k_state_binary64_subnormal_scale);
361 uint64_t quotient = 0U;
362 if (!internal_mdl_state_divide(&numerator, &denominator, shift, &quotient)) {
363 return false;
364 }
365 return internal_mdl_state_encode(quotient, exponent, negative, normal, out);
366}
mdl_state_big_limit_t
Fixed storage is sufficient for 17 digits multiplied or divided by 10^400.
@ k_state_big_words
Capacity of one fixed unsigned integer.
static void internal_mdl_state_big_init(mdl_state_big_t *big, uint64_t value)
Initialize a fixed integer from one uint64 value.
static bool internal_mdl_state_big_mul(mdl_state_big_t *big, uint32_t factor)
Multiply a fixed integer by one small factor.
static int internal_mdl_state_big_compare(const mdl_state_big_t *lhs, const mdl_state_big_t *rhs)
Compare two normalized fixed integers.
static void internal_mdl_state_big_trim(mdl_state_big_t *big)
Remove unused high words while retaining one zero word.
mdl_state_decimal_limit_t
Exact decimal and binary64 representation constants.
@ k_state_binary64_exponent_bias
Binary64 exponent bias.
@ k_state_binary64_exponent_max
Largest finite unbiased exponent.
@ k_state_binary64_fraction_bits
Stored binary64 fraction width.
@ k_state_binary64_exponent_min
Smallest normal unbiased exponent.
@ k_state_decimal_scale_max
Accepted absolute decimal scale.
@ k_state_binary64_subnormal_scale
Scale selecting subnormal units.
@ k_state_binary64_precision_bits
Binary64 significand precision.
@ k_state_binary64_sign_shift
Binary64 sign-bit position.
@ k_state_divide_bits
Width of the bounded quotient.
@ k_state_decimal_prime
Odd factor of decimal radix.
static bool internal_mdl_state_build_rational(uint64_t mantissa, int32_t decimal_scale, mdl_state_big_t *numerator, mdl_state_big_t *denominator)
Build the odd rational factors for a decimal value.
static uint16_t internal_mdl_state_big_bits(const mdl_state_big_t *big)
Return the significant bit count of a fixed integer.
static bool internal_mdl_state_encode(uint64_t quotient, int32_t exponent, bool negative, bool normal, double *out)
Encode one rounded quotient as finite binary64.
static bool internal_mdl_state_divide(const mdl_state_big_t *numerator, const mdl_state_big_t *denominator, int32_t binary_shift, uint64_t *out)
Divide one scaled rational and round to nearest-even.
static int internal_mdl_state_compare_power(const mdl_state_big_t *numerator, const mdl_state_big_t *denominator, int32_t binary_scale, int32_t exponent)
Compare a scaled rational against one exact power of two.
static bool internal_mdl_state_big_shift(const mdl_state_big_t *src, uint16_t shift, mdl_state_big_t *dst)
Copy one fixed integer shifted left by an exact bit count.
static void internal_mdl_state_big_subtract(mdl_state_big_t *lhs, const mdl_state_big_t *rhs)
Subtract a no-larger fixed integer from another.
bool priv_mdl_state_decimal_to_binary64(uint64_t mantissa, int32_t decimal_scale, bool negative, double *out)
Convert one exact bounded decimal rational to binary64.
Module-private validation shared by the state model and codec.
Annotation-attribute framework macros for ra8-firmware.
#define RA8_PRIV
Module-private helper: shared across TUs but only inside one library.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
void * memset(void *dst, int value, size_t n)
Fill memory with a constant byte value.
void * memcpy(void *dst, const void *src, size_t n)
Copy memory area between non-overlapping regions.
Little-endian base-2^32 unsigned integer.
uint8_t used
Significant word count.
uint32_t word[k_state_big_words]
Little-endian magnitude words.