Branch data Line data Source code
1 : : // Copyright 2019-2026 David Robillard <d@drobilla.net> 2 : : // SPDX-License-Identifier: ISC 3 : : 4 : : #include "scientific.h" 5 : : #include "big_decimal.h" 6 : : #include "int_math.h" 7 : : #include "result.h" 8 : : #include "write_utils.h" 9 : : 10 : : #include <exess/exess.h> 11 : : 12 : : #include <stdlib.h> 13 : : #include <string.h> 14 : : 15 : : typedef struct { 16 : : size_t length; 17 : : const char* string; 18 : : } SpecialCase; 19 : : 20 : : static const SpecialCase special_cases[] = {{3U, "NaN"}, 21 : : {4U, "-INF"}, 22 : : {3U, "INF"}, 23 : : {6U, "-0.0E0"}, 24 : : {5U, "0.0E0"}}; 25 : : 26 : : EXESS_CONST_FUNC static size_t 27 : 27526 : scientific_string_length(const BigDecimal value, const unsigned n_expt_digits) 28 : : { 29 [ + + ]: 27526 : if (value.kind < EXESS_NEGATIVE) { 30 : 1094 : return special_cases[value.kind].length; 31 : : } 32 : : 33 : 26432 : return (value.n_digits + n_expt_digits + 34 : 26432 : !!(value.kind == EXESS_NEGATIVE) + // Sign 35 : 26432 : 1U + // Decimal point 36 : 26432 : !!(value.n_digits <= 1) + // Added '0' after point 37 : 26432 : 1U + // 'E' 38 : 26432 : !!(value.expt < 1)); // Exponent sign 39 : : } 40 : : 41 : : EXESS_NONBLOCKING ExessResult 42 : 27526 : write_scientific(const BigDecimal value, 43 : : const char* const digits, 44 : : const size_t buf_size, 45 : : char* const buf) 46 : : { 47 : 27526 : const int expt = value.expt - 1; 48 : 27526 : unsigned abs_expt = (unsigned)abs(expt); 49 : 27526 : const unsigned n_expt_digits = (unsigned)exess_num_digits(abs_expt); 50 : 27526 : const size_t length = scientific_string_length(value, n_expt_digits); 51 [ + + ]: 27526 : if (length >= buf_size) { 52 : 300 : return RESULT(EXESS_NO_SPACE, length); 53 : : } 54 : : 55 [ + + ]: 27226 : if (value.kind < EXESS_NEGATIVE) { 56 : 991 : return write_special(special_cases[value.kind].length, 57 : 991 : special_cases[value.kind].string, 58 : : buf_size, 59 : : buf); 60 : : } 61 : : 62 : 26235 : size_t i = 0; 63 [ + + ]: 26235 : if (value.kind == EXESS_NEGATIVE) { 64 : 8 : buf[i++] = '-'; 65 : : } 66 : : 67 : : // Write mantissa, with decimal point after the first (normal form) 68 : 26235 : buf[i++] = digits[0]; 69 : 26235 : buf[i++] = '.'; 70 [ + + ]: 26235 : if (value.n_digits > 1) { 71 : 26207 : memcpy(buf + i, digits + 1, value.n_digits - 1U); 72 : 26207 : i += value.n_digits - 1U; 73 : : } else { 74 : 28 : buf[i++] = '0'; 75 : : } 76 : : 77 : : // Write exponent 78 : : 79 : 26235 : buf[i++] = 'E'; 80 [ + + ]: 26235 : if (expt < 0) { 81 : 12034 : buf[i++] = '-'; 82 : : } 83 : : 84 : 26235 : char* s = buf + i + n_expt_digits; 85 : : 86 : 26235 : *s-- = '\0'; 87 : : do { 88 : 54364 : *s-- = (char)('0' + (abs_expt % 10)); 89 [ + + ]: 54364 : } while ((abs_expt /= 10) > 0); 90 : : 91 : 26235 : return RESULT(EXESS_SUCCESS, i + n_expt_digits); 92 : : }