# Микроконтроллеры

/869150 fk0 (06.09.2018 11:07, просмотров: 4370)
I need to print signed 64-bit numbers in decimal form. Program runs in freestanding environment (no C library available, libgcc may be unavailable too, or may not work correctly). So I can't use printf(3) function. I'am trying to write function, which will be able to convert number from binary form (int64_t) to ascii. Simple solution is to divide number by 10, and use remainder as next digit (from left to right, iteratively). Unfortunately, processor doesn't have 64 bit division, and I can't rely on libgcc in that (__udivdi3 function). So I invented other way to perform binary->decimal conversion, by using binary coded decimal (BCD) numbers. First I convert binary number to BCD form (bit by bit, need 64 iterations, and need to sum BCD numbers), then convert BCD to ASCII. See source code below, I hope, somebody suggests me some improvements... /*static*/ void _print_dec(intmax_t num) { char *p; char buf[24 /* > log10(2^64) */]; uint_fast8_t r; uint64_t n = num < 0 ? -num : +num; uint_fast16_t result_h = 0, digit_h = 0; uint64_t result = 0, digit = 1; while (n != 0) { /* sum bcd numbers: r = a + b, where r should be L-value */ #define BCD_ADD(type, r, a, b) do { \ type t1 = a + (type)(0x6666666666666666 & ((type)-1 >> 4)), t2 = t1 ^ b; \ t1 += b, t2 = ~(t1 ^ t2) & (type)0x1111111111111110; r = t1 - (t2>>2 | t2>>3); \ } while (0); /* this macro computes rh:rl = ah:al + bh:bl (sum of compound BCD number), rh:rl should be L-value */ #define BCD_ADD_COMPOUND(type_h, type, rh, rl, ah, al, bh, bl) do { \ uint_fast8_t c = 0; \ type t1 = al, t2 = bl; \ BCD_ADD(type, rl, al, bl); \ c = rl >> (sizeof(type)*CHAR_BIT-4); \ BCD_ADD(type_h, rh, ah, bh); \ if (c >= 10 || (rl < t1 && rl < t2)) { \ rl = (rl & ((type)-1 >> 4)) | ((c - 10ULL) << (sizeof(type)*CHAR_BIT-4)); \ BCD_ADD(type_h, rh, rh, 1); \ } \ } while (0) if (n & 1) BCD_ADD_COMPOUND(uint_fast16_t, uint64_t, result_h, result, result_h, result, digit_h, digit); BCD_ADD_COMPOUND(uint_fast16_t, uint64_t, digit_h, digit, digit_h, digit, digit_h, digit); n >>= 1; } p = &buf[sizeof(buf) - 1]; *p = 0; do { r = result & 0x0f; *--p = r + '0'; result = (result >> 4) | ((uint64_t)(result_h & 0x0f) << (sizeof(uint64_t)*CHAR_BIT-4)); result_h = result_h >> 4; } while (result_h != 0 || result != 0); if (num < 0) *--p = '-'; print_cstr(p); }
[ZX]
Ответы