#include /* for log10() and floor() */ #include /* 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); }