From 4febbea2f8fc1be281e19fc69a69cb583bb47d0f Mon Sep 17 00:00:00 2001 From: Stephan Walter Date: Tue, 11 Jan 2011 19:17:52 +1100 Subject: [PATCH] fix decfloat_to_int, Less divisions in decfloat_to_int. Signed-off-by: Michael Moon --- gcode_parse.c | 58 ++++++++++++++++------------------------- gcode_parse.h | 16 +++++++----- sermsg.c | 72 ++++++++------------------------------------------- 3 files changed, 44 insertions(+), 102 deletions(-) diff --git a/gcode_parse.c b/gcode_parse.c index c9a74e9..3b3014d 100644 --- a/gcode_parse.c +++ b/gcode_parse.c @@ -25,10 +25,10 @@ which is about the worst case we have. All other machines have a bigger build volume. */ -#define STEPS_PER_M_X ((uint32_t) (STEPS_PER_MM_X * 1000.0)) -#define STEPS_PER_M_Y ((uint32_t) (STEPS_PER_MM_Y * 1000.0)) -#define STEPS_PER_M_Z ((uint32_t) (STEPS_PER_MM_Z * 1000.0)) -#define STEPS_PER_M_E ((uint32_t) (STEPS_PER_MM_E * 1000.0)) +#define STEPS_PER_M_X ((uint32_t) ((STEPS_PER_MM_X * 1000.0) + 0.5)) +#define STEPS_PER_M_Y ((uint32_t) ((STEPS_PER_MM_Y * 1000.0) + 0.5)) +#define STEPS_PER_M_Z ((uint32_t) ((STEPS_PER_MM_Z * 1000.0) + 0.5)) +#define STEPS_PER_M_E ((uint32_t) ((STEPS_PER_MM_E * 1000.0) + 0.5)) /* mm -> inch conversion @@ -50,8 +50,10 @@ GCODE_COMMAND next_target __attribute__ ((__section__ (".bss"))); /* utility functions */ +extern const uint32_t powers[]; // defined in sermsg.c +const int32_t rounding[DECFLOAT_EXP_MAX] = {0, 5, 50, 500, 5000, 50000, 500000}; -int32_t decfloat_to_int(decfloat *df, int32_t multiplicand, int32_t denominator) { +static int32_t decfloat_to_int(decfloat *df, int32_t multiplicand, uint32_t denominator) { int32_t r = df->mantissa; uint8_t e = df->exponent; @@ -59,36 +61,21 @@ int32_t decfloat_to_int(decfloat *df, int32_t multiplicand, int32_t denominator) if (e) e--; - // scale factors -// if (multiplicand != 1) -// r *= multiplicand; -// if (denominator != 1) -// r /= denominator; - int32_t rnew1 = r * (multiplicand / denominator); - int32_t rnew2 = r * (multiplicand % denominator) / denominator; - r = rnew1 + rnew2; + if (e) + { + int32_t rnew2 = r * (multiplicand % denominator) / denominator; + r = rnew1 + rnew2; - // sign - if (df->sign) - r = -r; - - // exponent- try to keep divides to a minimum for common (small) values at expense of slightly more code - while (e >= 5) { - r /= 100000; - e -= 5; + r = (r + rounding[e]) / powers[e]; + } + else + { + int32_t rnew2 = (r * (multiplicand % denominator) + (denominator / 2)) / denominator; + r = rnew1 + rnew2; } - if (e == 1) - r /= 10; - else if (e == 2) - r /= 100; - else if (e == 3) - r /= 1000; - else if (e == 4) - r /= 10000; - - return r; + return df->sign ? -r : r; } /**************************************************************************** @@ -292,10 +279,11 @@ void gcode_parse_char(uint8_t c) { #endif default: - // can't do ranges in switch..case, so process actual digits here. Limit the digits right of the decimal to avoid variable overflow in decfloat_to_int() due to excess precision - if (c >= '0' && c <= '9' && - ((next_target.option_inches == 0 && read_digit.exponent < 4) || - (next_target.option_inches && read_digit.exponent < 5))) { + // can't do ranges in switch..case, so process actual digits here. + if ( c >= '0' + && c <= '9' + && read_digit.mantissa < (DECFLOAT_MANT_MAX / 10) + && read_digit.exponent < DECFLOAT_EXP_MAX ) { // this is simply mantissa = (mantissa * 10) + atoi(c) in different clothes read_digit.mantissa = (read_digit.mantissa << 3) + (read_digit.mantissa << 1) + (c - '0'); if (read_digit.exponent) diff --git a/gcode_parse.h b/gcode_parse.h index 18e38ce..3359cbb 100644 --- a/gcode_parse.h +++ b/gcode_parse.h @@ -16,11 +16,18 @@ // wether to insist on a checksum //#define REQUIRE_CHECKSUM -// this is a very crude decimal-based floating point structure. a real floating point would at least have signed exponent +// this is a very crude decimal-based floating point structure. +// a real floating point would at least have signed exponent. +// max (DECFLOAT_EXP_MAX - 1) digits after decimal point, because point is +// counted as well +#define DECFLOAT_EXP_WIDTH 3 +#define DECFLOAT_EXP_MAX ((1 << DECFLOAT_EXP_WIDTH) - 1) +#define DECFLOAT_MANT_WIDTH (32 - 1 - DECFLOAT_EXP_WIDTH) +#define DECFLOAT_MANT_MAX (((uint32_t)1 << DECFLOAT_MANT_WIDTH) - 1) typedef struct { uint32_t sign :1; - uint32_t mantissa :24; - uint32_t exponent :7; + uint32_t mantissa :DECFLOAT_MANT_WIDTH; + uint32_t exponent :DECFLOAT_EXP_WIDTH; } decfloat; // this holds all the possible data from a received command @@ -67,9 +74,6 @@ typedef struct { // the command being processed extern GCODE_COMMAND next_target; -// utility functions -int32_t decfloat_to_int(decfloat *df, int32_t multiplicand, int32_t denominator); - // accept the next character and process it void gcode_parse_char(uint8_t c); diff --git a/sermsg.c b/sermsg.c index 87eaa13..ae2245f 100644 --- a/sermsg.c +++ b/sermsg.c @@ -25,72 +25,22 @@ void serwrite_hex32(uint32_t v) { serwrite_hex8(v & 0xFFFF); } +const uint32_t powers[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; + void serwrite_uint32(uint32_t v) { - uint8_t t = 0; - if (v >= 1000000000) { - for (t = 0; v >= 1000000000; v -= 1000000000, t++); - serial_writechar(t + '0'); + uint8_t e, t; + + for (e = 9; e > 0; e--) { + if (v >= powers[e]) + break; } - if (v >= 100000000) { - for (t = 0; v >= 100000000; v -= 100000000, t++); + do + { + for (t = 0; v >= powers[e]; v -= powers[e], t++); serial_writechar(t + '0'); } - else if (t != 0) - serial_writechar('0'); - - if (v >= 10000000) { - for (t = 0; v >= 10000000; v -= 10000000, t++); - serial_writechar(t + '0'); - } - else if (t != 0) - serial_writechar('0'); - - if (v >= 1000000) { - for (t = 0; v >= 1000000; v -= 1000000, t++); - serial_writechar(t + '0'); - } - else if (t != 0) - serial_writechar('0'); - - if (v >= 100000) { - for (t = 0; v >= 100000; v -= 100000, t++); - serial_writechar(t + '0'); - } - else if (t != 0) - serial_writechar('0'); - - if (v >= 10000) { - for (t = 0; v >= 10000; v -= 10000, t++); - serial_writechar(t + '0'); - } - else if (t != 0) - serial_writechar('0'); - - if (v >= 1000) { - for (t = 0; v >= 1000; v -= 1000, t++); - serial_writechar(t + '0'); - } - else if (t != 0) - serial_writechar('0'); - - if (v >= 100) { - t = v / 100; - serial_writechar(t + '0'); - v -= (t * 100); - } - else if (t != 0) - serial_writechar('0'); - - if (v >= 10) { - t = v / 10; - serial_writechar(t + '0'); - v -= (t * 10); - } - else if (t != 0) - serial_writechar('0'); - - serial_writechar(v + '0'); + while (e--); } void serwrite_int32(int32_t v) {