Making a formula float free

I have a formula that uses floats. I’d like to make it float free, and use ints only. Ideas?

The float version:

variables:

Where num = 2300, bin will return 93

// convert mm to bin numbers

int convert() {
float mm;
float maxmm = 2.330;
float range = .003;
float jump = .004;
int maxl = 100;

mm = (float)num/1000;

float formula = round((((maxmm-(range/2.000))-mm)/jump));

int f;

f = (int)formula;

int bin = maxl-f;

return bin;

}

The trick is to use a common multiple.

You have to decide on the precision you want, and then multiply everything by that.

So, let's say you want a 3 decimal precision - you'd pick a multiply factor of 1000.

Representing 9 would be 9000. Representing 0.004 would be 4.

Then, at the end, divide the whole answer by the scaling factor.

// convert mm to bin numbers

int convert(int num) {
  long convnum;
  long mm;
  int maxmm = 2330;
  int range = 3;
  int jump = 4;
  long maxl = 100000;

  convnum = num * 1000; // scale it
  mm = num/1000;  // Yes, this makes the previous line redundant - but only for a scaling of 1000.

  long formula = (((maxmm-(range/2))-mm)/jump);
  return formula/1000;
}

Of course, I don't know if this actually works, as I haven't tested it, but you get the idea (I hope)

Are these values variables or constants?

float maxmm = 2.330;
float range = .003;
float jump = .004;
int maxl = 100;

If they are constants, you can calculate the result, then your formula will be easier. After that, you can multiply everything in order to eliminate decimals.

Majenko, the formula still comes out to 7.125

I need it to come out to 7125, then say

if formula >6999 & <7501
then formula = 7000
if formula >7500 & <8001
then formula = 8000

jorgepl, those are constants.

Majenko, the formula still comes out to 7.125

Then don't do the final /1000.

int range = 3;

.... - range/2 - ....

probably does not do what is intended. Working with integers requires a bit thinking about intermediate results, underflow and overflow. float arithmetics make us a bit lazy :wink:

I only picked a scale of 1,000 as an example. 10,000 might be more appropriate given the numbers involved, or even 100,000.

Be sure to use longs where appropriate.

That's before the final / 1000

7.125=((((2330-(3/2))-2300)/4))

Then you can simplify the formula:

formula = round (((2.330-0.003/2.000)-mm)/0.004) = round (582.125-(num/4)) = round (4657-2num)/8)
~= (4657 - 2
num)/8

formula ~= (4657-2*num)/8

I’m confused. I use a spreadsheet to check my values before coding them.

micrometer.xls (13.5 KB)

jorgepl, different sections of the program have different constants based on what gear family you are testing (ok, so that kind of makes them variables, doesn’t it? My bad). You are still using floats in that formula.

I’ve attached the complete sketch so you can see how it’s being used. I’m trying to speed things up by eliminating float arithmatic, since I can put an int in, and get an int out.

micrometer.ino (30.7 KB)

What floats?

jorgepl:
formula ~= (4657-2*num)/8

Naugthy boy!!!

oh, formula = round (((2.330-0.003/2.000)-mm)/0.004) is equivalent to (4657-2*num)/8

I get it. no problem, I just work out a different formula above for each section of code.

except it's formula = round((((2330-(3/2))-2300)/4))

(2330 - 1.5) -2300

(2328.5 - 2300) / 4

28.5 / 4

Round(7.125)

7

100 - 7

Bin = 93

jorgepl:
What floats?

jorgepl:
formula ~= (4657-2*num)/8

You can even do without division and multiplication in this case, just shifts on uint16_t variables :wink:

michael_x:
You can even do without division and multiplication in this case, just shifts on uint16_t variables :wink:

Compiler will do.

say what?

But you said range=0.003:

float maxmm = 2.330;
float range = .003;
float jump = .004;
int maxl = 100;

yes,

round (((2.330-(0.003/2.000)-mm)/0.004))

you put

round (((2.330-0.003/2.000)-mm)/0.004)

That changed the order of arithmetic.

Another poster said to multiply everything by 1000 to get rid of decimals. If I use 10000:

round (((23300-(30/2)-23000)/40)

(((23300-(15)-23000)/40)

285 /40 = 7.125 (still back to a decimal)

so, ((1000*(23300-(30/2)-23000)/40))

gives me 7125

if formula >6999 & <7501
then formula = 7000
if formula >7500 & <8001
then formula = 8000

So 1000 * maxBin (100) = 100000 - 7000 = 93000 / 1000 = 93

Bin 93 is correct. No decimals.

If you want the result to be in different units, then the value going in will have to be in different units.

Multiply num by 1000 before you start, and the result will be multiplied by 1000.

You don't do a sum on meters and suddenly end up with millimeters, without some extra multiplication in place.