Check floating point equality

Hi, I am using a simple code to check if a number Tsw divided by another Ts gives 0 or not in order to computer integer multiplicity. The code works fine on a computer however on the arduino it behaves weirdly. Can someone please help identify the issue and fix it?

void setup() {
        Serial.begin(115200);
   	
        double Ts = 0.05;
	double Tsw = 1.20;// i need to try with 1.20 and 1.13 or anything that yields integer and non-integer

	double TswDivTs = Tsw/ Ts; // want to know if TswDivTs is integer or not
	
	Serial.print(F("TswDivTs : "));Serial.println(TswDivTs,12);
	Serial.print(F("int TswDivTs :"));Serial.println(int(TswDivTs));

	double z = (int(TswDivTs)*Ts) - Tsw;
	Serial.print(F("double z :"));Serial.println((z),10);

	if (z==0.0){ 
	Serial.println("Tsw is integer multiple");
	}
	else{
	Serial.println("Tsw is not integer multiple");
	}

}

void loop() {
  // put your main code here, to run repeatedly:

}
if (z==0.0){

Do not ever try to compare a floating-point number to exactly zero. You must always have a tolerance. The reason is that there is no exact binary floating point number for seemingly simple numbers like 10. This will be represented in the floating-point format as 9.9999991 or something.

Now divide that by 5. You won't get exactly 2.00000000.

You must always compare floating point numbers with a threshold. Set that threshold very small, like .00001 and then use this code:

#define FP_THRESHOLD 0.00001
if(z > -FP_THRESHOLD && z < FP_THRESHOLD) {
  //z is close enough to zero

10 is directly represented (as are all integers up to about 2^23), 0.1 isn't

Thanks. 0.1 is a better example to use for this explanation.

would it not be more correct to check as any float operation in this line

double z = (int(TswDivTs)*Ts) - Tsw;

can affect the equality in negative sense

  if (int(TswDivTs) == TswDivTs)
  {
    Serial.println("Tsw is integer multiple");
  }
  else 
  {
    Serial.println("Tsw is not integer multiple");
  }

and yes, even int() has its limits.

Hello all,
I thank you for your input. As per the two suggestions I have got here, I tried both methods on an Arduino Due using the 1.6.4 IDE. In one case I used (only if statement shown below)

if (int(TswDivTs) == TswDivTs)
  {
    Serial.println("Tsw is integer multiple");
  }
  else
  {
    Serial.println("Tsw is not integer multiple");
  }

The output was

TswDivTs : 24.000000000000
int TswDivTs :23
double z :-0.0500000000
Tsw is not integer multiple

and in another case i tried

	if (z > -FP_THRESHOLD && z < FP_THRESHOLD ){
	Serial.println("Tsw is integer multiple");
	}
	else{
	Serial.println("Tsw is not integer multiple");
	}

and the output was

TswDivTs : 24.000000000000
int TswDivTs :23
double z :-0.0500000000
Tsw is not integer multiple

As you can see, in neither cases did the code tell me that a division of 1.20 by 0.05 yields an integer. I really need to find a solution to this...and it's frustrating because this check works on my desktop computer but not on an arduino.

just because the math works on your desktop, It does not mean it is directly compatible with the due, or any micro controller.

It is unfair to compare the Arduino due, which does not have a math coprocessor, with a desktop computer, which has a math coprocessor built into the main processor. without a math coprocessor, a desktop computer would be very limited in the math that it could execute.

If you need better math capability, you need a math coprocessor. otherwise if you need to output a integer, you need to work with the limitations of the processor, and use integers to start with.

Hi Promacjoe,
I understand what you are saying. Just to confirm, is there no way to achieve what I'm trying to do on the DUE then? see if the division of two rational number yields an integer result?

If your computational needs exceed the ability of the Arduino due, you need to add a math coprocessor, such as this one;

http://micromegacorp.com/umfpu64.html

this should solve your problems.

Note: there are probably dozens of different Math coprocessors available, this is only one example. do your homework first.

I now have a Due free and the inequality tests are the most robust to test if a number is.
If you print the numbers with 20 decimals you see that float math never is exact

//
//    FILE: .ino
//  AUTHOR: Rob Tillaart
// VERSION: 0.1.00
// PURPOSE:
//    DATE:
//     URL:
//
// Released to the public domain
//

#define FP_THRESHOLD 0.001

void setup()
{
  Serial.begin(115200);

  double Ts = 0.05;
  double Tsw = 1.20;

  double TswDivTs = Tsw / Ts; // want to know if TswDivTs is integer or not

  Serial.print(F("TswDivTs : ")); Serial.println(TswDivTs, 12);
  Serial.print(F("int TswDivTs : ")); Serial.println(int(TswDivTs));

  double z = (round(TswDivTs) * Ts) - Tsw;

  Serial.print(F("double z :"));
  Serial.println(z, 20);
  Serial.println(abs(z), 20);
  Serial.println(TswDivTs, 20);
  Serial.println(abs(round(TswDivTs) - TswDivTs), 20);

  if (z == 0.0) Serial.println("1: Tsw is integer multiple");
  if (abs(z) < FP_THRESHOLD) Serial.println("2: Tsw is integer multiple");
  if (abs(round(TswDivTs) - TswDivTs) < FP_THRESHOLD) Serial.println("3: Tsw is integer multiple");
  if (round(TswDivTs) == TswDivTs) Serial.println("4: Tsw is integer multiple");

  Ts = 0.05;
  Tsw = 1.20000001;
  TswDivTs = Tsw / Ts; // want to know if TswDivTs is integer or not
  z = (round(TswDivTs) * Ts) - Tsw;

  if (z == 0.0) Serial.println("1: Tsw is integer multiple");
  if (abs(z) < FP_THRESHOLD) Serial.println("2: Tsw is integer multiple");
  if (abs(round(TswDivTs) - TswDivTs) < FP_THRESHOLD) Serial.println("3: Tsw is integer multiple");
  if (round(TswDivTs) == TswDivTs) Serial.println("4: Tsw is integer multiple");

}

void loop()
{
  // put your main code here, to run repeatedly:
}

Hi Robtillart,
It seems that your code works best with method 4. Method 1 is completely inaccurate.

Method 2 and 3 rely heavily on the value of FP_threshold. If it is 1e-3 or 1e-4 it yields inaccurate answers if Tsw is chosen to have 6 or 7 decimal zeros and then a 1 above an integer multiple of Ts.

Then I tried a method 5 where i test

Serial.print(F("abs z : ")); Serial.println(abs(z));
  if (abs(z) == 0.0) Serial.println("5: Tsw is integer multiple"); else if (round(TswDivTs) != TswDivTs) Serial.println("5: Tsw is not integer multiple");
  Serial.println(" ");

This is exactly the same as method 4 but instead checking against 0.0. And it works perfectly.
Thank you all for your help.