LudoDu31
LudoDu31

Reputation: 31

Trouble when computing modulos with floats in C

I am not an expert in programming, and I am facing the following issue.

I need to compute modulo between floats A and B. So I use fmod((double)A, (double)B). Theorically, if A is a multiple of B, then the result is 0.0. However, due to floating point precision purpose, A and B are not exactly the number I expected to have. Then, the result of the modulo computation is not 0.0, but something different. Which is problematic.

Example: A=99999.9, but the compiler interprets it as 99999.898. B=99.9, but the compiler interprets it as 99.900002. fmod(A,B) expected to be 0.0, but gives actually 99.9.

So the question is: how do you use to manage this kind of situation ?

Thank you

Upvotes: 2

Views: 80

Answers (1)

chux
chux

Reputation: 153303

The trouble is that:
A is not 99999.9, but 99999.8984375 and
B is not 99.9, but 99.90000152587890625 and
A mod B is 99.89691162109375

OP is getting the correct answer for the arguments given.

Need to use different augments.

A reasonable alternative is to convert the arguments by a scaled power-of-10, then round to an integer, %, back to floating point and un-scale.

Overflow is a concern.

Since OP wants to treat numbers to the nearest 0.1, scale by 10.

#include <float.h>
#include <stdio.h>

int main(void) {
  float A = 99999.9;
  float B = 99.9;
  printf("%.25f\n", A);
  printf("%.25f\n", B);
  printf("%.25f\n", fmod(A,B));
  long long a = lround(A*10.0);
  long long b = lround(B*10.0);
  long long m = a%b;
  double D = m/10.0;
  printf("D = %.25f\n", D);
  return 0;
}

Output

99999.8984375000000000000000000
99.9000015258789062500000000
99.8969116210937500000000000
D = 0.0000000000000000000000000

Alternative

  long long a = lround(A*10.0);
  long long b = lround(B*10.0);
  long long m = a%b;
  double D = m/10.0;

Scale, but skip the integer conversion part

  double a = round(A*10.0);
  double b = round(B*10.0);
  double m = fmod(a,b);
  double D = m/10.0;

Upvotes: 2

Related Questions