Introduce an integer multiply-divide algorithm.

We have multiplies followed by divides all over the place and
most of them are difficult to handle regarding overflows. This
new algorithm handles this fine in all cases, as long as all
three operators and the overall result fits into 32 bits.
This commit is contained in:
Markus Hitter 2012-04-24 03:15:36 +02:00
parent 3d1ebf1186
commit 7efb895ee3
3 changed files with 72 additions and 1 deletions

View File

@ -80,7 +80,7 @@ PROGID = arduino
PROGRAM = mendel
SOURCES = $(PROGRAM).c dda.c gcode_parse.c gcode_process.c timer.c temp.c sermsg.c dda_queue.c watchdog.c debug.c sersendf.c heater.c analog.c intercom.c pinio.c clock.c home.c crc.c delay.c
SOURCES = $(PROGRAM).c gcode_parse.c gcode_process.c dda.c dda_maths.c dda_queue.c timer.c temp.c sermsg.c watchdog.c debug.c sersendf.c heater.c analog.c intercom.c pinio.c clock.c home.c crc.c delay.c
ARCH = avr-
CC = $(ARCH)gcc

60
dda_maths.c Normal file
View File

@ -0,0 +1,60 @@
/** \file
\brief Mathematic algorithms for the digital differential analyser (DDA).
*/
#include "dda_maths.h"
#include <stdlib.h>
#include <stdint.h>
/*!
Integer multiply-divide algorithm.
\param multiplicand
\param multiplier
\param divisor
\return rounded result of multiplicand * multiplier / divisor
Calculate a * b / c, without overflowing and without using 64-bit integers.
Doing this the standard way, a * b could easily overflow, even if the correct
overall result fits into 32 bits. This algorithm avoids this intermediate
overflow and delivers valid results for all cases where each of the three
operators as well as the result fits into 32 bits.
Found on http://stackoverflow.com/questions/4144232/
how-to-calculate-a-times-b-divided-by-c-only-using-32-bit-integer-types-even-i
*/
const uint32_t muldiv(uint32_t multiplicand, uint32_t multiplier,
uint32_t divisor) {
uint32_t quotient = 0;
uint32_t remainder = 0;
uint32_t qn = multiplier / divisor;
uint32_t rn = multiplier % divisor;
while(multiplicand) {
if (multiplicand & 1) {
quotient += qn;
remainder += rn;
if (remainder >= divisor) {
quotient++;
remainder -= divisor;
}
}
multiplicand >>= 1;
qn <<= 1;
rn <<= 1;
if (rn >= divisor) {
qn++;
rn -= divisor;
}
}
// rounding
if (remainder > divisor / 2)
quotient++;
// remainder is valid here, but not returned
return quotient;
}

11
dda_maths.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef _DDA_MATHS_H
#define _DDA_MATHS_H
#include <stdint.h>
// return rounded result of multiplicand * multiplier / divisor
const uint32_t muldiv(uint32_t multiplicand, uint32_t multiplier,
uint32_t divisor);
#endif /* _DDA_MATHS_H */