negitive float math

Hello,

I am having trouble with my program during subtraction and the answer should be negative. The variables are float because I use trig to find some angles, so I just made all the ‘math’ variables float, I am not concerned with time.

I am using some whisker sensors and storing the time they are hit in the variables w3t, w5t, etc. Then I am subtracting the times to find how long the difference was between them. The whole prog seems to work well except when I should get a negative tdiffH. I get what is to me a werid value… example:

w3t = 228721876
w4t = 228376604
and the value it came back with was (w4t-w3t)
tdiffH = 4294621952
where it should be -345272

if (w3t == 0 || w5t == 0) { //bad sensor or bad hit but will try to calc
    Serial.println("Who missed it me or you?");
    if (w3t == 0 && w5t == 0) {
      Serial.println("edges are 0 no angle");//something went wrong
      tdiffH = 0;
    }
    else if (w3t == 0) { // "0 7 9", "0 5 5", "0 7 5"
      tdiffH = w5t - w4t;
      Serial.println("1");
    }
    else {// "5 7 0", "5 5 0", "9 7 0"
      tdiffH = w4t - w3t;
      Serial.println("2");
     }
  }
  else if (w3t <= w5t) { // "5 7 9" or "5 5 5"
    tdiffH = w4t - w3t;
    Serial.println("3");
  }
  else if (w3t > w5t) { //"9 7 5"
    tdiffH = w5t - w4t;
    Serial.println("4");
  }
  else {
    Serial.println("something happend wrong");//something went really wrong... I ran out of ifs
  }

I just don’t get the result, when I did a basic program with float values and subtraction it gave back negative numbers fine.
I am enjoying the new serial print float numbers in 18 though.

You don’t show the declration of your variables (w3t, w5t), but assuming they’re floats you may have an issue with the following statement:

if (w3t == 0 || w5t == 0)

Generally it is not considered good practice to compare a float for equality. Rather you should test to see if the value is within an approximate range. Such as:

if (((w3t >= -0.5) && (w3t <= 0.5))  || ((w5t >= -0.5) && (w5t <= 0.5)))

The problem is that the equality operator requires an exact match. Even though two variables only differ with a very small fraction this will not qualify for equality.

You also don't show how w3t and w5t are valued, but you say they are times. If they are the result of a call to millis(), they should be unsigned longs. You don't show they type of tdiffH, either. The results you are seing makes it appear as though you are using unsigned variables.

Please post more (or all) of your code.

I did declare w3t, w4t, w5t as unsigned longs with the function micros(). tdiffH is a float variable. Looks like this is my issue. I am getting a rolled over unsigned long answer. My assumption when I wrote this was that because tdiffH is a float the answer would be float. I thought the largest variable used in a equation would be used, which I thought was float because of the reference page.

Floating-point numbers can be as large as 3.4028235E+38 and as low as -3.4028235E+38.

Where as unsigned longs say:

making their range from 0 to 4,294,967,295 (2^32 - 1).

But now that I actually think about this, the 3.4E38 doesn't make sense to me. This can't mean that a float can hold 3.4E38 as its only 4 bytes. So float var can hold the same as long vars? What is the 3.4E38 supposed to tell me? :-?

How would I get this to output a negative value? Can I force it to output in float? Maybe I just change the to long instead of unsigned and my program will just overflow sooner?

Even though two variables only differ with a very small fraction this will not qualify for equality.

I read that in the reference but it just didn't click when I was writing the program... I'll be sure to check that out, although, I have not run into not entering the if statements, it has always compared properly.

I'll post more code when I can. Thank you for the help... my biggest hurdle in learning the arduino is figuring out variable types and how the program/code switches between and which ones to use.

But now that I actually think about this, the 3.4E38 doesn't make sense to me. This can't mean that a float can hold 3.4E38 as its only 4 bytes.

Yes it can - it just can't hold any particular value to the same precision as an integer. That's why we have floating point and fixed point.

Yes it can

So the maximum value a float can hold is 3.4 x 10^38? Where as a unsigned long maximum is only 4.2 x 10^9?

But both are 4 bytes

A 32 bit float has 23 digits of precision (6+ decimal digits), 7 bits for exponent (2^+/-127) and 2 bits for sign (mantissa and exponent).

A 32 bit integer has 31 bits of precision (9+ decimal digits) and 1 bit for sign.

So the tradeoff is range versus precision.

It is often argued that integer is preferred over float in terms of computation speed. On the Atmel architecture (8-bit RISC) this is however not the case. Float arithmetic is comparable in speed to 32-bit integer arithmetic (it's all handled by hand optimized assembly code).

Imagine that instead of counting by ones, you counted fours, or tens, or…
With a float, you can’t represent all the numbers between 0 and 232-1 (obviously - there are all the decimals in between).

With floating point, the bigger (or smaller) the number, the lower the precision.

As a float, you could subtract one million (1E6) from 3.4E38, and still have 3.4E38.

I see, guess I never understood float. Thanks.

Well that being said why does my equation go to unsigned long when the variable is declared as float? I think I read somewhere that equations take the largest variable type, in this case float. I have:

float = (smaller unsigned long) - (larger unsigned long)

Which I expect to be a negative number in float type.

Because all variables in the calculation are unsigned long, the arithmetic is performed using unsigned longs. Since unsigned longs can't hold a negative value, you get a rollover. The rolled over result is then stored in a float.

What I think you will need to do is track the sign independent from the result:

bool positive;
unsigned long valueOne;
unsigned long valueTwo;
unsigned long result;
if(valueOne > valueTwo)
{
   result = valueOne - valueTwo;
   positive = true;
}
else
{
   result = valueTwo - valueOne;
   positive = false;
}
// The absolute value of the difference is in result
// positive is true if result should be positive. Otherwise, it's false

I see. If I track the sign independent I will also have to factor in overflow. Which I will have to read up on. Any links would be helpful.

Otherwise, would it be bad to just store my time values, micros(), in float instead of unsigned long?

Maybe a better question, Is unsigned long always recommended for timing functions purely because of its size?