0

Are there any methods, code snippets or libraries to perform simple calculations (multiplications, divisions, sums, subtractions) without using floating point numbers?

I code in C on an 8 bits MCU without Floating Point Unit, so floating calculations are very long. I would like to convert all my floating point calculations to integers.

I can allow doing float calculations at initialization for example to calculate integer coefficients from float coefficients.

AdriZ
  • 393
  • 3
  • 9
  • 4
    Fixed-point arithmetic is *very* common in the embedded world. So while it's easy to do yourself (as 0___________'s answer shows), there have got to be *gobs* of libraries out there, already written, to do it for you. Try [this Google search](https://www.google.com/search?q=fixed-point+library+C). (I don't work in the embedded world, however, so I can't recommend one.) – Steve Summit Nov 18 '22 at 14:37
  • 1
    See also [the Wikipedia article](https://en.wikipedia.org/wiki/Fixed-point_arithmetic) – Steve Summit Nov 18 '22 at 14:44
  • "methods to perform simple calculations without using floating point numbers" --> possible but easy to do so poorly. – chux - Reinstate Monica Nov 18 '22 at 19:36
  • Thanks to all! "Fixed point arithmetic" is indeed what I am looking for. – AdriZ Nov 21 '22 at 10:21

1 Answers1

0

Scale your integers by using one or two digits as the fractional part. For example, 345 can be interpreted as 3.45. All arithmetic is (almost) exactly the same.

Example:

int mult(int a, int b)
{
    long long result = ((long long)a * b) / 100;
    if(result > INT_MAX || result < INT_MIN) { /* do something */}
    return result;
}

int divide(int a, int b)
{
    return b ? ((long long)a * 100) / b : 0;
}


int main(void)
{
    int result = divide(500, 3000);
    printf("%d.%d\n", result / 100, result % 100);
}
0___________
  • 60,014
  • 4
  • 34
  • 74
  • OK. Thanks. It is more problematic for divisions: int div(int a, int b) if b > a, the result is 0. I guess it can't be well done without defining a specific type, taking into account the output exponent. – AdriZ Nov 18 '22 at 14:19
  • @AdriZ It is done this way - but you can of course try to invent something new. Division you need to scale the opposize way. – 0___________ Nov 18 '22 at 14:22
  • Usually, I would scale by a power of 2, e.g., `1<<16` if you store your values in 32bit integers. Maybe unless you actually work with currency values, or a significant amount of your work is converting from/to decimal strings. – chtz Nov 18 '22 at 14:25
  • @chtz you can scale any way you wish. This is just example. – 0___________ Nov 18 '22 at 14:27
  • 2
    this is [fixed-point math](https://en.wikipedia.org/wiki/Fixed-point_arithmetic). And definitely scaling by a power of 2 is preferable for performance. @AdriZ rounding to nearest is simple. Do some research on it – phuclv Nov 18 '22 at 14:32
  • 1
    @phuclv I agree, but decimal is easier to understand by beginners – 0___________ Nov 18 '22 at 14:34
  • And it's useful to understand that the scaling factor can be literally *anything*. You could use 3373 as the scaling factor and everything would work out the same. (Well, except for the way things rounded, of course.) – Steve Summit Nov 18 '22 at 14:43
  • `"%d.%d\n"` more likely should be `"%d.%02d\n"` yet still does not well handle case when `result < 0`. – chux - Reinstate Monica Nov 18 '22 at 18:04
  • `((long long)a * 100) / b` does not round right, more like `((long long)a * 100 + 50) / b` and cleaner as `(a * 100LL + 50) / b` when dividend/divisor are positive. In general, this scaling idea is sound, yet there are cases not yet handled well especially rounding. – chux - Reinstate Monica Nov 18 '22 at 18:10
  • @chux-ReinstateMonica `((long long)a * 100 + 50) / b` will not round correctly, either. You could try `((long long)a * 100 + b/2) / b` (still need to be careful with negative inputs). – chtz Nov 18 '22 at 21:39
  • @chtz Yes, you are correct s/b `+ b/2`, not `+ 50/2` and with additional concerns about sign. – chux - Reinstate Monica Nov 18 '22 at 22:28
  • Thanks to all! "Fixed point arithmetic" is indeed what I am looking for. The comments confirm me that it is useful to work with a library that will handle all the side effects. – AdriZ Nov 21 '22 at 10:10
  • I think it's still interesting to do my own calculations so I can do calculations like: a*b/c If we do : `uint16_t tmp=mul(a,b);` `uint16_t result=div(tmp,c);` Even if result is OK in 16 bits, it is possible that tmp overflows. By going through all the float calculations that I want to convert in integer, I realize that I will have to think each time about all the possible cases of overflow. – AdriZ Nov 21 '22 at 10:19