Optimized string-to-number functions (#21484)
This commit is contained in:
@@ -28,6 +28,146 @@
|
||||
|
||||
#include "../MarlinCore.h"
|
||||
|
||||
#ifdef __AVR__
|
||||
|
||||
static FORCE_INLINE uint32_t mult10(uint32_t val) {
|
||||
uint32_t tmp = val;
|
||||
__asm__ __volatile__ (
|
||||
"add %A[tmp], %A[tmp]\n"
|
||||
"adc %B[tmp], %B[tmp]\n"
|
||||
"adc %C[tmp], %C[tmp]\n"
|
||||
"adc %D[tmp], %D[tmp]\n"
|
||||
"add %A[tmp], %A[tmp]\n"
|
||||
"adc %B[tmp], %B[tmp]\n"
|
||||
"adc %C[tmp], %C[tmp]\n"
|
||||
"adc %D[tmp], %D[tmp]\n"
|
||||
"add %A[val], %A[tmp]\n"
|
||||
"adc %B[val], %B[tmp]\n"
|
||||
"adc %C[val], %C[tmp]\n"
|
||||
"adc %D[val], %D[tmp]\n"
|
||||
"add %A[val], %A[val]\n"
|
||||
"adc %B[val], %B[val]\n"
|
||||
"adc %C[val], %C[val]\n"
|
||||
"adc %D[val], %D[val]\n"
|
||||
: [val] "+&r" (val),
|
||||
[tmp] "+&r" (tmp)
|
||||
);
|
||||
return val;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static FORCE_INLINE uint32_t mult10(uint32_t val) { return val * 10; }
|
||||
|
||||
#endif
|
||||
|
||||
// cheap base-10 strto(u)l.
|
||||
// does not check for errors.
|
||||
int32_t parse_int32(const char *buf) {
|
||||
char c;
|
||||
|
||||
// Get a char, skipping leading spaces
|
||||
do { c = *buf++; } while (c == ' ');
|
||||
|
||||
// check for sign
|
||||
bool is_negative = (c == '-');
|
||||
if (is_negative || c == '+')
|
||||
c = *buf++;
|
||||
|
||||
// optimization for first digit (no multiplication)
|
||||
uint8_t uc = c - '0';
|
||||
if (uc > 9) return 0;
|
||||
|
||||
// read unsigned value
|
||||
uint32_t uval = uc;
|
||||
while (true) {
|
||||
c = *buf++;
|
||||
uc = c - '0';
|
||||
if (uc > 9) break;
|
||||
uval = mult10(uval) + uc;
|
||||
}
|
||||
|
||||
return is_negative ? -uval : uval;
|
||||
}
|
||||
|
||||
// cheap strtof.
|
||||
// does not support nan/infinity or exponent notation.
|
||||
// does not check for errors.
|
||||
float parse_float(const char *buf) {
|
||||
char c;
|
||||
|
||||
// Get a char, skipping leading spaces
|
||||
do { c = *buf++; } while (c == ' ');
|
||||
|
||||
// check for sign
|
||||
bool is_negative = (c == '-');
|
||||
if (is_negative || c == '+')
|
||||
c = *buf++;
|
||||
|
||||
// read unsigned value and decimal point
|
||||
uint32_t uval;
|
||||
uint8_t exp_dec;
|
||||
uint8_t uc = c - '0';
|
||||
if (uc <= 9) {
|
||||
uval = uc;
|
||||
exp_dec = 0;
|
||||
}
|
||||
else {
|
||||
if (c != '.') return 0;
|
||||
uval = 0;
|
||||
exp_dec = 1;
|
||||
}
|
||||
|
||||
int8_t exp = 0;
|
||||
while (true) {
|
||||
c = *buf++;
|
||||
uc = c - '0';
|
||||
if (uc <= 9) {
|
||||
exp -= exp_dec;
|
||||
uval = mult10(uval) + uc;
|
||||
if (uval >= (UINT32_MAX - 9) / 10) {
|
||||
// overflow. keep reading digits until decimal point.
|
||||
while (exp_dec == 0) {
|
||||
c = *buf++;
|
||||
uc = c - '0';
|
||||
if (uc > 9) break;
|
||||
exp++;
|
||||
}
|
||||
goto overflow;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (c != '.' || exp_dec != 0) break;
|
||||
exp_dec = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// early return for 0
|
||||
if (uval == 0) return 0;
|
||||
|
||||
overflow:
|
||||
|
||||
// convert to float and apply sign
|
||||
float fval = uval;
|
||||
if (is_negative) fval *= -1;
|
||||
|
||||
// apply exponent (up to 1e-15 / 1e+15)
|
||||
if (exp < 0) {
|
||||
if (exp <= -8) { fval *= 1e-8; exp += 8; }
|
||||
if (exp <= -4) { fval *= 1e-4; exp += 4; }
|
||||
if (exp <= -2) { fval *= 1e-2; exp += 2; }
|
||||
if (exp <= -1) { fval *= 1e-1; exp += 1; }
|
||||
}
|
||||
else if (exp > 0) {
|
||||
if (exp >= 8) { fval *= 1e+8; exp -= 8; }
|
||||
if (exp >= 4) { fval *= 1e+4; exp -= 4; }
|
||||
if (exp >= 2) { fval *= 1e+2; exp -= 2; }
|
||||
if (exp >= 1) { fval *= 1e+1; exp -= 1; }
|
||||
}
|
||||
|
||||
return fval;
|
||||
}
|
||||
|
||||
// Must be declared for allocation and to satisfy the linker
|
||||
// Zero values need no initialization.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user