На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
Страницы: (4) [1] 2 3 ... Последняя » все  ( Перейти к последнему сообщению )  
> как детектировать переполнение мантиссы в числе с плавающей точкой?
    Здравствуйте!

    Если числа умножать, то возможно произойдёт переполнение. Как его обработать?

    Например функция, возвращающая максимальное число разрядов, с указанным основанием системы счисления, для типа double.
    ExpandedWrap disabled
      int get_double_digits( int b = 10 )
      {
      int ret = 0;
      double x = 1;
       
      // умножаем до упора
      for(;;)
      {
      x = b * x;
      ret++;
      }
       
      return ret;
      }


    А когда нужно прервать цыкл?

    Интересуют стандартные инструменты. Возможно есть какие-то функции, умножающие с проверкой переполнения?

    Библиотеки, для сверхбольших чисел не волнуют!

    Добавлено
    Есть функция matherr и там даже есть код ошибки overflow. Но кому её указывать? И будет ли она вызвана при умножении? В прочем, похоже, это не тот случай. Слишком неудобен здесь callback.

    Добавлено
    Меня интересует тот момент, когда число, начинает терять точность, отбрасывая младшие разряды.
    Вот например число 9.999 может быть востановлено, а число 9.99999999999999999 превращается в 10.
    По этому я взялся именно умножать, на основание нужной системы счисления.
    Сообщение отредактировано: Eric-S -
      1.Сидеть и на каждое из сотен умножений молиться на переполнение - по-моему глуповато и стандартом не предусмотрено.
      2.Я бы на конкретный случай так залепил:
      ExpandedWrap disabled
        if( (long double)b*(long double)x>1e4000 ) тру-ля-ля; // не 1e4000 конечно, но суть в этом, типа DBL__MAX
        else x = b*x;
          Тоже вариант. Но почему оператор ">"? Если максимальное значение, значит число не может быть больше.
          С другой стороны, при переполнении, биты теряются и в результате получается битовая каша.
          Если процессор проверяет переполнение, то должно быть nan. Но функция _isnan не детектит!
            Цитата Eric-S @
            Есть функция matherr и там даже есть код ошибки overflow. Но кому её указывать? И будет ли она вызвана при умножении? В прочем, похоже, это не тот случай. Слишком неудобен здесь callback.

            Не будет. Это только для целочисленных.


            Цитата Славян @
            2.Я бы на конкретный случай так залепил:

            Выходные параметры надо проверять и выдавать ошибку если они вызывают переполнение.

            Цитата Славян @
            .Сидеть и на каждое из сотен умножений молиться на переполнение - по-моему глуповато и стандартом не предусмотрено

            Можно исключения отлавливать. Вот только тут вопрос что дальше делать?

            Давно известно несколько подходов.
            Забить на ошибки.
            Сделать расчёты так чтобы они были нечувствительны к ошибкам. т. е. устойчивы.
            Проверить входные параметры и выставить false как результат функции.
            Проверить входные параметры и выставить исключение.
            В любом случае ошибку должен обрабатывать решатель, т.е основной код программы. Но так как в большинстве случаев вообще не ясно что делать то выполнение программы прекращается с выкидом ошибки.
              Цитата Pavia @
              Сделать расчёты так чтобы они были нечувствительны к ошибкам. т. е. устойчивы.
              Вот это, думаю, лучшее решение! Беспокоитесь, Eric-S, что будет переполнение - завóдите не 'x', а '_1x', в коем храните 1/x, и тогда уже не умножаете, а без проблем делите на 10. А в итоге - смотрите, получили 0 или нет. Если "да", то это ваш NaN и тут уже раскручиваете карусель.
                Цитата Мяут-Настоящий @
                Была тут недавно тема

                Спасибо... Но там чуток другое. У него же short. И он может взять long, которого заведомо хватит для результата, а потом его проверить константами на переполнение.
                А мне же интересен double или даже long double. А что может быть заведомо больше?

                Цитата Pavia @
                Не будет. Это только для целочисленных.

                Спасибо. Я только описание прочитал.

                Цитата Pavia @
                Забить на ошибки.

                Это не мой подход. Ошибки должны долбать по совести. И желательно посильнее.

                Цитата Pavia @
                Можно исключения отлавливать. Вот только тут вопрос что дальше делать?

                А нет их! Всё тихо.

                Цитата Pavia @
                Проверить входные параметры и выставить false как результат функции.

                Я привел пример функции. Любые входные параметры, ранее или позднее, приводят к переполнению. Хе-хе. При этом входные параметры заведомо корректны.

                Цитата Pavia @
                В любом случае ошибку должен обрабатывать решатель, т.е основной код программы.

                Это как раз понятно. А вот как узнать, что настал тот самый случай? Вот, например, в операционке, встроена програма "calc.exe". Когда я над ней глумлюсь, она порой заявляет, что дальше считать не будет, ибо получается слишком большое число. Но, именно что явно объявляет, а не падает или не выдаёт хрень.
                  Eric-S
                  "calc.exe" использует длинные числа и кучу if.

                  Добавлено
                  Цитата Eric-S @
                  А нет их! Всё тихо.

                  Так замени числа с плавающий точкой на целые числа. К примеру "long long int".
                  Просто для плавающих точек переполнение нет. Зато есть исключение забыл что за исключение но оно не информативное там надо уже конкретно проверять числа.
                  Сообщение отредактировано: Pavia -
                    Цитата Славян @
                    Вот это, думаю, лучшее решение! Беспокоитесь, Eric-S, что будет переполнение - завóдите не 'x', а '_1x', в коем храните 1/x, и тогда уже не умножаете, а без проблем делите на 10. А в итоге - смотрите, получили 0 или нет. Если "да", то это ваш NaN и тут уже раскручиваете карусель.

                    Это была первая мысль. Даже точнее нулевая. Но число-то с плавающей точкой и делить его можно так же до посинения.
                    Я может чего-то путаю, но там же есть, всякие мантиссы и экспаненты. Соответственно и максимально возможное число, будет, гэ-ха-эм, не совсем корректное.

                    В прочем, попробовал. Думал, что оно меня приятно удивит. По идее, я должен получить 16 если задам 10 на входе. Но получил 309.
                    Сообщение отредактировано: Eric-S -
                      Eric-S
                      Давай так. Тебе что надо get_double_digits написать или ошибки научиться обрабатывать?
                        Цитата Pavia @
                        "calc.exe" использует длинные числа и кучу if.

                        Да вроде короткие. За максимальные значения не выскакивал.
                        А куча if... не страшно.

                        Цитата Pavia @
                        Так замени числа с плавающий точкой на целые числа.

                        Мне нужно именно long double. В std::numeric_limits есть функция возвращающая число разрядов для основания системы счисления равным 10. То есть для десятичной системы. А я хочу получить для любой... От 2 (двоичной) до 36-ричной.

                        Не знаю, может надо не через переполнение, а как-то по иному вычислять. Пока не придумался алгоритм.

                        Добавлено
                        Цитата Pavia @
                        Eric-S
                        Давай так. Тебе что надо get_double_digits написать или ошибки научиться обрабатывать?

                        И того и другого, можно даже без хлеба.

                        Добавлено
                        Упс. Мне похоже, чуток не то надо. С учётом экспоненты оно шибко круто набирает высоту. А можно ли как-то получить отдельно значение мантиссы и экспоненты?
                          http://www.cplusplus.com/reference/cmath/frexp/

                          Добавлено
                          Цитата Eric-S @
                          Но функция _isnan не детектит!
                          NaN - это не переполнение.
                          http://www.cplusplus.com/reference/cmath/isinf/

                          Добавлено
                          P.S. Не знаю как сейчас, а раньше MSVC не поддерживал 80-битные числа с плавающей точкой, и long double бы в нем синонимом double.
                          В MSVC бесконечность числа можно проверить функцией _finite
                            Цитата Eric-S @
                            А можно ли как-то получить отдельно значение мантиссы и экспоненты?
                            Да. Можно. К примеру, через наложение структур. Но это емкий процесс, как для такой задачи, хотя, кому как.

                            Написал по памяти, мб и ошибся где-то, но смысл в этом.

                            ExpandedWrap disabled
                              #include <stdio.h>
                               
                              union ParsedDouble
                              {
                                  double dbl; // значение Double
                                  struct
                                  {
                                      unsigned __int64 m : 52;  // мантисса
                                      unsigned int     e : 11;  // экспонента
                                      unsigned int     s : 1;   // знак
                                  } d;
                              };
                               
                              void main()
                              {
                                  ParsedDouble A; // Буфер для перевода
                                  double B;       // Ваша переменная Double
                                  
                                  B = 32.680765433; // Ваше число
                                  
                                  // Переводим
                                  A.dbl = B;
                                      
                                  printf("Мантиса: %I64d \n", A.d.m);
                                  printf("Экспонента: %u \n", A.d.e);
                                  if (A.d.s == 1)
                                      printf("Число отрицательное.");
                                  else
                                      printf("Число положительное.");
                                  
                              }
                              Цитата simsergey @
                              К примеру, через наложение структур.

                              Насколько я знаю, эта структура, может изменятся. Есть даже функции для изменения точности.

                              В прочем, если размер мантиссы жестко фиксирован, то нужное значение, я могу вбить в код магическим числом. И сократить вычисления.

                              Цитата trainer @

                              Ага. Я её уже смотрел. Думал что подойдёт, но не очень понял, что она делает.
                              Сейчас попробовал подобратся глубже... И всё равно туплю.

                              Возвращает число, от 0.5 до 10.
                              Дополнительно указывает... Какое-то число.

                              Решил потестировать. Понятнее не стало. Хотя...

                              ExpandedWrap disabled
                                double x = 1;
                                int n = 0;
                                double r = frexp( x, &n );


                              x=1, r=0.5, n=1.
                              x=2, r=0.5, n=2.
                              x=4, r=0.5, n=3.
                              x=8, r=0.5, n=4.
                              x=10, r=0.265, n=4.

                              Похоже что n - экспонента, но основания двойки. Ндяс. Всё куда интереснее, чем казалось. Ну да верно, ведь число-то хранится в двоичной системе. Уф, откровение!

                              А вот что делать с этим дальше, в практическом смысле... Это же надо как-то пересчитывать, для нужного основания.
                              Сообщение отредактировано: Eric-S -
                                Цитата Eric-S @
                                Насколько я знаю, эта структура, может изменятся.
                                Я так не думаю :)

                                Цитата Eric-S @
                                Например функция, возвращающая максимальное число разрядов, с указанным основанием системы счисления, для типа double.
                                Тип double в с++ использует двоичное основание. Не зависимо того, что вы с ним будете делать, он как хранился по основанию 2 так и будет храниться, ему как выделялось 52 бита под мантису, так и будет выделяться..
                                Если я Вас не так понял, мб переформулируете, или другой приведете пример, что же должна делать функция.. :)
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0460 ]   [ 16 queries used ]   [ Generated: 4.04.25, 10:58 GMT ]