@Redproxima
Студент технического ВВУЗ'а

Как проверять на нестрогое неравенство вещественные числа?

Пишу программу, где в участке кода необходимо сравнить некий коэффициент одного объекта с коэффициентом другого объекта, имеющие тип float. Я знаю, что для проверки на равенство (a == b) необходимо использовать специальные костыли, а как быть с проверкой вида ( a <= b) или (a >= b)? На строгое неравенство проверяется отлично, а вот перечисленные конструкции вызывают непредвиденное (для меня разумеется) поведение. Существуют ли методы решения таких вопросов? Существуют ли специально заточенные функции стандартной библиотеки на подобие ctrcmp() для строк, возвращающее 0, >0, <0?

Для наглядности привожу исходник.
Суть: программа хранит две структуры. Одна - с "календарем", где есть дни недели и флаг (выходной\будний). Вторая - структура с подразделениями, где хранятся имя центра, количество дежурных, помощников, коэффицент (дельта) и флаг занят\свободен, с целью не допустить заступления два и более дней подряд. Для каждого дня месяца пргограмма перебирает центры, ищет центр с меньшей дельтой, ставит его в этот день, устанавливает флаг busy и обнуляет флаги busy других центров, обновляет дельту, увеличивая количество фактических заступлений и разделяя на количество имеющихся дежурных.
В общем, не суть. А суть в том, что я уже пытался и явно приводить, умножая при этом на нужное число разрядов, к int, и наоборот. И как я только не пытался. А началось все с того, что при делении 2 / 27 я вообще получал единицу.
Листинг кода
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>


#define MAX_DUTY_CENTERS 12
#define MAX_MOUNTH 31

    struct Duty {
        char center_name[6];
        unsigned short int number_of_duties;
        unsigned short int number_of_helpers;
        float last_delta;
        unsigned short int actual_duty;
        unsigned short int busy;
    };

    struct Dates {
        unsigned short int date;
        char center_name[6];
        unsigned short int weekend;
    };

void  calendar_grid_duty(struct Duty *List_of_Duty, struct Dates *Duty_date, unsigned short int tmp_cntr, unsigned short int tmp_date);
void  calendar_grid_helpers(struct Duty *List_of_Duty, struct Dates *Duty_date, unsigned short int tmp_cntr, unsigned short int tmp_date);

int main()
{
   struct Duty List_of_Duty[MAX_DUTY_CENTERS];
   struct Dates Duty_date[MAX_MOUNTH];

    FILE* Centers = fopen("C:\\Projects\\Sheduler\\Center_list.txt", "r");
    FILE* Calendar = fopen("C:\\Projects\\Sheduler\\bin\\Debug\\Calendar.txt", "r");
    FILE* Duty_list = fopen("C:\\Projects\\Sheduler\\bin\\Debug\\Duty_list.txt", "w");

    int tmp_cntr = 0;
    int tmp_date = 0;

    while(!feof(Centers)){
        fscanf(Centers, "%s%hu%hu%f%hu%hu",
               List_of_Duty[tmp_cntr].center_name,
            &(List_of_Duty[tmp_cntr].number_of_duties),
            &(List_of_Duty[tmp_cntr].number_of_helpers),
            &(List_of_Duty[tmp_cntr].last_delta),
            &(List_of_Duty[tmp_cntr].actual_duty),
            &(List_of_Duty[tmp_cntr].busy));
            tmp_cntr++;
    }

    while(!feof(Calendar)){
        fscanf(Calendar, "%hu%hu",
            &(Duty_date[tmp_date].date),
            &(Duty_date[tmp_date].weekend));
            tmp_date++;
    }
////-----------------------CHECK CENTER READ-------------------------
    printf("tmp_center = %d\n", tmp_cntr);

//    for(int i = 0; i < tmp_cntr; i++){
//        printf("CenterName = %s\nDuties = %d\nHelpers = %d\nDelta = %.4f\nActual duty = %hu\n\n",
//            List_of_Duty[i].center_name,
//            List_of_Duty[i].number_of_duties,
//            List_of_Duty[i].number_of_helpers,
//            List_of_Duty[i].last_delta,
//            List_of_Duty[i].actual_duty);
//    }



//----------------------------CHECK DATE READ------------------------
    printf("tmp_date = %d\n", tmp_date);
//
//   for(int j = 0; j < tmp_date; j++){
//        printf("Date = %u W: %d Center: %s\n",
//            Duty_date[j].date,
//            Duty_date[j].weekend,
//            Duty_date[j].center_name);
//    }
    calendar_grid_duty(List_of_Duty, Duty_date, tmp_cntr, tmp_date);
   // calendar_grid_helpers(List_of_Duty, Duty_date, tmp_cntr, tmp_date);
}
void calendar_grid_duty(struct Duty *List_of_Duty, struct Dates *Duty_date, unsigned short int tmp_cntr, unsigned short int tmp_date){

//---------CALENDAR GRID DISTRIBUTION----(FOR "MAX DAYS" LEIGHT)----------------------------------
//-----Initial weights 1 \ n are initialized, where n is the number of attendants-----------------
    for(int i = 0; i < tmp_cntr; i++){
        List_of_Duty[i].actual_duty = 1;
        List_of_Duty[i].last_delta = List_of_Duty[i].actual_duty / (float)List_of_Duty[i].number_of_duties;
        printf("Fist %hu center delta value = %.4f and factic: %hu\n", i+1, List_of_Duty[i].last_delta, List_of_Duty[i].actual_duty);
    }


    float tmp_delta = List_of_Duty[0].last_delta;
    int nowID;
    for(int i = 0; i < tmp_date; i++){
            tmp_delta = List_of_Duty[0].last_delta;
        for(int j = 0; j < tmp_cntr; j++){
            if(List_of_Duty[j].busy != 0){
                continue;
            } else
            if(List_of_Duty[j].last_delta <= tmp_delta){
                nowID = j;
                tmp_delta = List_of_Duty[j].last_delta;
            }

        }
        memcpy(Duty_date[i].center_name, List_of_Duty[nowID].center_name, sizeof(Duty_date[i].center_name));
            List_of_Duty[nowID].actual_duty++;
            List_of_Duty[nowID].last_delta = (float)List_of_Duty[nowID].actual_duty / (float)List_of_Duty[nowID].number_of_helpers;
            List_of_Duty[nowID].busy = 1;

            for(int k = 0; k < tmp_cntr; k++){
                if(k == nowID){
                    continue;
                } else {
                List_of_Duty[k].busy = 0;}
            }
            strcm
            for(int s = 0; s < tmp_cntr; s++){
        printf("%d center have delta = %f\n", s+1, List_of_Duty[s].last_delta);
            }
            printf("\n");
    }






    for(int i = 0; i < tmp_cntr; i++){
        printf("Second %hu center delta value = %.4f and factic: %hu\n", i+1, List_of_Duty[i].last_delta, List_of_Duty[i].actual_duty);
    }

    printf("Duty men:\n");
    for(int i =  0; i < tmp_cntr; i++){
        printf("%6s\t", List_of_Duty[i].center_name);
        for(int j = 0; j < tmp_date; j++){
            if((strcmp(List_of_Duty[i].center_name, Duty_date[j].center_name)) == 0){
                printf("%hu ", Duty_date[j].date);
            }
        }
        printf("\n");
    }
    printf("\n");
}




    printf("Helpers mens:\n");
    for(int i =  0; i < tmp_cntr; i++){
        printf("%6s\t", List_of_Duty[i].center_name);
        for(int j = 0; j < tmp_date; j++){
            if((strcmp(List_of_Duty[i].center_name, Duty_date[j].center_name)) == 0){
                printf("%hu ", Duty_date[j].date);
            }
        }
        printf("\n");
    }
}

