Skip to content

Commit

Permalink
Remove hacks to avoid divisions
Browse files Browse the repository at this point in the history
  • Loading branch information
bigspider committed Jun 26, 2024
1 parent e77cf09 commit ad65230
Showing 1 changed file with 5 additions and 48 deletions.
53 changes: 5 additions & 48 deletions src/ui/display_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,46 +4,12 @@

#include "./display_utils.h"

// Division and modulus operators over uint64_t causes the inclusion of the __udivmoddi4 and other
// library functions that occupy more than 400 bytes. Since performance is not critical and division
// by 10 is sufficient, we avoid it with a binary search instead.
static uint64_t div10(uint64_t n) {
if (n < 10) return 0; // special case needed to make sure that n - 10 is safe

// Since low, mid and high are always <= UINT64_MAX / 10, there is no risk of overflow
uint64_t low = 0;
uint64_t high = UINT64_MAX / 10;

while (true) {
uint64_t mid = (low + high) / 2;

// the result equals mid if and only if mid * 10 <= n < mid * 10 + 10
// care is taken to make sure overflows and underflows are impossible
if (mid * 10 > n - 10 && n >= mid * 10) {
return mid;
} else if (n < mid * 10) {
high = mid - 1;
} else /* n >= 10 * mid + 10 */ {
low = mid + 1;
}
}
}

static uint64_t div100000000(uint64_t n) {
uint64_t res = n;
for (int i = 0; i < 8; i++) res = div10(res);
return res;
}

static size_t n_digits(uint64_t number) {
size_t count = 0;
do {
count++;

// HACK: avoid __udivmoddi4
// number /= 10;

number = div10(number);
number /= 10;
} while (number != 0);
return count;
}
Expand All @@ -57,23 +23,14 @@ void format_sats_amount(const char *coin_name,

char *amount_str = out + coin_name_len + 1;

// HACK: avoid __udivmoddi4
// uint64_t integral_part = amount / 100000000;
// uint32_t fractional_part = (uint32_t) (amount % 100000000);
uint64_t integral_part = div100000000(amount);
uint32_t fractional_part = (uint32_t) (amount - integral_part * 100000000);
uint64_t integral_part = amount / 100000000;
uint32_t fractional_part = (uint32_t) (amount % 100000000);

// format the integral part, starting from the least significant digit
size_t integral_part_digit_count = n_digits(integral_part);
for (unsigned int i = 0; i < integral_part_digit_count; i++) {
// HACK: avoid __udivmoddi4
// amount_str[integral_part_digit_count - 1 - i] = '0' + (integral_part % 10);
// integral_part /= 10;

uint64_t tmp_quotient = div10(integral_part);
char tmp_remainder = (char) (integral_part - 10 * tmp_quotient);
amount_str[integral_part_digit_count - 1 - i] = '0' + tmp_remainder;
integral_part = tmp_quotient;
amount_str[integral_part_digit_count - 1 - i] = '0' + (integral_part % 10);
integral_part /= 10;
}

if (fractional_part == 0) {
Expand Down

0 comments on commit ad65230

Please sign in to comment.