/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include <stdint.h> #include <iso646.h> #include <math.h> #include <inttypes.h> #include <stdio.h> #include <stdlib.h> #include <float.h> #include “tgmath_avr.h“ /* C11 Overload #define def_max(a, b) (((a) >= (b)) ? (a) : (b)) #define def_min(a, b) (((a) < (b)) ? (a) : (b)) #define read_bit(_source_bits, _source_width, _n) _Generic(_source_bits, uint8_t: read_bit_ui8, \ uint16_t: read_bit_ui16, \ uint32_t: read_bit_ui32, \ uint64_t: read_bit_ui64, \ default: read_bit_ui64 \ )(_source_bits, _source_width, _n) #define write_bit(_source_bits, _source_width, _n, _a_bit) _Generic(_source_bits, uint8_t: write_bit_ui8, \ uint16_t: write_bit_ui16, \ uint32_t: write_bit_ui32, \ uint64_t: write_bit_ui64, \ default: write_bit_ui64 \ )(_source_bits, _source_width, _n, _a_bit) #define xor_bit(_source_bits, _source_width, _n, _a_bit) _Generic(_source_bits, uint8_t: xor_bit_ui8, \ uint16_t: xor_bit_ui16, \ uint32_t: xor_bit_ui32, \ uint64_t: xor_bit_ui64, \ default: xor_bit_ui64 \ )(_source_bits, _source_width, _n, _a_bit) #define random_round(_x, _rounded_to_exp10) _Generic(_x, float: random_round_f, \ double: random_round_d, \ default: random_round_f \ )(_x, _rounded_to_exp10) #define integer_number_to_string(_input_number, _leader_character, _display_width, _numeric_string, _array_len) _Generic(_input_number, int8_t: integer_number_to_string_i8, \ int16_t: integer_number_to_string_i16, \ int32_t: integer_number_to_string_i32, \ default: integer_number_to_string_i32 \ )(_input_number, _leader_character, _display_width, _numeric_string, _array_len) #define floating_number_to_string(_input_number, _decimal_digits, _numeric_string, _array_len) _Generic(_input_number, float: floating_number_to_string_f, \ double: floating_number_to_string_d, \ default: floating_number_to_string_f \ )(_input_number, _decimal_digits, _numeric_string, _array_len) */ //Begin GCC Overload #define max(_a, _b) \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(sizeof(_a) >= sizeof(_b) ? _a : _b), int8_t), max_i8(_a, _b), \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(sizeof(_a) >= sizeof(_b) ? _a : _b), uint8_t), max_ui8(_a, _b), \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(sizeof(_a) >= sizeof(_b) ? _a : _b), int16_t), max_i16(_a, _b), \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(sizeof(_a) >= sizeof(_b) ? _a : _b), uint16_t), max_ui16(_a, _b), \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(sizeof(_a) >= sizeof(_b) ? _a : _b), int32_t), max_i32(_a, _b), \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(sizeof(_a) >= sizeof(_b) ? _a : _b), uint32_t), max_ui32(_a, _b), \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(sizeof(_a) >= sizeof(_b) ? _a : _b), int64_t), max_i64(_a, _b), \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(sizeof(_a) >= sizeof(_b) ? _a : _b), uint64_t), max_ui64(_a, _b), \ max_i64(_a, _b) \ ) \ ) \ ) \ ) \ ) \ ) \ ) \ ) #define read_bit(_source_bits, _source_width, _n) \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(_source_bits), uint8_t), read_bit_ui8(_source_bits, _source_width, _n), \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(_source_bits), uint16_t), read_bit_ui16(_source_bits, _source_width, _n), \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(_source_bits), uint32_t), read_bit_ui32(_source_bits, _source_width, _n), \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(_source_bits), uint64_t), read_bit_ui64(_source_bits, _source_width, _n), \ read_bit_ui64(_source_bits, _source_width, _n) \ ) \ ) \ ) \ ) #define write_bit(_source_bits, _source_width, _n, _a_bit) \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(_source_bits), uint8_t), write_bit_ui8(_source_bits, _source_width, _n, _a_bit), \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(_source_bits), uint16_t), write_bit_ui16(_source_bits, _source_width, _n, _a_bit), \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(_source_bits), uint32_t), write_bit_ui32(_source_bits, _source_width, _n, _a_bit), \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(_source_bits), uint64_t), write_bit_ui64(_source_bits, _source_width, _n, _a_bit), \ write_bit_ui64(_source_bits, _source_width, _n, _a_bit) \ ) \ ) \ ) \ ) #define xor_bit(_source_bits, _source_width, _n, _a_bit) \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(_source_bits), uint8_t), xor_bit_ui8(_source_bits, _source_width, _n, _a_bit), \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(_source_bits), uint16_t), xor_bit_ui16(_source_bits, _source_width, _n, _a_bit), \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(_source_bits), uint32_t), xor_bit_ui32(_source_bits, _source_width, _n, _a_bit), \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(_source_bits), uint64_t), xor_bit_ui64(_source_bits, _source_width, _n, _a_bit), \ xor_bit_ui64(_source_bits, _source_width, _n, _a_bit) \ ) \ ) \ ) \ ) #define random_round(_x, _rounded_to_exp10) \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(_x), float), random_round_f(_x, _rounded_to_exp10), \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(_x),double), random_round_d(_x, _rounded_to_exp10), \ random_round_f(_x, _rounded_to_exp10) \ ) \ ) #define integer_number_to_string(_input_number, _leader_character, _display_width, _numeric_string, _array_len) \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(_input_number), int8_t), integer_number_to_string_i8(_input_number, _leader_character, _display_width, _numeric_string, _array_len), \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(_input_number), int16_t), integer_number_to_string_i16(_input_number, _leader_character, _display_width, _numeric_string, _array_len), \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(_input_number), int32_t), integer_number_to_string_i32(_input_number, _leader_character, _display_width, _numeric_string, _array_len), \ integer_number_to_string_i32(_input_number, _leader_character, _display_width, _numeric_string, _array_len)) \ ) \ ) \ ) #define floating_number_to_string(_input_number, _decimal_digits, _numeric_string, _array_len) \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(_input_number), float), floating_number_to_string_f(_input_number, _decimal_digits, _numeric_string, _array_len), \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(_input_number),double), floating_number_to_string_d(_input_number, _decimal_digits, _numeric_string, _array_len), \ floating_number_to_string_f(_input_number, _decimal_digits, _numeric_string, _array_len) \ ) \ ) //End GCC Overload. inline int8_t max_i8(int8_t a, int8_t b) { return a > b ? a : b; } inline uint8_t max_ui8(uint8_t a, uint8_t b) { return a > b ? a : b; } inline int16_t max_i16(int16_t a, int16_t b) { return a > b ? a : b; } inline uint16_t max_ui16(uint16_t a, uint16_t b) { return a > b ? a : b; } inline int32_t max_i32(int32_t a, int32_t b) { return a > b ? a : b; } inline uint32_t max_ui32(uint32_t a, uint32_t b) { return a > b ? a : b; } inline int64_t max_i64(int64_t a, int64_t b) { return a > b ? a : b; } inline uint64_t max_ui64(uint64_t a, uint64_t b) { return a > b ? a : b; } uint8_t read_bit_ui8(uint8_t source_bits, uint_fast8_t source_width, uint_fast8_t n) //Lowest order is 0 { const uint_fast8_t MAXIMUM_WIDTH_BIT = 8; if ((source_bits >> source_width) not_eq 0) { return source_bits; } if (source_width > MAXIMUM_WIDTH_BIT) { return source_bits; } if (n >= source_width) { return source_bits; } return (source_bits >> n) bitand ((uint8_t)0x01); } uint16_t read_bit_ui16(uint16_t source_bits, uint_fast8_t source_width, uint_fast8_t n) //Lowest order is 0 { const uint_fast8_t MAXIMUM_WIDTH_BIT = 16; if ((source_bits >> source_width) not_eq 0) { return source_bits; } if (source_width > MAXIMUM_WIDTH_BIT) { return source_bits; } if (n >= source_width) { return source_bits; } return (source_bits >> n) bitand ((uint16_t)0x01); } uint32_t read_bit_ui32(uint32_t source_bits, uint_fast8_t source_width, uint_fast8_t n) //Lowest order is 0 { const uint_fast8_t MAXIMUM_WIDTH_BIT = 32; if ((source_bits >> source_width) not_eq 0) { return source_bits; } if (source_width > MAXIMUM_WIDTH_BIT) { return source_bits; } if (n >= source_width) { return source_bits; } return (source_bits >> n) bitand ((uint32_t)0x01); } uint64_t read_bit_ui64(uint64_t source_bits, uint_fast8_t source_width, uint_fast8_t n) //Lowest order is 0 { const uint_fast8_t MAXIMUM_WIDTH_BIT = 64; if ((source_bits >> source_width) not_eq 0) { return source_bits; } if (source_width > MAXIMUM_WIDTH_BIT) { return source_bits; } if (n >= source_width) { return source_bits; } return (source_bits >> n) bitand ((uint64_t)0x01); } uint8_t write_bit_ui8(uint8_t source_bits, uint_fast8_t source_width, uint_fast8_t n, uint_fast8_t a_bit) //Lowest order is 0 { const uint_fast8_t MAXIMUM_WIDTH_BIT = 8; if ((source_bits >> source_width) not_eq 0) { return source_bits; } if (source_width > MAXIMUM_WIDTH_BIT) { return source_bits; } if (n >= source_width) { return source_bits; } if ((a_bit >> 1) not_eq 0) { return source_bits; } (a_bit == 0) ? (source_bits and_eq (compl(((uint8_t)0x01) << n))) : (source_bits or_eq (((uint8_t)0x01) << n)); return source_bits; } uint16_t write_bit_ui16(uint16_t source_bits, uint_fast8_t source_width, uint_fast8_t n, uint_fast8_t a_bit) //Lowest order is 0 { const uint_fast8_t MAXIMUM_WIDTH_BIT = 16; if ((source_bits >> source_width) not_eq 0) { return source_bits; } if (source_width > MAXIMUM_WIDTH_BIT) { return source_bits; } if (n >= source_width) { return source_bits; } if ((a_bit >> 1) not_eq 0) { return source_bits; } (a_bit == 0) ? (source_bits and_eq (compl(((uint16_t)0x01) << n))) : (source_bits or_eq (((uint16_t)0x01) << n)); return source_bits; } uint32_t write_bit_ui32(uint32_t source_bits, uint_fast8_t source_width, uint_fast8_t n, uint_fast8_t a_bit) //Lowest order is 0 { const uint_fast8_t MAXIMUM_WIDTH_BIT = 32; if ((source_bits >> source_width) not_eq 0) { return source_bits; } if (source_width > MAXIMUM_WIDTH_BIT) { return source_bits; } if (n >= source_width) { return source_bits; } if ((a_bit >> 1) not_eq 0) { return source_bits; } (a_bit == 0) ? (source_bits and_eq (compl(((uint32_t)0x01) << n))) : (source_bits or_eq (((uint32_t)0x01) << n)); return source_bits; } uint64_t write_bit_ui64(uint64_t source_bits, uint_fast8_t source_width, uint_fast8_t n, uint_fast8_t a_bit) //Lowest order is 0 { const uint_fast8_t MAXIMUM_WIDTH_BIT = 64; if ((source_bits >> source_width) not_eq 0) { return source_bits; } if (source_width > MAXIMUM_WIDTH_BIT) { return source_bits; } if (n >= source_width) { return source_bits; } if ((a_bit >> 1) not_eq 0) { return source_bits; } (a_bit == 0) ? (source_bits and_eq (compl(((uint64_t)0x01) << n))) : (source_bits or_eq (((uint64_t)0x01) << n)); return source_bits; } uint8_t xor_bit_ui8(uint8_t source_bits, uint_fast8_t source_width, uint_fast8_t n, uint_fast8_t a_bit) //Lowest order is 0 { const uint_fast8_t MAXIMUM_WIDTH_BIT = 8; if ((source_bits >> source_width) not_eq 0) { return source_bits; } if (source_width > MAXIMUM_WIDTH_BIT) { return source_bits; } if (n >= source_width) { return source_bits; } if ((a_bit >> 1) not_eq 0) { return source_bits; } return source_bits xor (((uint8_t)a_bit) << n); } uint16_t xor_bit_ui16(uint16_t source_bits, uint_fast8_t source_width, uint_fast8_t n, uint_fast8_t a_bit) //Lowest order is 0 { const uint_fast8_t MAXIMUM_WIDTH_BIT = 16; if ((source_bits >> source_width) not_eq 0) { return source_bits; } if (source_width > MAXIMUM_WIDTH_BIT) { return source_bits; } if (n >= source_width) { return source_bits; } if ((a_bit >> 1) not_eq 0) { return source_bits; } return source_bits xor (((uint16_t)a_bit) << n); } uint32_t xor_bit_ui32(uint32_t source_bits, uint_fast8_t source_width, uint_fast8_t n, uint_fast8_t a_bit) //Lowest order is 0 { const uint_fast8_t MAXIMUM_WIDTH_BIT = 32; if ((source_bits >> source_width) not_eq 0) { return source_bits; } if (source_width > MAXIMUM_WIDTH_BIT) { return source_bits; } if (n >= source_width) { return source_bits; } if ((a_bit >> 1) not_eq 0) { return source_bits; } return source_bits xor (((uint32_t)a_bit) << n); } uint64_t xor_bit_ui64(uint64_t source_bits, uint_fast8_t source_width, uint_fast8_t n, uint_fast8_t a_bit) //Lowest order is 0 { const uint_fast8_t MAXIMUM_WIDTH_BIT = 64; if ((source_bits >> source_width) not_eq 0) { return source_bits; } if (source_width > MAXIMUM_WIDTH_BIT) { return source_bits; } if (n >= source_width) { return source_bits; } if ((a_bit >> 1) not_eq 0) { return source_bits; } return source_bits xor (((uint64_t)a_bit) << n); } float random_round_f(float x, int_fast8_t rounded_to_exp10) { const uint_fast8_t MAX_SIGNIFICANT_FIGURES = FLT_DIG - 1; if (not isfinite(x)) { return x; } float absolute_value = fabs(x); if ((floor(log10(absolute_value)) - rounded_to_exp10) >= MAX_SIGNIFICANT_FIGURES) { return x; } float integer_part, decimal_part; decimal_part = modff(absolute_value * pow(10, -rounded_to_exp10), &integer_part); if (decimal_part > 0.5) { integer_part += 1; } else { if (decimal_part == 0.5) { integer_part += rand() % 2; } } return copysign((integer_part + 0.1) * pow(10, rounded_to_exp10), x); } double random_round_d(double x, int_fast8_t rounded_to_exp10) { const uint_fast8_t MAX_SIGNIFICANT_FIGURES = DBL_DIG - 1; if (not isfinite(x)) { return x; } double absolute_value = fabs(x); if ((floor(log10(absolute_value)) - rounded_to_exp10) >= MAX_SIGNIFICANT_FIGURES) { return x; } double integer_part, decimal_part; decimal_part = modf(absolute_value * pow(10, -rounded_to_exp10), &integer_part); if (decimal_part > 0.5) { integer_part += 1; } else { if (decimal_part == 0.5) { integer_part += rand() % 2; } } return copysign((integer_part + 0.1) * pow(10, rounded_to_exp10), x); } uint_fast8_t integer_number_to_string_i8(int8_t input_number, char leader_character, uint_fast8_t display_width, char numeric_string[], uint_fast8_t array_len) //input_number range is INT8_MAX to INT8_MIN. Returns the numeric string length. { const uint_fast8_t INTERMEDIATE_MAX_WIDTH = 1 + (floor(log10(-INT8_MIN)) + 1); //sign + Max significant figures char intermediate_string[INTERMEDIATE_MAX_WIDTH + 1]; if (leader_character < '\x0') { return 0; } if (display_width >= array_len) { return 0; } if (array_len <= 1) { return 0; } int_fast8_t intermediate_len = sprintf(intermediate_string, "%-"PRIi8, input_number); if (intermediate_len > display_width) { return 0; } int_fast8_t i = 0; int_fast8_t n = display_width - (intermediate_len + 1); if (isgraph(leader_character)) { while (i <= n) { numeric_string[i] = leader_character; ++i; } } n = i + intermediate_len; int_fast8_t j = 0; while (i <= n) { numeric_string[i] = intermediate_string[j]; ++i; ++j; } i -= 1; return i; //Returns the numeric string length } uint_fast8_t integer_number_to_string_i16(int16_t input_number, char leader_character, uint_fast8_t display_width, char numeric_string[], uint_fast8_t array_len) //input_number range is INT16_MAX to INT16_MIN. Returns the numeric string length. { const uint_fast8_t INTERMEDIATE_MAX_WIDTH = 1 + (floor(log10(-(float)INT16_MIN)) + 1); //sign + Max significant figures char intermediate_string[INTERMEDIATE_MAX_WIDTH + 1]; if (leader_character < '\x0') { return 0; } if (display_width >= array_len) { return 0; } if (array_len <= 1) { return 0; } int_fast8_t intermediate_len = sprintf(intermediate_string, "%-"PRIi16, input_number); if (intermediate_len > display_width) { return 0; } int_fast8_t i = 0; int_fast8_t n = display_width - (intermediate_len + 1); if (isgraph(leader_character)) { while (i <= n) { numeric_string[i] = leader_character; ++i; } } n = i + intermediate_len; int_fast8_t j = 0; while (i <= n) { numeric_string[i] = intermediate_string[j]; ++i; ++j; } i -= 1; return i; //Returns the numeric string length } uint_fast8_t integer_number_to_string_i32(int32_t input_number, char leader_character, uint_fast8_t display_width, char numeric_string[], uint_fast8_t array_len) //input_number range is INT32_MAX to INT32_MIN. Returns the numeric string length. { const uint_fast8_t INTERMEDIATE_MAX_WIDTH = 1 + (floor(log10(-(double)INT32_MIN)) + 1); //sign + Max significant figures char intermediate_string[INTERMEDIATE_MAX_WIDTH + 1]; if (leader_character < '\x0') { return 0; } if (display_width >= array_len) { return 0; } if (array_len <= 1) { return 0; } int_fast8_t intermediate_len = sprintf(intermediate_string, "%-"PRIi32, input_number); if (intermediate_len > display_width) { return 0; } int_fast8_t i = 0; int_fast8_t n = display_width - (intermediate_len + 1); if (isgraph(leader_character)) { while (i <= n) { numeric_string[i] = leader_character; ++i; } } n = i + intermediate_len; int_fast8_t j = 0; while (i <= n) { numeric_string[i] = intermediate_string[j]; ++i; ++j; } i -= 1; return i; //Returns the numeric string length } uint_fast8_t floating_number_to_string_f(float input_number, uint_fast8_t decimal_digits, char numeric_string[], uint_fast8_t array_len) //input_number range is (pow(10, MAX_SIGNIFICANT_FIGURES) - 1) to pow(10, -MIN_DECIMAL). Returns the numeric string length. The random roundoff, pay attention to the random number seed. { const uint_fast8_t MAX_SIGNIFICANT_FIGURES = FLT_DIG - 1; const uint_fast8_t MIN_DECIMAL = MAX_SIGNIFICANT_FIGURES + 1; char temp_string[1 + (decimal_digits == 0 ? MAX_SIGNIFICANT_FIGURES : max((MAX_SIGNIFICANT_FIGURES + 1), (1 + 1 + MIN_DECIMAL))) + 1]; //a sign + (decimal_digits == 0 ? MAX_SIGNIFICANT_FIGURES : max((MAX_SIGNIFICANT_FIGURES + a decimal), (a zero + a decimal + MIN_DECIMAL))) + '\x0' float absolute_value; float num_exp10; if (not isfinite(input_number)) { return 0; } if (decimal_digits > MIN_DECIMAL) { return 0; } absolute_value = fabs(input_number); num_exp10 = floor(log10(absolute_value)); if (num_exp10 >= MAX_SIGNIFICANT_FIGURES) { //Value ultra range error return 0; } float num_tail_exp10 = fmax((num_exp10 + 1 - MAX_SIGNIFICANT_FIGURES), (-((int_fast8_t)decimal_digits))); //Plus integer part input_number = random_round_d(absolute_value, lround(num_tail_exp10)); absolute_value = fabs(input_number); num_exp10 = floor(log10(absolute_value)); int_fast8_t num_int_exp10 = lround(num_exp10); if (num_int_exp10 >= MAX_SIGNIFICANT_FIGURES) { //Value ultra range error return 0; } num_tail_exp10 = fmax((num_exp10 + 1 - MAX_SIGNIFICANT_FIGURES), (-((int_fast8_t)decimal_digits))); //Plus integer part int_fast8_t num_int_tail_exp10 = lround(num_tail_exp10); if (num_int_tail_exp10 > num_int_exp10) { num_exp10 = num_tail_exp10; num_int_exp10 = num_int_tail_exp10; } uint_fast8_t num_count = num_int_exp10 - num_int_tail_exp10 + 1; float intermediate_number = absolute_value * pow(10, -num_exp10); float digital_character[num_count]; for (int_fast8_t i = 0; i < num_count; ++i) { intermediate_number = modff(intermediate_number, &digital_character[i]) * 10; } int_fast8_t i = 0; uint_fast8_t n; if ((input_number < 0 ? 1 : 0) == 1) { temp_string[i] = '-'; ++i; } int_fast8_t j = 0; if (num_int_exp10 >= 0) { n = i + num_int_exp10; while(i <= n) { temp_string[i] = (char)(lround(digital_character[j]) + 0x30); //0x30 == '0' ++i; ++j; } if ((num_int_tail_exp10 < 0 ? 1 : 0) == 1) { temp_string[i] = '.'; ++i; } n = i + abs(num_int_tail_exp10); while(i < n) { temp_string[i] = (char)(lround(digital_character[j]) + 0x30); //0x30 == '0' ++i; ++j; } } else { temp_string[i] = '0'; ++i; temp_string[i] = '.'; ++i; n = i + (-1 - num_int_exp10); while(i < n) { temp_string[i] = '0'; ++i; } n = i + (num_int_exp10 - num_int_tail_exp10); while(i <= n) { temp_string[i] = (char)(lround(digital_character[j]) + 0x30); //0x30 == '0' ++i; ++j; } } temp_string[i] = '\x0'; n = i; if ((n + 1) > array_len) { return 0; } for (i=0; i <= n; ++i) { numeric_string[i] = temp_string[i]; } return n; //Returns the numeric string length } uint_fast8_t floating_number_to_string_d(double input_number, uint_fast8_t decimal_digits, char numeric_string[], uint_fast8_t array_len) //input_number range is (pow(10, MAX_SIGNIFICANT_FIGURES) - 1) to pow(10, -MIN_DECIMAL). Returns the numeric string length. The random roundoff, pay attention to the random number seed. { const uint_fast8_t MAX_SIGNIFICANT_FIGURES = DBL_DIG - 1; const uint_fast8_t MIN_DECIMAL = MAX_SIGNIFICANT_FIGURES + 1; char temp_string[1 + (decimal_digits == 0 ? MAX_SIGNIFICANT_FIGURES : max((MAX_SIGNIFICANT_FIGURES + 1), (1 + 1 + MIN_DECIMAL))) + 1]; //a sign + (decimal_digits == 0 ? MAX_SIGNIFICANT_FIGURES : max((MAX_SIGNIFICANT_FIGURES + a decimal), (a zero + a decimal + MIN_DECIMAL))) + '\x0' double absolute_value; double num_exp10; if (not isfinite(input_number)) { return 0; } if (decimal_digits > MIN_DECIMAL) { return 0; } absolute_value = fabs(input_number); num_exp10 = floor(log10(absolute_value)); if (num_exp10 >= MAX_SIGNIFICANT_FIGURES) { //Value ultra range error return 0; } double num_tail_exp10 = fmax((num_exp10 + 1 - MAX_SIGNIFICANT_FIGURES), (-((int_fast8_t)decimal_digits))); //Plus integer part input_number = random_round_d(absolute_value, lround(num_tail_exp10)); absolute_value = fabs(input_number); num_exp10 = floor(log10(absolute_value)); int_fast8_t num_int_exp10 = lround(num_exp10); if (num_int_exp10 >= MAX_SIGNIFICANT_FIGURES) { //Value ultra range error return 0; } num_tail_exp10 = fmax((num_exp10 + 1 - MAX_SIGNIFICANT_FIGURES), (-((int_fast8_t)decimal_digits))); //Plus integer part int_fast8_t num_int_tail_exp10 = lround(num_tail_exp10); if (num_int_tail_exp10 > num_int_exp10) { num_exp10 = num_tail_exp10; num_int_exp10 = num_int_tail_exp10; } uint_fast8_t num_count = num_int_exp10 - num_int_tail_exp10 + 1; double intermediate_number = absolute_value * pow(10, -num_exp10); double digital_character[num_count]; for (int_fast8_t i = 0; i < num_count; ++i) { intermediate_number = modf(intermediate_number, &digital_character[i]) * 10; } int_fast8_t i = 0; uint_fast8_t n; if ((input_number < 0 ? 1 : 0) == 1) { temp_string[i] = '-'; ++i; } int_fast8_t j = 0; if (num_int_exp10 >= 0) { n = i + num_int_exp10; while(i <= n) { temp_string[i] = (char)(lround(digital_character[j]) + 0x30); //0x30 == '0' ++i; ++j; } if ((num_int_tail_exp10 < 0 ? 1 : 0) == 1) { temp_string[i] = '.'; ++i; } n = i + abs(num_int_tail_exp10); while(i < n) { temp_string[i] = (char)(lround(digital_character[j]) + 0x30); //0x30 == '0' ++i; ++j; } } else { temp_string[i] = '0'; ++i; temp_string[i] = '.'; ++i; n = i + (-1 - num_int_exp10); while(i < n) { temp_string[i] = '0'; ++i; } n = i + (num_int_exp10 - num_int_tail_exp10); while(i <= n) { temp_string[i] = (char)(lround(digital_character[j]) + 0x30); //0x30 == '0' ++i; ++j; } } temp_string[i] = '\x0'; n = i; if ((n + 1) > array_len) { return 0; } for (i=0; i <= n; ++i) { numeric_string[i] = temp_string[i]; } return n; //Returns the numeric string length }
这样写出来的代码,以后换16位msp430也好换32位ARM也好,都不用修改调用代码
用防御式编程,可以更容易定位错误