diff options
Diffstat (limited to 'Build/source/libs/pplib/pplib-src/src/util/utilnumber.c')
-rw-r--r-- | Build/source/libs/pplib/pplib-src/src/util/utilnumber.c | 1177 |
1 files changed, 1177 insertions, 0 deletions
diff --git a/Build/source/libs/pplib/pplib-src/src/util/utilnumber.c b/Build/source/libs/pplib/pplib-src/src/util/utilnumber.c new file mode 100644 index 00000000000..4352c26fbd0 --- /dev/null +++ b/Build/source/libs/pplib/pplib-src/src/util/utilnumber.c @@ -0,0 +1,1177 @@ + +#include <math.h> /* for log10() and floor() */ +#include <stdio.h> /* for printf() */ + +#include "utilnumber.h" + +// todo: lookups can be chars +// change lookup arrays to some __name to discourage accessing them directly; they always should be accessed via macros; base16_value() base16_digit() +// + +const int base10_lookup[] = { + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 +}; + +const int base16_lookup[] = { + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, + -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 +}; + +const int base26_lookup[] = { + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15, + 16,17,18,19,20,21,22,23,24,25,26,-1,-1,-1,-1,-1, + -1, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15, + 16,17,18,19,20,21,22,23,24,25,26,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 +}; + +const int base36_lookup[] = { + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, + -1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, + 25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1, + -1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, + 25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 +}; + +/* common buffer for quick conversions (unsafe) */ + +char util_number_buffer[NUMBER_BUFFER_SIZE] = { 0 }; + +/* integer from string; return a pointer to character next to the last digit */ + +#define string_scan_sign(s, c, sign) _scan_sign(c, sign, *++s) +#define string_scan_integer(s, c, number) _scan_integer(c, number, *++s) +#define string_scan_radix(s, c, number, radix) _scan_radix(c, number, radix, *++s) +#define string_read_integer(s, c, number) _read_integer(c, number, *++s) +#define string_read_radix(s, c, number, radix) _read_radix(c, number, radix, *++s) + +const char * string_to_int32 (const char *s, int32_t *number) +{ + int sign, c = *s; + string_scan_sign(s, c, sign); + string_scan_integer(s, c, *number); + if (sign) *number = -*number; + return s; +} + +const char * string_to_slong (const char *s, long *number) +{ + int sign, c = *s; + string_scan_sign(s, c, sign); + string_scan_integer(s, c, *number); + if (sign) *number = -*number; + return s; +} + +const char * string_to_int64 (const char *s, int64_t *number) +{ + int sign, c = *s; + string_scan_sign(s, c, sign); + string_scan_integer(s, c, *number); + if (sign) *number = -*number; + return s; +} + +const char * string_to_uint32 (const char *s, uint32_t *number) +{ + int c = *s; + string_scan_integer(s, c, *number); + return s; +} + +const char * string_to_ulong (const char *s, unsigned long *number) +{ + int c = *s; + string_scan_integer(s, c, *number); + return s; +} + +const char * string_to_usize (const char *s, size_t *number) +{ + int c = *s; + string_scan_integer(s, c, *number); + return s; +} + +const char * string_to_uint64 (const char *s, uint64_t *number) +{ + int c = *s; + string_scan_integer(s, c, *number); + return s; +} + +const char * radix_to_int32 (const char *s, int32_t *number, int radix) +{ + int sign, c = *s; + string_scan_sign(s, c, sign); + string_scan_radix(s, c, *number, radix); + if (sign) *number = -*number; + return s; +} + +const char * radix_to_slong (const char *s, long *number, int radix) +{ + int sign, c = *s; + string_scan_sign(s, c, sign); + string_scan_radix(s, c, *number, radix); + if (sign) *number = -*number; + return s; +} + +const char * radix_to_int64 (const char *s, int64_t *number, int radix) +{ + int sign, c = *s; + string_scan_sign(s, c, sign); + string_scan_radix(s, c, *number, radix); + if (sign) *number = -*number; + return s; +} + +const char * radix_to_uint32 (const char *s, uint32_t *number, int radix) +{ + int c = *s; + string_scan_radix(s, c, *number, radix); + return s; +} + +const char * radix_to_ulong (const char *s, unsigned long *number, int radix) +{ + int c = *s; + string_scan_radix(s, c, *number, radix); + return s; +} + +const char * radix_to_usize (const char *s, size_t *number, int radix) +{ + int c = *s; + string_scan_radix(s, c, *number, radix); + return s; +} + +const char * radix_to_uint64 (const char *s, uint64_t *number, int radix) +{ + int c = *s; + string_scan_radix(s, c, *number, radix); + return s; +} + +/* roman to uint16_t */ + +#define roman1000(c) (c == 'M' || c == 'm') +#define roman500(c) (c == 'D' || c == 'd') +#define roman100(c) (c == 'C' || c == 'c') +#define roman50(c) (c == 'L' || c == 'l') +#define roman10(c) (c == 'X' || c == 'x') +#define roman5(c) (c == 'V' || c == 'v') +#define roman1(c) (c == 'I' || c == 'i') + +#define roman100s(p) (roman100(*p) ? (100 + ((++p, roman100(*p)) ? (100 + ((++p, roman100(*p)) ? (++p, 100) : 0)) : 0)) : 0) +#define roman10s(p) (roman10(*p) ? (10 + ((++p, roman10(*p)) ? (10 + ((++p, roman10(*p)) ? (++p, 10) : 0)) : 0)) : 0) +#define roman1s(p) (roman1(*p) ? (1 + ((++p, roman1(*p)) ? (1 + ((++p, roman1(*p)) ? (++p, 1) : 0)) : 0)) : 0) + +const char * roman_to_uint16 (const char *s, uint16_t *number) +{ + const char *p; + /* M */ + for (*number = 0, p = s; roman1000(*p); *number += 1000, ++p); + /* D C */ + if (roman500(*p)) + { + ++p; + *number += 500 + roman100s(p); + } + else if (roman100(*p)) + { + ++p; + if (roman1000(*p)) + { + ++p; + *number += 900; + } + else if (roman500(*p)) + { + ++p; + *number += 400; + } + else + *number += 100 + roman100s(p); + } + /* L X */ + if (roman50(*p)) + { + ++p; + *number += 50 + roman10s(p); + } + else if (roman10(*p)) + { + ++p; + if (roman100(*p)) + { + ++p; + *number += 90; + } + else if (roman50(*p)) + { + ++p; + *number += 40; + } + else + *number += 10 + roman10s(p); + } + /* V I */ + if (roman5(*p)) + { + ++p; + *number += 5 + roman1s(p); + } + else if (roman1(*p)) + { + ++p; + if (roman10(*p)) + { + ++p; + *number += 9; + } + else if (roman5(*p)) + { + ++p; + *number += 4; + } + else + *number += 1 + roman1s(p); + } + return p; +} + +/* integer to string; return a pointer to null-terminated static const string */ + +#define end_of_integer_buffer(integer_buffer) (integer_buffer + MAX_INTEGER_DIGITS - 1) + +#define number_printrev_signed(p, number, quotient) \ + do { \ + quotient = number; number /= 10; \ + *--p = base10_palindrome[9 + (quotient - number*10)]; \ + } while (number); \ + if (quotient < 0) *--p = '-' + +#define number_printrev_unsigned(p, number, quotient) \ + do { \ + quotient = number; number /= 10; \ + *--p = (char)(quotient - integer_multiplied10(number)) + '0'; \ + } while (number) + +#define SINTTYPE_AS_STRING(inttype, number, ibuf, psize) \ + char *p, *e; \ + inttype quotient; \ + e = p = end_of_integer_buffer(ibuf); *p = '\0'; \ + number_printrev_signed(p, number, quotient); \ + *psize = (size_t)(e - p) + +#define UINTTYPE_AS_STRING(inttype, number, ibuf, psize) \ + char *p, *e; \ + inttype quotient; \ + e = p = end_of_integer_buffer(ibuf); *p = '\0'; \ + number_printrev_unsigned(p, number, quotient); \ + *psize = (size_t)(e - p) + +char * int32_as_string (int32_t number, char ibuf[MAX_INTEGER_DIGITS], size_t *psize) +{ + SINTTYPE_AS_STRING(int32_t, number, ibuf, psize); + return p; +} + +char * slong_as_string (long number, char ibuf[MAX_INTEGER_DIGITS], size_t *psize) +{ + SINTTYPE_AS_STRING(long, number, ibuf, psize); + return p; +} + +char * int64_as_string (int64_t number, char ibuf[MAX_INTEGER_DIGITS], size_t *psize) +{ + SINTTYPE_AS_STRING(int64_t, number, ibuf, psize); + return p; +} + +char * uint32_as_string (uint32_t number, char ibuf[MAX_INTEGER_DIGITS], size_t *psize) +{ + UINTTYPE_AS_STRING(uint32_t, number, ibuf, psize); + return p; +} + +char * ulong_as_string (unsigned long number, char ibuf[MAX_INTEGER_DIGITS], size_t *psize) +{ + UINTTYPE_AS_STRING(unsigned long, number, ibuf, psize); + return p; +} + +char * usize_as_string (size_t number, char ibuf[MAX_INTEGER_DIGITS], size_t *psize) +{ + UINTTYPE_AS_STRING(size_t, number, ibuf, psize); + return p; +} + +char * uint64_as_string (uint64_t number, char ibuf[MAX_INTEGER_DIGITS], size_t *psize) +{ + UINTTYPE_AS_STRING(uint64_t, number, ibuf, psize); + return p; +} + +/* radix variant */ + +#define number_printrev_signed_radix_uc(p, number, radix, quotient) \ + do { \ + quotient = number; number /= radix; \ + *--p = base36_uc_palindrome[MAX_RADIX - 1 + (quotient - number*radix)]; \ + } while (number) + +#define number_printrev_signed_radix_lc(p, number, radix, quotient) \ + do { \ + quotient = number; number /= radix; \ + *--p = base36_lc_palindrome[MAX_RADIX - 1 + (quotient - number*radix)]; \ + } while (number) + +#define number_printrev_signed_radix(p, number, radix, quotient, uc) \ + do { \ + if (uc) { number_printrev_signed_radix_uc(p, number, radix, quotient); } \ + else { number_printrev_signed_radix_lc(p, number, radix, quotient); } \ + if (quotient < 0) *--p = '-'; \ + } while (0) + +#define number_printrev_unsigned_radix_uc(p, number, radix, quotient) \ + do { \ + quotient = number; number /= radix; \ + *--p = base36_uc_alphabet[quotient % radix]; \ + } while (number) + +#define number_printrev_unsigned_radix_lc(p, number, radix, quotient) \ + do { \ + quotient = number; number /= radix; \ + *--p = base36_lc_alphabet[quotient % radix]; \ + } while (number) + +#define number_printrev_unsigned_radix(p, number, radix, quotient, uc) \ + do { \ + if (uc) { number_printrev_unsigned_radix_uc(p, number, radix, quotient); } \ + else { number_printrev_unsigned_radix_lc(p, number, radix, quotient); } \ + } while (0) + +#define SINTTYPE_AS_RADIX(inttype, number, radix, uc, ibuf, psize) \ + char *p, *e; \ + inttype quotient; \ + e = p = end_of_integer_buffer(ibuf); *p = '\0'; \ + number_printrev_signed_radix(p, number, radix, quotient, uc); \ + *psize = (size_t)(e - p) + +#define UINTTYPE_AS_RADIX(inttype, number, radix, uc, ibuf, psize) \ + char *p, *e; \ + inttype quotient; \ + e = p = end_of_integer_buffer(ibuf); *p = '\0'; \ + number_printrev_unsigned_radix(p, number, radix, quotient, uc); \ + *psize = (size_t)(e - p) + +char * int32_as_radix (int32_t number, int radix, int uc, char ibuf[MAX_INTEGER_DIGITS], size_t *psize) +{ + SINTTYPE_AS_RADIX(int32_t, number, radix, uc, ibuf, psize); + return p; +} + +char * slong_as_radix (long number, int radix, int uc, char ibuf[MAX_INTEGER_DIGITS], size_t *psize) +{ + SINTTYPE_AS_RADIX(long, number, radix, uc, ibuf, psize); + return p; +} + +/* +char * ssize_as_radix (ssize_t number, int radix, int uc, char ibuf[MAX_INTEGER_DIGITS], size_t *psize) +{ + SINTTYPE_AS_RADIX(ssize_t, number, radix, uc, ibuf, psize); + return p; +} +*/ + +char * int64_as_radix (int64_t number, int radix, int uc, char ibuf[MAX_INTEGER_DIGITS], size_t *psize) +{ + SINTTYPE_AS_RADIX(int64_t, number, radix, uc, ibuf, psize); + return p; +} + +char * uint32_as_radix (uint32_t number, int radix, int uc, char ibuf[MAX_INTEGER_DIGITS], size_t *psize) +{ + UINTTYPE_AS_RADIX(uint32_t, number, radix, uc, ibuf, psize); + return p; +} + +char * ulong_as_radix (unsigned long number, int radix, int uc, char ibuf[MAX_INTEGER_DIGITS], size_t *psize) +{ + UINTTYPE_AS_RADIX(unsigned long, number, radix, uc, ibuf, psize); + return p; +} + +char * usize_as_radix (size_t number, int radix, int uc, char ibuf[MAX_INTEGER_DIGITS], size_t *psize) +{ + UINTTYPE_AS_RADIX(size_t, number, radix, uc, ibuf, psize); + return p; +} + +char * uint64_as_radix (uint64_t number, int radix, int uc, char ibuf[MAX_INTEGER_DIGITS], size_t *psize) +{ + UINTTYPE_AS_RADIX(uint64_t, number, radix, uc, ibuf, psize); + return p; +} + +/* aaa, aab, aac, ...; unsigned only. 0 gives empty string */ + +#define string_scan_alpha(s, c, number, radix) \ + for (number = 0, c = *s; (c = base26_value(c)) > 0; number = number * radix + c, c = *++s) + +const char * alpha_to_uint32 (const char *s, uint32_t *number) +{ + int c; + string_scan_alpha(s, c, *number, 26); + return s; +} + +const char * alpha_to_ulong (const char *s, unsigned long *number) +{ + int c; + string_scan_alpha(s, c, *number, 26); + return s; +} + +const char * alpha_to_usize (const char *s, size_t *number) +{ + int c; + string_scan_alpha(s, c, *number, 26); + return s; +} + +const char * alpha_to_uint64 (const char *s, uint64_t *number) +{ + int c; + string_scan_alpha(s, c, *number, 26); + return s; +} + +#define number_printrev_unsigned_alpha_uc(p, number, radix, quotient) \ + while (number > 0) { \ + quotient = --number; number /= radix; \ + *--p = base26_uc_alphabet[quotient % radix]; \ + } + +#define number_printrev_unsigned_alpha_lc(p, number, radix, quotient) \ + while (number > 0) { \ + quotient = --number; number /= radix; \ + *--p = base26_lc_alphabet[quotient % radix]; \ + } + +#define UINTTYPE_AS_ALPHA(inttype, number, uc, ibuf, psize) \ + char *p, *e; \ + inttype quotient; \ + e = p = end_of_integer_buffer(ibuf); *p = '\0'; \ + if (uc) { number_printrev_unsigned_alpha_uc(p, number, 26, quotient); } \ + else { number_printrev_unsigned_alpha_lc(p, number, 26, quotient); } \ + *psize = (size_t)(e - p) + +char * uint32_as_alpha (uint32_t number, int uc, char ibuf[MAX_INTEGER_DIGITS], size_t *psize) +{ + UINTTYPE_AS_ALPHA(uint32_t, number, uc, ibuf, psize); + return p; +} + +char * ulong_as_alpha (unsigned long number, int uc, char ibuf[MAX_INTEGER_DIGITS], size_t *psize) +{ + UINTTYPE_AS_ALPHA(unsigned long, number, uc, ibuf, psize); + return p; +} + +char * usize_as_alpha (size_t number, int uc, char ibuf[MAX_INTEGER_DIGITS], size_t *psize) +{ + UINTTYPE_AS_ALPHA(size_t, number, uc, ibuf, psize); + return p; +} + +char * uint64_as_alpha (uint64_t number, int uc, char ibuf[MAX_INTEGER_DIGITS], size_t *psize) +{ + UINTTYPE_AS_ALPHA(uint64_t, number, uc, ibuf, psize); + return p; +} + +/* a variant of alphabetic, a, b, c, ..., z, aa, bb, cc, ..., zz (eg. pdf page labelling) + watch out: unsafe for large numbers; for buffer size N we can handle max. N * 26. */ + +#define string_scan_alphan(s, c, number, radix) \ + do { \ + number = 0; \ + if ((c = (uint16_t)base26_value(*s)) > 0) { \ + number = c; \ + while (c == (uint16_t)base26_value(*++s)) number += radix; \ + } \ + } while (0) + +const char * alphan_to_uint16 (const char *s, uint16_t *number) +{ + uint16_t c; + string_scan_alphan(s, c, *number, 26); + return s; +} + +#define number_print_alphan_uc(p, e, c, number, radix) \ + for (c = (--number) % radix, number -= c; ; number -= radix) { \ + *p++ = base26_uc_alphabet[c]; \ + if (number == 0 || p >= e) break; \ + } + +#define number_print_alphan_lc(p, e, c, number, radix) \ + for (c = (--number) % radix, number -= c; ; number -= radix) { \ + *p++ = base26_lc_alphabet[c]; \ + if (number == 0 || p >= e) break; \ + } + +#define UINTTYPE_AS_ALPHAN(inttype, number, uc, ibuf, size, psize) \ + char *p, *e; \ + uint8_t c; \ + p = ibuf; \ + e = p + size; \ + if (number > 0) { \ + if (uc) { number_print_alphan_uc(p, e, c, number, 26); } \ + else { number_print_alphan_lc(p, e, c, number, 26); } \ + } \ + *p = '\0'; \ + *psize = (size_t)(p - ibuf) + +char * uint16_as_alphan (uint16_t number, int uc, char ibuf[], size_t size, size_t *psize) +{ + UINTTYPE_AS_ALPHAN(uint16_t, number, uc, ibuf, size, psize); + return ibuf; +} + +/* roman numeral */ + +/* large roman numerals? http://mathforum.org/library/drmath/view/57569.html */ + +#define base_roman_uc_alphabet "MDCLXVI" +#define base_roman_lc_alphabet "mdclxvi" + +char * uint16_as_roman (uint16_t number, int uc, char ibuf[MAX_ROMAN_DIGITS], size_t *psize) +{ + static const uint32_t base_roman_values[] = { 1000, 500, 100, 50, 10, 5, 1 }; + const char *alphabet; + char *p; + uint32_t k, j, v, u, n; + + n = (uint32_t)number; // uint16_t used to limit leding 'M' + alphabet = uc ? base_roman_uc_alphabet : base_roman_lc_alphabet; + for (p = ibuf, j = 0, v = base_roman_values[0]; n > 0; ) + { + if (n >= v) + { + *p++ = alphabet[j]; + n -= v; + continue; + } + if (j & 1) + k = j + 1; + else + k = j + 2; + u = base_roman_values[k]; + if (n + u >= v) + { + *p++ = alphabet[k]; + n += u; + } + else + v = base_roman_values[++j]; + } + *p = '\0'; + *psize = (size_t)(p - ibuf); + return ibuf; +} + +/* IEEE-754 */ + +#define BINARY_MODF 1 + +#define NOT_A_NUMBER_STRING "NaN" +#define INFINITY_STRING "INF" +#define SIGNED_INFINITY 1 +#define SIGNED_ZERO 0 +#define SIGNED_NOT_A_NUMBER 0 +#define RADIX_CHAR '.' + +/* double/float to decimal */ + +typedef struct ieee_double { + union { + double number; + uint64_t bits; + }; + uint64_t fraction; + int exponent, sign; +} ieee_double; + +typedef struct ieee_float { + union { + float number; + uint32_t bits; + }; + uint32_t fraction; + int exponent, sign; +} ieee_float; + +#define IEEE_DOUBLE_BIAS 1023 +#define IEEE_DOUBLE_MIN_EXPONENT -1023 +#define IEEE_DOUBLE_MAX_EXPONENT (0x7ff - IEEE_DOUBLE_BIAS) + +#define IEEE_FLOAT_BIAS 127 +#define IEEE_FLOAT_MIN_EXPONENT -127 +#define IEEE_FLOAT_MAX_EXPONENT (0xff - IEEE_FLOAT_BIAS) + +#define ieee_double_fraction(i) (i & 0x000fffffffffffffull) +#define ieee_double_exponent(i) ((0x7ff & (i >> 52)) - IEEE_DOUBLE_BIAS) +#define ieee_double_init(ieee_number, number) \ + ieee_number.number = number, \ + ieee_number.fraction = ieee_double_fraction(ieee_number.bits), \ + ieee_number.exponent = ieee_double_exponent(ieee_number.bits) + +#define ieee_float_fraction(i) (i & 0x007fffff) +#define ieee_float_exponent(i) ((0xff & (i >> 23)) - IEEE_FLOAT_BIAS) +#define ieee_float_init(ieee_number, number) \ + ieee_number.number = number, \ + ieee_number.fraction = ieee_float_fraction(ieee_number.bits), \ + ieee_number.exponent = ieee_float_exponent(ieee_number.bits) + +/* special cases */ + +#define ieee_double_is_zero(ieee_number) (ieee_number.number == 0) // || ieee_double_too_small(ieee_number) ? +#define ieee_double_too_small(ieee_number) (ieee_number.exponent == 0 && ieee_number.fraction != 0) // denormalized, implicit fracion bit not set + +#define ieee_float_is_zero(ieee_number) (ieee_number.number == 0) // || ieee_float_too_small(ieee_number) ? +#define ieee_float_too_small(ieee_number) (ieee_number.exponent == 0 && ieee_number.fraction != 0) + +#define ieee_double_zero_string(ieee_number) (SIGNED_ZERO && ieee_number.sign ? "-0" : "0") +#define ieee_double_infinity_string(ieee_number) (SIGNED_INFINITY && ieee_number.sign ? "-" INFINITY_STRING : INFINITY_STRING) + +#define ieee_float_zero_string ieee_double_zero_string +#define ieee_float_infinity_string ieee_double_infinity_string + +#define ieee_double_special_case(ieee_number) (ieee_number.exponent == IEEE_DOUBLE_MAX_EXPONENT) +#define ieee_double_special_string(ieee_number) (ieee_number.fraction ? NOT_A_NUMBER_STRING : ieee_double_infinity_string(ieee_number)) + +#define ieee_float_special_case(ieee_number) (ieee_number.exponent == IEEE_FLOAT_MAX_EXPONENT) +#define ieee_float_special_string(ieee_number) (ieee_number.fraction ? NOT_A_NUMBER_STRING : ieee_float_infinity_string(ieee_number)) + +#if 0 + +const double double_binary_power10[] = +{ + 1.0e1, 1.0e2, 1.0e4, 1.0e8, 1.0e16, 1.0e32, 1.0e64, 1.0e128, 1.0e256 +}; + +const float float_binary_power10[] = +{ + 1.0e1, 1.0e2, 1.0e4, 1.0e8, 1.0e16, 1.0e32 +}; + +const double double_binary_negpower10[] = +{ + 1.0e-1, 1.0e-2, 1.0e-4, 1.0e-8, 1.0e-16, 1.0e-32 +}; + +const float float_binary_negpower10[] = +{ + 1.0e-1, 1.0e-2, 1.0e-4, 1.0e-8, 1.0e-16, 1.0e-32 +}; + +#else + +const double double_decimal_power10[] = { + 1.0e0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, 1.0e6, 1.0e7, 1.0e8, 1.0e9, + 1.0e10, 1.0e11, 1.0e12, 1.0e13, 1.0e14, 1.0e15, 1.0e16, 1.0e17, 1.0e18, 1.0e19, + 1.0e20, 1.0e21, 1.0e22, 1.0e23, 1.0e24, 1.0e25, 1.0e26, 1.0e27, 1.0e28, 1.0e29, + 1.0e30, 1.0e31, 1.0e32, 1.0e33, 1.0e34, 1.0e35, 1.0e36, 1.0e37, 1.0e38, 1.0e39, + 1.0e40, 1.0e41, 1.0e42, 1.0e43, 1.0e44, 1.0e45, 1.0e46, 1.0e47, 1.0e48, 1.0e49, + 1.0e50, 1.0e51, 1.0e52, 1.0e53, 1.0e54, 1.0e55, 1.0e56, 1.0e57, 1.0e58, 1.0e59, + 1.0e60, 1.0e61, 1.0e62, 1.0e63, 1.0e64, 1.0e65, 1.0e66, 1.0e67, 1.0e68, 1.0e69, + 1.0e70, 1.0e71, 1.0e72, 1.0e73, 1.0e74, 1.0e75, 1.0e76, 1.0e77, 1.0e78, 1.0e79, + 1.0e80, 1.0e81, 1.0e82, 1.0e83, 1.0e84, 1.0e85, 1.0e86, 1.0e87, 1.0e88, 1.0e89, + 1.0e90, 1.0e91, 1.0e92, 1.0e93, 1.0e94, 1.0e95, 1.0e96, 1.0e97, 1.0e98, 1.0e99, + 1.0e100, 1.0e101, 1.0e102, 1.0e103, 1.0e104, 1.0e105, 1.0e106, 1.0e107, 1.0e108, 1.0e109, + 1.0e110, 1.0e111, 1.0e112, 1.0e113, 1.0e114, 1.0e115, 1.0e116, 1.0e117, 1.0e118, 1.0e119, + 1.0e120, 1.0e121, 1.0e122, 1.0e123, 1.0e124, 1.0e125, 1.0e126, 1.0e127, 1.0e128, 1.0e129, + 1.0e130, 1.0e131, 1.0e132, 1.0e133, 1.0e134, 1.0e135, 1.0e136, 1.0e137, 1.0e138, 1.0e139, + 1.0e140, 1.0e141, 1.0e142, 1.0e143, 1.0e144, 1.0e145, 1.0e146, 1.0e147, 1.0e148, 1.0e149, + 1.0e150, 1.0e151, 1.0e152, 1.0e153, 1.0e154, 1.0e155, 1.0e156, 1.0e157, 1.0e158, 1.0e159, + 1.0e160, 1.0e161, 1.0e162, 1.0e163, 1.0e164, 1.0e165, 1.0e166, 1.0e167, 1.0e168, 1.0e169, + 1.0e170, 1.0e171, 1.0e172, 1.0e173, 1.0e174, 1.0e175, 1.0e176, 1.0e177, 1.0e178, 1.0e179, + 1.0e180, 1.0e181, 1.0e182, 1.0e183, 1.0e184, 1.0e185, 1.0e186, 1.0e187, 1.0e188, 1.0e189, + 1.0e190, 1.0e191, 1.0e192, 1.0e193, 1.0e194, 1.0e195, 1.0e196, 1.0e197, 1.0e198, 1.0e199, + 1.0e200, 1.0e201, 1.0e202, 1.0e203, 1.0e204, 1.0e205, 1.0e206, 1.0e207, 1.0e208, 1.0e209, + 1.0e210, 1.0e211, 1.0e212, 1.0e213, 1.0e214, 1.0e215, 1.0e216, 1.0e217, 1.0e218, 1.0e219, + 1.0e220, 1.0e221, 1.0e222, 1.0e223, 1.0e224, 1.0e225, 1.0e226, 1.0e227, 1.0e228, 1.0e229, + 1.0e230, 1.0e231, 1.0e232, 1.0e233, 1.0e234, 1.0e235, 1.0e236, 1.0e237, 1.0e238, 1.0e239, + 1.0e240, 1.0e241, 1.0e242, 1.0e243, 1.0e244, 1.0e245, 1.0e246, 1.0e247, 1.0e248, 1.0e249, + 1.0e250, 1.0e251, 1.0e252, 1.0e253, 1.0e254, 1.0e255, 1.0e256, 1.0e257, 1.0e258, 1.0e259, + 1.0e260, 1.0e261, 1.0e262, 1.0e263, 1.0e264, 1.0e265, 1.0e266, 1.0e267, 1.0e268, 1.0e269, + 1.0e270, 1.0e271, 1.0e272, 1.0e273, 1.0e274, 1.0e275, 1.0e276, 1.0e277, 1.0e278, 1.0e279, + 1.0e280, 1.0e281, 1.0e282, 1.0e283, 1.0e284, 1.0e285, 1.0e286, 1.0e287, 1.0e288, 1.0e289, + 1.0e290, 1.0e291, 1.0e292, 1.0e293, 1.0e294, 1.0e295, 1.0e296, 1.0e297, 1.0e298, 1.0e299, + 1.0e300, 1.0e301, 1.0e302, 1.0e303, 1.0e304, 1.0e305, 1.0e306, 1.0e307, 1.0e308 +}; + +const float float_decimal_power10[] = { + 1.0e0f, 1.0e1f, 1.0e2f, 1.0e3f, 1.0e4f, 1.0e5f, 1.0e6f, 1.0e7f, 1.0e8f, 1.0e9f, + 1.0e10f, 1.0e11f, 1.0e12f, 1.0e13f, 1.0e14f, 1.0e15f, 1.0e16f, 1.0e17f, 1.0e18f, 1.0e19f, + 1.0e20f, 1.0e21f, 1.0e22f, 1.0e23f, 1.0e24f, 1.0e25f, 1.0e26f, 1.0e27f, 1.0e28f, 1.0e29f, + 1.0e30f, 1.0e31f, 1.0e32f, 1.0e33f, 1.0e34f, 1.0e35f, 1.0e36f, 1.0e37f, 1.0e38f +}; + +const double double_decimal_negpower10[] = { + 1.0e0, 1.0e-1, 1.0e-2, 1.0e-3, 1.0e-4, 1.0e-5, 1.0e-6, 1.0e-7, 1.0e-8, 1.0e-9, + 1.0e-10, 1.0e-11, 1.0e-12, 1.0e-13, 1.0e-14, 1.0e-15, 1.0e-16, 1.0e-17, 1.0e-18, 1.0e-19, + 1.0e-20, 1.0e-21, 1.0e-22, 1.0e-23, 1.0e-24, 1.0e-25, 1.0e-26, 1.0e-27, 1.0e-28, 1.0e-29, + 1.0e-30, 1.0e-31, 1.0e-32, 1.0e-33, 1.0e-34, 1.0e-35, 1.0e-36, 1.0e-37, 1.0e-38, 1.0e-39, + 1.0e-40, 1.0e-41, 1.0e-42, 1.0e-43, 1.0e-44, 1.0e-45, 1.0e-46, 1.0e-47, 1.0e-48, 1.0e-49, + 1.0e-50, 1.0e-51, 1.0e-52, 1.0e-53, 1.0e-54, 1.0e-55, 1.0e-56, 1.0e-57, 1.0e-58, 1.0e-59, + 1.0e-60, 1.0e-61, 1.0e-62, 1.0e-63, 1.0e-64, 1.0e-65, 1.0e-66, 1.0e-67, 1.0e-68, 1.0e-69, + 1.0e-70, 1.0e-71, 1.0e-72, 1.0e-73, 1.0e-74, 1.0e-75, 1.0e-76, 1.0e-77, 1.0e-78, 1.0e-79, + 1.0e-80, 1.0e-81, 1.0e-82, 1.0e-83, 1.0e-84, 1.0e-85, 1.0e-86, 1.0e-87, 1.0e-88, 1.0e-89, + 1.0e-90, 1.0e-91, 1.0e-92, 1.0e-93, 1.0e-94, 1.0e-95, 1.0e-96, 1.0e-97, 1.0e-98, 1.0e-99, + 1.0e-100, 1.0e-101, 1.0e-102, 1.0e-103, 1.0e-104, 1.0e-105, 1.0e-106, 1.0e-107, 1.0e-108, 1.0e-109, + 1.0e-110, 1.0e-111, 1.0e-112, 1.0e-113, 1.0e-114, 1.0e-115, 1.0e-116, 1.0e-117, 1.0e-118, 1.0e-119, + 1.0e-120, 1.0e-121, 1.0e-122, 1.0e-123, 1.0e-124, 1.0e-125, 1.0e-126, 1.0e-127, 1.0e-128, 1.0e-129, + 1.0e-130, 1.0e-131, 1.0e-132, 1.0e-133, 1.0e-134, 1.0e-135, 1.0e-136, 1.0e-137, 1.0e-138, 1.0e-139, + 1.0e-140, 1.0e-141, 1.0e-142, 1.0e-143, 1.0e-144, 1.0e-145, 1.0e-146, 1.0e-147, 1.0e-148, 1.0e-149, + 1.0e-150, 1.0e-151, 1.0e-152, 1.0e-153, 1.0e-154, 1.0e-155, 1.0e-156, 1.0e-157, 1.0e-158, 1.0e-159, + 1.0e-160, 1.0e-161, 1.0e-162, 1.0e-163, 1.0e-164, 1.0e-165, 1.0e-166, 1.0e-167, 1.0e-168, 1.0e-169, + 1.0e-170, 1.0e-171, 1.0e-172, 1.0e-173, 1.0e-174, 1.0e-175, 1.0e-176, 1.0e-177, 1.0e-178, 1.0e-179, + 1.0e-180, 1.0e-181, 1.0e-182, 1.0e-183, 1.0e-184, 1.0e-185, 1.0e-186, 1.0e-187, 1.0e-188, 1.0e-189, + 1.0e-190, 1.0e-191, 1.0e-192, 1.0e-193, 1.0e-194, 1.0e-195, 1.0e-196, 1.0e-197, 1.0e-198, 1.0e-199, + 1.0e-200, 1.0e-201, 1.0e-202, 1.0e-203, 1.0e-204, 1.0e-205, 1.0e-206, 1.0e-207, 1.0e-208, 1.0e-209, + 1.0e-210, 1.0e-211, 1.0e-212, 1.0e-213, 1.0e-214, 1.0e-215, 1.0e-216, 1.0e-217, 1.0e-218, 1.0e-219, + 1.0e-220, 1.0e-221, 1.0e-222, 1.0e-223, 1.0e-224, 1.0e-225, 1.0e-226, 1.0e-227, 1.0e-228, 1.0e-229, + 1.0e-230, 1.0e-231, 1.0e-232, 1.0e-233, 1.0e-234, 1.0e-235, 1.0e-236, 1.0e-237, 1.0e-238, 1.0e-239, + 1.0e-240, 1.0e-241, 1.0e-242, 1.0e-243, 1.0e-244, 1.0e-245, 1.0e-246, 1.0e-247, 1.0e-248, 1.0e-249, + 1.0e-250, 1.0e-251, 1.0e-252, 1.0e-253, 1.0e-254, 1.0e-255, 1.0e-256, 1.0e-257, 1.0e-258, 1.0e-259, + 1.0e-260, 1.0e-261, 1.0e-262, 1.0e-263, 1.0e-264, 1.0e-265, 1.0e-266, 1.0e-267, 1.0e-268, 1.0e-269, + 1.0e-270, 1.0e-271, 1.0e-272, 1.0e-273, 1.0e-274, 1.0e-275, 1.0e-276, 1.0e-277, 1.0e-278, 1.0e-279, + 1.0e-280, 1.0e-281, 1.0e-282, 1.0e-283, 1.0e-284, 1.0e-285, 1.0e-286, 1.0e-287, 1.0e-288, 1.0e-289, + 1.0e-290, 1.0e-291, 1.0e-292, 1.0e-293, 1.0e-294, 1.0e-295, 1.0e-296, 1.0e-297, 1.0e-298, 1.0e-299, + 1.0e-300, 1.0e-301, 1.0e-302, 1.0e-303, 1.0e-304, 1.0e-305, 1.0e-306, 1.0e-307, 1.0e-308 +}; + +const float float_decimal_negpower10[] = { + 1.0e0f, 1.0e-1f, 1.0e-2f, 1.0e-3f, 1.0e-4f, 1.0e-5f, 1.0e-6f, 1.0e-7f, 1.0e-8f, 1.0e-9f, + 1.0e-10f, 1.0e-11f, 1.0e-12f, 1.0e-13f, 1.0e-14f, 1.0e-15f, 1.0e-16f, 1.0e-17f, 1.0e-18f, 1.0e-19f, + 1.0e-20f, 1.0e-21f, 1.0e-22f, 1.0e-23f, 1.0e-24f, 1.0e-25f, 1.0e-26f, 1.0e-27f, 1.0e-28f, 1.0e-29f, + 1.0e-30f, 1.0e-31f, 1.0e-32f, 1.0e-33f, 1.0e-34f, 1.0e-35f, 1.0e-36f, 1.0e-37f, 1.0e-38f +}; + +#endif + +/* scale number by floor(log10(number)) + 1 so that the result is in range [0.1, 1) */ + +#define ieee_double_exponent10(ieee_number) ((int)floor(log10(ieee_number.number)) + 1) +#define ieee_float_exponent10(ieee_number) ((int)floorf(log10f(ieee_number.number)) + 1) // floorf, log10f ? + +#define ieee_double_exp10(ieee_number, exponent10) \ + exponent10 = ieee_double_exponent10(ieee_number); \ + if (exponent10 > 0) { \ + double_negative_exp10(ieee_number.number, -exponent10); \ + ieee_number.fraction = ieee_double_fraction(ieee_number.bits); \ + ieee_number.exponent = ieee_double_exponent(ieee_number.bits); \ + } else if (exponent10 < 0) { \ + double_positive_exp10(ieee_number.number, -exponent10); \ + ieee_number.fraction = ieee_double_fraction(ieee_number.bits); \ + ieee_number.exponent = ieee_double_exponent(ieee_number.bits); \ + } + +#define ieee_float_exp10(ieee_number, exponent10) \ + exponent10 = ieee_float_exponent10(ieee_number); \ + if (exponent10 > 0) { \ + float_negative_exp10(ieee_number.number, -exponent10); \ + ieee_number.fraction = ieee_float_fraction(ieee_number.bits); \ + ieee_number.exponent = ieee_float_exponent(ieee_number.bits); \ + } else if (exponent10 < 0) { \ + float_positive_exp10(ieee_number.number, -exponent10); \ + ieee_number.fraction = ieee_float_fraction(ieee_number.bits); \ + ieee_number.exponent = ieee_float_exponent(ieee_number.bits); \ + } + +#if BINARY_MODF + +/* unhide implicit bit 53, produce 56-bit denormalised fraction (binary exponent already in range [-4, -1]) */ + +#define ieee_double_denormalize(ieee_number) \ + (ieee_number.exponent == IEEE_DOUBLE_MIN_EXPONENT ? (++ieee_number.exponent, 0) : (ieee_number.fraction |= (1ull<<52))), \ + ieee_number.fraction <<= (ieee_number.exponent + 4) + +/* unhide implicit bit 24, produce 27-bit denormalized fraction (binary exponent already in range [-4, -1]) */ + +#define ieee_float_denormalize(ieee_number) \ + (ieee_number.exponent == IEEE_FLOAT_MIN_EXPONENT ? (++ieee_number.exponent, 0) : (ieee_number.fraction |= (1<<23))), \ + ieee_number.fraction <<= (ieee_number.exponent + 4) + +/* turn off significant bits over 56 (integer part), multiply by 10, return new integer part (subsequent decimal digit) */ + +#define ieee_double_binary_fraction(ieee_number) \ + (ieee_number.fraction &= ((1ull<<56) - 1), \ + ieee_number.fraction = (ieee_number.fraction << 1) + (ieee_number.fraction << 3), \ + ieee_number.fraction >> 56) + +/* turn off significant bits over 27 (integer part), multiply by 10, return the integer part (subsequent decimal digit) */ + +#define ieee_float_binary_fraction(ieee_number) \ + (ieee_number.fraction &= ((1<<27) - 1), \ + ieee_number.fraction = (ieee_number.fraction << 1) + (ieee_number.fraction << 3), \ + ieee_number.fraction >> 27) + +#define ieee_double_decimal(ieee_number, exponent10, digits, p) \ + ieee_number_decimal(ieee_double_binary_fraction, ieee_number, exponent10, digits, p) +#define ieee_float_decimal(ieee_number, exponent10, digits, p) \ + ieee_number_decimal(ieee_float_binary_fraction, ieee_number, exponent10, digits, p) + +#else + +/* generic method */ + +#define ieee_double_decimal_fraction(ieee_number, i) (ieee_number.number = modf(10*ieee_number.number, &i), i) +#define ieee_float_decimal_fraction(ieee_number, i) (ieee_number.number = (float)modf(10*ieee_number.number, &i), i) // ??? + +#define ieee_double_decimal(ieee_number, exponent10, digits, p) \ + ieee_number_decimal(ieee_double_decimal_fraction, ieee_number, exponent10, digits, p) +#define ieee_float_decimal(ieee_number, exponent10, digits, p) \ + ieee_number_decimal(ieee_float_decimal_fraction, ieee_number, exponent10, digits, p) + +#endif + +#define ieee_number_decimal(method, ieee_number, exponent10, digits, p) \ + ieee_double_denormalize(ieee_number); \ + if (ieee_number.sign) *p++ = '-'; \ + if (exponent10 <= 0) \ + for (*p++ = '0', *p++ = RADIX_CHAR; exponent10 && digits; *p++ = '0', ++exponent10, --digits); \ + else \ + { \ + do { *p++ = '0' + (char)method(ieee_number); } while (--exponent10); \ + *p++ = RADIX_CHAR; \ + } \ + for ( ; digits && ieee_number.fraction; --digits) \ + *p++ = '0' + (char)method(ieee_number) + +/* rounding to nearest integer */ + +#if BINARY_MODF +/* check if the mantissa has the most significant bit set, means >= 0.5 */ +# define ieee_double_half(ieee_number) (ieee_number.fraction & (1ull<<55)) +# define ieee_float_half(ieee_number) (ieee_number.fraction & (1<<26)) +#else +# define ieee_double_half(ieee_number) (ieee_number.number >= 0.5) +# define ieee_float_half(ieee_number) (ieee_number.number >= 0.5) +#endif + +/* rounding to nearest integer */ + +#define buffer_ceil(s, p, sign) \ + { \ + while (*--p == '9'); \ + if (*p != RADIX_CHAR) ++*p++; \ + else { \ + char *q; \ + for (q = p - 1; ; --q) { \ + if (*q < '9') { ++*q; break; } \ + *q = '0'; \ + if (q == s) \ + *--s = '1'; \ + else if (sign && q - 1 == s) \ + *s = '1', *--s = '-'; \ + } \ + } \ + } + +#define buffer_remove_trailing_zeros(s, p, sign) \ + { \ + while (*--p == '0'); \ + if (*p != RADIX_CHAR) \ + ++p; \ + else if (!SIGNED_ZERO && sign && p - 2 == s && *(p - 1) == '0') \ + p -= 2, *p++ = '0'; \ + } + +// if digits parameter was initially less then exponent10, then exponent10 > 0 and ieee_double_half(ieee_number) is irrelevant +#define ieee_double_round(ieee_number, exponent10, s, p) \ + if (exponent10 == 0 && ieee_double_half(ieee_number)) \ + { buffer_ceil(s, p, ieee_number.sign); } \ + else \ + { buffer_remove_trailing_zeros(s, p, ieee_number.sign); } + +#define ieee_float_round(ieee_number, exponent10, s, p) \ + if (exponent10 == 0 && ieee_float_half(ieee_number)) \ + { buffer_ceil(s, p, ieee_number.sign); } \ + else \ + { buffer_remove_trailing_zeros(s, p, ieee_number.sign); } + +/* double to decimal */ + +#define ieee_copy_special_string(nbuf, special, p, _p) \ + for (p = nbuf, _p = special; ; ++p, ++_p) { \ + if ((*p = *_p) == '\0') break; \ + } + +#define ieee_copy_special_string_re(nbuf, special, p, _p, r, e) \ + for (p = nbuf, _p = special; ; ++p, ++_p) { \ + if ((*p = *_p) == '\0') { \ + if (r != NULL) *r = NULL; \ + if (e != NULL) *e = p; \ + break; \ + } \ + } + +char * double_as_string (double number, int digits, char nbuf[MAX_NUMBER_DIGITS], size_t *psize) +{ + ieee_double ieee_number; + int exponent10; + char *s, *p; const char *_p; + s = p = nbuf + 1; // for sign/rounding + ieee_double_init(ieee_number, number); + if ((ieee_number.sign = ieee_number.bits >> 63) != 0) + ieee_number.number = -ieee_number.number; + if (ieee_double_is_zero(ieee_number)) // to avoid crash on log10(number) + { + ieee_copy_special_string(nbuf, ieee_double_zero_string(ieee_number), p, _p); + *psize = (size_t)(p - nbuf); + return nbuf; + } + if (ieee_double_special_case(ieee_number)) + { + ieee_copy_special_string(nbuf, ieee_double_special_string(ieee_number), p, _p); + *psize = (size_t)(p - nbuf); + return nbuf; + } + ieee_double_exp10(ieee_number, exponent10); + ieee_double_decimal(ieee_number, exponent10, digits, p); + ieee_double_round(ieee_number, exponent10, s, p); + *p = '\0'; + *psize = (size_t)(p - s); + return s; +} + +/* float to decimal */ + +char * float_as_string (float number, int digits, char nbuf[MAX_NUMBER_DIGITS], size_t *psize) +{ + ieee_float ieee_number; + int exponent10; + char *s, *p; const char *_p; + s = p = nbuf + 1; // for sign/rounding + ieee_float_init(ieee_number, number); + if ((ieee_number.sign = ieee_number.bits >> 31) != 0) + ieee_number.number = -ieee_number.number; + if (ieee_float_is_zero(ieee_number)) + { + ieee_copy_special_string(nbuf, ieee_float_zero_string(ieee_number), p, _p); + *psize = (size_t)(p - nbuf); + return nbuf; + } + if (ieee_float_special_case(ieee_number)) + { + ieee_copy_special_string(nbuf, ieee_float_special_string(ieee_number), p, _p); + *psize = (size_t)(p - nbuf); + return nbuf; + } + ieee_float_exp10(ieee_number, exponent10); + ieee_float_decimal(ieee_number, exponent10, digits, p); + ieee_float_round(ieee_number, exponent10, s, p); + *p = '\0'; + *psize = (size_t)(p - s); + return s; +} + +/* decimal string to double/float */ + +#define string_scan_decimal(s, c, number) _scan_decimal(c, number, *++s) +#define string_scan_fraction(s, c, number, exponent10) _scan_fraction(c, number, exponent10, *++s) +#define string_scan_exponent10(s, c, exponent10) _scan_exponent10(c, exponent10, *++s) + +const char * string_to_double (const char *s, double *number) +{ + int sign, exponent10, c = *s; + string_scan_sign(s, c, sign); + string_scan_decimal(s, c, *number); + if (c == '.') + { + c = *++s; + string_scan_fraction(s, c, *number, exponent10); + } + else + exponent10 = 0; + if (c == 'e' || c == 'E') + { + c = *++s; + string_scan_exponent10(s, c, exponent10); + } + double_exp10(*number, exponent10); + if (sign) *number = -*number; + return s; +} + +const char * string_to_float (const char *s, float *number) +{ + int sign, exponent10, c = *s; + string_scan_sign(s, c, sign); + string_scan_decimal(s, c, *number); + if (c == '.') + { + c = *++s; + string_scan_fraction(s, c, *number, exponent10); + } + else + exponent10 = 0; + if (c == 'e' || c == 'E') + { + c = *++s; + string_scan_exponent10(s, c, exponent10); + } + float_exp10(*number, exponent10); + if (sign) *number = -*number; + return s; +} + +/* conventional form */ + +const char * convert_to_double (const char *s, double *number) +{ + int sign, c = *s; + string_scan_sign(s, c, sign); + string_scan_decimal(s, c, *number); + if (c == '.' || c == ',') + { + int exponent10; + c = *++s; + string_scan_fraction(s, c, *number, exponent10); + if (exponent10 < 0) + double_negative_exp10(*number, exponent10); + } + if (sign) *number = -*number; + return s; +} + +const char * convert_to_float (const char *s, float *number) +{ + int sign, c = *s; + string_scan_sign(s, c, sign); + string_scan_decimal(s, c, *number); + if (c == '.' || c == ',') + { + int exponent10; + c = *++s; + string_scan_fraction(s, c, *number, exponent10); + if (exponent10 < 0) + float_negative_exp10(*number, exponent10); + } + if (sign) *number = -*number; + return s; +} + +/* pretty common stuff */ + +size_t bytes_to_hex_lc (const void *input, size_t size, unsigned char *output) +{ + size_t i; + const unsigned char *p; + for (i = 0, p = (const unsigned char *)input; i < size; ++i, ++p) + { + *output++ = base16_lc_digit1(*p); + *output++ = base16_lc_digit2(*p); + } + *output = '\0'; + return 2*size + 1; +} + +size_t bytes_to_hex_uc (const void *input, size_t size, unsigned char *output) +{ + size_t i; + const unsigned char *p; + for (i = 0, p = (const unsigned char *)input; i < size; ++i, ++p) + { + *output++ = base16_uc_digit1(*p); + *output++ = base16_uc_digit2(*p); + } + *output = '\0'; + return 2*size + 1; +} + +size_t hex_to_bytes (const void *input, size_t size, unsigned char *output) +{ + size_t i; + int c1, c2; + const unsigned char *p; + for (i = 1, p = (const unsigned char *)input; i < size; i += 2) + { + c1 = base16_value(*p); + ++p; + c2 = base16_value(*p); + ++p; + if (c1 >= 0 && c2 >= 0) + *output++ = (unsigned char)((c1<<4)|c2); + else + break; + } + return i >> 1; +} + +void print_as_hex (const void *input, size_t bytes) +{ + const unsigned char *p; + for (p = (const unsigned char *)input; bytes > 0; --bytes, ++p) + printf("%02x", *p); +} |