На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
  
> Получить значение функции, когда будет деление на 0
    Всем хай! Сходу к делу!

    Есть такая "система":
    Прикреплённая картинка
    Прикреплённая картинка


    a, b, c, x - вещественные.

    Ок, допустим можно написать такую функцию (вот ее заголовок):
    ExpandedWrap disabled
      double F ( const double a, const double b, const double c, const double x );


    Для 1ой ветви такой вызов, например: F( 1, 2, 3, -5 ); - тут все ОК
    Для 2ой ветви такой: F( 1, 0, 5, 5 ); и вот уже ни хрена не ОК, т к будет деление на 0. В этом случае перетекаем в 3ю ветвь, что ли?
    Для 3ей ветви: F( 1, 0, 0, -5 ); опять деление на 0

    Некорректная постанова, да, получается? Или здесь я чего-то не замечаю и "система" ВСЕГДА имеет смысл?
      Смотря что понимать под "корректностью постановки". Так, при c=0 и попадании в случай 3 можно считать, что F неопределена и всё корректно.
        как я понял, вводят с клавиатуры a, b, c, x и нужно вывести на экран значение функции, т е функция типа всегда принимает допустимое значение из своей ОДЗ, я хз
        а вообще это популярная задача (такого типа) и по сети гуляет много ее разновидностей, так по-разному ее лепят, но проверок деления на 0 не делают почти нигде

        все это странно, все это оч.странно...
          Ну и я б не делал. Задача ничего специального не требует, код насчитает то же, что должно получиться математически – бесконечность. Причём с правильным знаком. Зачем излишнюю инициативу проявлять?

          Добавлено
          Ну или будет 0/0, что является неопределённостью, и код тоже вернёт NaN. И тут математически верный результат.
            Цитата Qraizer @
            Ну и я б не делал.


            хорошо, вот данная "система" в заданном виде:
            ExpandedWrap disabled
              double F( const double a, const double b, const double c, const double x )
              {
              #define EPS 0.0001
               
                  double result;
               
                  // 1 ветвь системы
                  if ( ( x < 0 ) && ( b != 0 ) )
                      result = a * x * x + b;
                  else
                      // 2 ветвь системы
                      if ( ( x > 0 ) && ( fabs( b ) <= EPS ) )
                          result = ( x - a ) / ( x - c );
                      // 3 ветвь системы
                      else
                          result = x / c;
               
                  return result;
              }


            Вот тест для 2ой ветки, когда будет деление на 0:
            ExpandedWrap disabled
                  double a = 1.0;
                  double b = 0.0;
                  double c = 5.0;
                  double x = 5.0;
               
                  double result = F( a, b, c, x );

            В итоге в переменную result заносится значение 1.#INF000 (там много нулей идет). Я так давно не делил на 0, что даже забыл, что прожка не крашится при этом, ну, ок) А вот отловить это значение НЕ удалось.

            Для проверки на NAN есть функция из заголовка <float.h>:
            ExpandedWrap disabled
                  if ( _isnan( result ) )
                      printf( "\n Getting NOT a number!" );


            Для проверки с 1.#INF00 пишут, что есть функция isinf / _isinf, но нет ее ни в math.h, ни в float.h. Покурив мат.часть я так и не понял, ее ввели только в С99 или она где-то раньше была еще, причем во всех примерах ее юзают налево и направо, а у меня VS 2010 (исходник *.c) НЕ видит этой функции isinf...

            В общем вывод такой для себя сделал: функцию F можно оставить БЕЗ проверок деления на 0 (хотя это ооооооооооочень странно выглядит) и просто выпечатывать то, что получилось: норм.значение, NAN или этот +-1.#INF00(0). Но вроде NAN невозможно получить ни при каких входных a, b, c, x - хотя не уверен.

            В общем единственное, что хотелось бы еще понять, как проверить на 1.#INF00 в C89 (или C90, я так и не понял на 100%, какой комплятор вшит в студию по дефалту, но точно не С99)
                Цитата Qraizer @
                Не работает?

                да уж, все отлично работает в твоем варианте, я балда даже не заметил, что ты раньше все мне написал, что да как)
                вот так сделал:
                ExpandedWrap disabled
                  // return 1 if isinf, else 0
                  int __cdecl Is_inf( const double x )
                  {
                  #define EPS 0.00001
                      // x/2.0 - x дает -1.#INF000, ок, поэтому пробуем вариант Qraizer :)
                      // if ( ( fabs( x/2.0 - x ) <= EPS ) && ( x + 2 == x ) )
                   
                      // вариант Qraizer работает превосходно! Вот так то.
                      if ( ( x/2.0 == x ) && ( x + 2 == x ) )
                          return 1;
                      return 0;
                  }


                после всего этого я даже не буду уточнять, почему дробные значения сравниваются между собой на прямую через "==", почему получаем -1.#INF000 и т.п., т к вопросов в 1000 раз больше, чем ответов. Пока работает, ну и слава б-гу))

                Нашел еще много полезной инфы по поводу стандарта С99 и мат.нововведений. Такое чувство, что С99 улучшился в основном ТОЛЬКО из-за расширения <math.h> и добавления кучи новых макросов, констант, функций isnan, isinf, INFINITY, а в С89 вообще ни хрена в этом плане полезного не было (лишь 22 мат.функции) и вот хрен его знает, почему VS 2010 "видит" функцию _isnan, о которой кстати почти нет инфы, а есть только про isnan.

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

                Qraizer, спасибо за проверку на isinf - там дичь какая-то, но работает превосходно...с др.стороны так и нужно проверять это isinf и по-другому никак вообще
                  Цитата FasterHarder @
                  после всего этого я даже не буду уточнять, почему дробные значения сравниваются между собой на прямую через "=="
                  Потому что для "дробных значений" aka "нормализованное вещественное" всегда будет "не равно". Уравнение x/2 == x не имеет ненулевых решений. "Равно" возможно только для спец.форматов: нуля и бесконечности.

                  Добавлено
                  P.S. Нуль тоже спец.формат, как ни странно. И это единственное "вещественное", для которого IEEE может гарантировать точность операций эквивалентности.
                    Цитата Qraizer @
                    "нормализованное вещественное"

                    кстати, в С99 что-то добавлено для обработки нормализованных вещественных
                    Qraizer, спс за помощь ;)
                      Цитата FasterHarder @
                      почему получаем -1.#INF000
                      Ну вот так работает преобразование inf в строку. Единичка впереди – дань традиции, т.к. в прошлой редакции IEEE помимо "обычных" спец.форматов были ещё всяко-разные псевдо-: -бесконечноности, -нечисла, -нули и -денормализованное, а также ненормализованные числа. Единичка впереди однозначно отделяла псевды от настоящих. В современном IEEE псевды упразднены, но совместимость всё ещё местами играет роль. Знак же определяет... хм, знак. Бесконечность – она знаковая. Правда, опять же, в прошлом IEEE определял две бесконечности: аффинная и проективная. Последняя не различала знак, ныне этот тип в IEEE упразднён. Ну а нулики в конце просто дополняют поле вывода до нужной ширины, в %f по умолчанию 6 знаков после запятой.

                      Добавлено
                      Цитата FasterHarder @
                      // x/2.0 - x дает -1.#INF000, ...
                      x/2.0 - x должно дать NaN, если x бесконечность. Вычитание двух бесконечностей одного знака – это неопределённость.
                        Цитата Qraizer @
                        Единичка впереди – дань традиции
                        Или особенность работы процедуры конвертирования в строку. В нормализованный числах ведь первая единичка мантиссы опускается.

                        Ещё. Часто в IEEE-представлении при исчезновении порядка (число становится меньше минимально представимого нормализованного ненулевого) происходит переход к ненормализованному представлению.
                          Денормализованному. Ненормализованный упразднён, как и всякие там псевды, и отличается тем, что он имеет порядок в валидном диапазоне вместо минимально представимого. Ненормализованный никогда не считался нормальным форматом (как минимум из-за потери точности представления) и в своё время допускался в связи с тогдашными ограничениями аппаратных реализаций IEEE, предполагалось, что им будут помогать программно нормализовывать этот спец.формат. Никакого полезного смысла в этом формате не было. Денормализованные в отличие от них полезны, т.к. позволяют плавно, посредством постепенной потери точности мантиссы, сводить очень малые значения к нулю, вместо того, чтобы обнулить сразу и резко. При этом такие значения всё равно обрабатываются корректно и выводятся в обычной форме.
                          Замечу, что все спец.форматы, кроме нуля, возможны только при явной старшей единице. Ныне таковым является только оригинальный long double, который 80-битный, он по-прежнему поддерживается FPU, но уже очень давно не имеет официального отражения на типы C/C++ (хотя Intel Compiler всё ещё имеет ключик командной строки для его активации) и всякие там SIMD с его SSExx. Но ты можешь быть прав, я не проверял, как ведут себя библиотеки при работе с ненормализованными числами, ибо сейчас уже тупо нет железа, на котором можно было бы проверить сие.
                          0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                          0 пользователей:


                          Рейтинг@Mail.ru
                          [ Script execution time: 0,0705 ]   [ 18 queries used ]   [ Generated: 2.05.24, 14:59 GMT ]