Входные файлы
*Center_list.txt*
A 5 5 0.0 0 0
B 7 8 0.0 0 0
C 20 2 0.0 0 0
D 27 12 0.0 0 0

*Calendar.txt*
1 1
2 1
3 0
4 0
5 0
6 0
7 0
8 1
9 1
10 0
11 0
12 0
13 0
14 0
15 1
16 1
17 0
18 0
19 0
20 0
21 0
22 1
23 1
24 0
25 0
26 0
27 0
28 0
29 1
30 1
31 0
  • Вопрос задан
  • 156 просмотров
Пригласить эксперта
Ответы на вопрос 3
@res2001
Developer, ex-admin
Много букв, не осилил.
Но для вашей задачи просто переведите float в double и забудьте об этой проблеме.
Другой вариант - пересчитывать дельту в число с фиксированной точностью, в целое грубо говоря.

Вопросы округления и сравнения в числах с плавающей точкой обычно важны в математических алгоритмах, где реально много математики. В прикладных задачах обычно это можно легко обойти, варианты обхода я написал выше.

Про сравнение чисел с плавающей точкой есть вводные статьи на хабре. Вариантов сравнения, которые бы удовлетворяли во всех случаях я не встречал. Использовал несколько подходов, но все они работают в каких-то ситуациях, в других не работают. Ситуация тут это набор чисел для сравнения.
Наиболее адекватный вариант, по моему, в boostе.

https://www.boost.org/doc/libs/1_64_0/libs/math/do...
https://rsdn.org/forum/cpp/2640596.1
https://habr.com/ru/post/112953/
https://randomascii.wordpress.com/2012/02/25/compa...
Ответ написан
firedragon
@firedragon
Senior .NET developer
https://stackoverflow.com/questions/17333/what-is-...
Мне вот этот код понравился
bool approximatelyEqual(float a, float b, float epsilon)
{
    return fabs(a - b) <= ( (fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * epsilon);
}

bool essentiallyEqual(float a, float b, float epsilon)
{
    return fabs(a - b) <= ( (fabs(a) > fabs(b) ? fabs(b) : fabs(a)) * epsilon);
}

bool definitelyGreaterThan(float a, float b, float epsilon)
{
    return (a - b) > ( (fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * epsilon);
}

bool definitelyLessThan(float a, float b, float epsilon)
{
    return (b - a) > ( (fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * epsilon);
}
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы
АКМЭ сервис Санкт-Петербург
от 120 000 ₽
Кликнет Санкт-Петербург
До 150 000 ₽
Технология Екатеринбург
от 100 000 до 200 000 ₽