1

Имеется вот такой код:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
long double s21_atofLong(const char *str) {
  long int length = strlen(str);
  long double returnValue = 0;
  int counterE = 0;
    int sign = 1;
    int i = 0;
                if ((str[i] == 'i' || str[i] == 'I')
         && (str[i + 1] == 'n' || str[i + 1] == 'N')
         && (str[i + 2] == 'f' || str[i + 2] == 'F')) {
          returnValue = INFINITY;
         }
                if ((str[i] == 'N' || str[i] == 'n')
         && (str[i + 1] == 'a' || str[i + 1] == 'A')
         && (str[i + 2] == 'N' || str[i + 2] == 'n')) {
          returnValue = NAN;
         }
if (str[i] == '+' || str[i] == '-') {
  if (str[i] == '-') {
    sign = -1;
  }
  i++;
}
while(str[i] &gt;= '0' &amp;&amp; str[i] &lt;= '9') {
  returnValue = returnValue * 10 + (str[i] - 48);
  i++;
}
if (str[i] == '.') {
  i++;
}
int pow1 = 1;
while(str[i] &gt;= '0' &amp;&amp; str[i] &lt;= '9') {
  returnValue = returnValue + (str[i] - 48.0) / (10 * pow1);
  i++;
  pow1 = pow1 * 10;
}
if (str[i] == 'e') {
  i++;
}
int signE = 1;
if (str[i] == '+' || str[i] == '-') {
  if (str[i] == '-') {
    signE = -1;
  }
  i++;
}
while(str[i] &gt;= '0' &amp;&amp; str[i] &lt;= '9') {
  counterE = counterE * 10 + (str[i] - 48);
  i++;
}
returnValue = returnValue * pow(10, signE * counterE);

return sign * returnValue; }

int main(int argc, char **argv) {

long double a1 = 1, a2 = 1;

const char str[] = &quot;53.123&quot;;
const char fstr[] = &quot;%Lf&quot;;

a1 = s21_atofLong(str);
sscanf(str, fstr, &amp;a2);

printf("%.25Lf %.25Lf", a1, a2);

return 0; }

Почему из sscanf я получаю немного другое значение, а не как в своей функции?

53.1230000000000000051625371
53.1230000000000000016930901

Ну и получается что при сравнении значений с максимальной точностью получаю, что они не равны. Как правильно будет посчитать?

Kromster
  • 13,809
  • https://ru.stackoverflow.com/questions/913542/ – MBo Nov 28 '22 at 07:30
  • 2
    10-чное : 53.123 ; 2-ичное : 110101.000(1111101111100111011011001000101101000011100101011000000100000110001001001101110100101111000110101001) - бесконечная периодическая и в 64 бита не влазит.... – AlexGlebe Nov 28 '22 at 08:08
  • scanf решает задачу максимум - отыскать вещественное число наиболее близкое к заданной десятичной дроби. Обратите внимание что сама десятичная дробь может не иметь точного представления. То есть, вам надо подыскать вещественное значение близкое ... к чему? К чему-то что вы даже выразить средствами вещественных чисел не можете. Надеюсь, я объяснил почему scanf устроен внутри сложно. Ваш метод использует неточные вычисления (из которых pow - худшее), по этому вы получаете другой результат. Если вы намерены решить задачу примерно, используйте примерное равенство. Иначе - сложно и интересно. – Stanislav Volodarskiy Nov 29 '22 at 11:42

1 Answers1

5

Дробное число невозможно задать точно потому что размер переменной не бесконечен. На каждом шаге оно будет округляться до ближайшего двоичнозадаваемого числа. Разное количество операций приводит к разному округлению.

Сравнивать числа с фиксированной и с плавающей точкой можно только через выражения вроде abs(a-b) < 0.0000000001. Значение подбирается исходя из оценки максимальной погрешности и требованиям к точности.

Обычно это значение зависит от погрешности вводимых данных. Минимальное значение должно быть в 2 раза больше максимальной погрешности косвенных измерений.

eri
  • 35,224
  • 1
    Стоит только добавить, что правильно использовать не 0.0000000001, а Epsilon зависящий от масштаба сравниваемых значений. – Kromster Nov 28 '22 at 08:00
  • 1
    @Kromster По-нормальному вообще надо смотреть на предметную область и исходя из неё выбирать эпсилон ) Какая точность требуется там. – CrazyElf Nov 28 '22 at 08:03
  • потому там и стоит слово "вроде" =) – eri Nov 28 '22 at 08:58
  • Эпсилон не часть предметной области, а часть данных. Каждому вещественному числу должен быть придан свой эпсилон. Иногда, определённой группе чисел, может быть придан один и тот же эпсилон, но это не делает его частью предметной области. – Stanislav Volodarskiy Nov 29 '22 at 10:43
  • Конкретно эта задача формулируется без эпсилон: построить вещественное число наиболее близкое к заданной десятичной дроби. Мы говорим в вводе значении вообще, никаких эпсилонов, только наиболее точный возможный результат. – Stanislav Volodarskiy Nov 29 '22 at 10:44