Проблема при вычислении модулей с поплавками в C - PullRequest
2 голосов
/ 24 марта 2020

Я не специалист по программированию, и у меня возникла следующая проблема:

Мне нужно вычислить по модулю между числами A и B. Поэтому я использую fmod ((double) A, (double) B ). Теоретически, если A кратно B, то результат равен 0.0. Однако из-за точности точности с плавающей запятой, A и B не совсем то число, которое я ожидал получить. Тогда результат вычисления по модулю не 0,0, а что-то другое. Это проблематично c.

Пример: A = 99999,9, но компилятор интерпретирует его как 99999,898. B = 99,9, но компилятор интерпретирует его как 99,900002. fmod (A, B) ожидается равным 0,0, но на самом деле дает 99,9.

Итак, вопрос: как вы используете для управления такого рода ситуации?

Спасибо

1 Ответ

2 голосов
/ 24 марта 2020

Проблема в том, что:
A не 99999.9, а 99999,8984375 и
B не 99.9, а 99,90000152587890625 и
A mod B 99.89691162109375

OP получает правильный ответ для заданных аргументов.

Нужно использовать разные дополнения.

Разумная альтернатива - преобразовать аргументы с масштабированной степенью of-10, затем округлите до целое число , %, вернитесь к с плавающей точкой и не масштабируйте.

Переполнение является проблемой.

Поскольку OP хочет обрабатывать числа с точностью до 0,1, масштабируется на 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;
}

Выход

99999.8984375000000000000000000
99.9000015258789062500000000
99.8969116210937500000000000
D = 0.0000000000000000000000000

Альтернатива

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

Масштабировать, но пропустить целое число часть преобразования

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