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

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

    Например функция, возвращающая максимальное число разрядов, с указанным основанием системы счисления, для типа 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 бита под мантису, так и будет выделяться..
                                Если я Вас не так понял, мб переформулируете, или другой приведете пример, что же должна делать функция.. :)
                                  Eric-S
                                  Тема большая поэтому всё рассказать не получиться.

                                  Числа с плавающей точкой состоят из мантиссы и экспоненты. И ещё бывают децентрализованные и нормализованные.
                                  Проблема в том что перевод чисел из одной системы счисления в другую идут с ошибками округления. Поэтому тут надо будет ещё аккуратно.
                                  А ещё числа бывают двоичные и десятичные. Десятичные конечно редкость.

                                  Формат вывода чисел бывает с фиксированной точкой бывает научный (-d.ddd...E+ddd...)

                                  Мантиса.
                                  Точность мантисы. Точность можно вычислить
                                  http://en.wikipedia.org/wiki/Machine_epsil...n_using_C.2B.2B
                                  Но гораздо проще воспользоваться константой.
                                  В Си есть библиотека констант.
                                  std::numeric_limits
                                  Но так как константу нельзя записать числами из за погрешности при переводи из одной системы счисления(СС) в другую СС.
                                  Поэтому машинную точность определяют через функцию power
                                  EpsSingle=power(2,-24);
                                  EpsDouble=power(2,-53);

                                  Экспонента.
                                  Тут уже сказали что будет inf(бесконечность), а не NaN(не число).

                                  Пересчёт констант из одной СС в другую.
                                  Константы легко пересчитать для разной СС.
                                  2^13=10^x
                                  log_10(2^13)=x
                                  Или x=log(2^13)/log(10)

                                  Что касается ловли ошибок.
                                  У чисел с плавающей точкой есть разные классы ошибок.
                                  http://www.openwatcom.org/index.php/Math_e...handling_on_x87
                                  http://msdn.microsoft.com/en-us/library/wi...9(v=vs.85).aspx
                                  Тип ошибок который стоит обрабатывать надо просто установить.
                                  http://msdn.microsoft.com/en-us/library/c9...6h(VS.100).aspx

                                  По умолчанию насколько помню включено деления на 0 и неправильная команда.
                                  Некоторые графические библиотеки любят работать с определённым типом чисел нормированные/денормальными.

                                  По поводу общей концепции обработки ошибок. Такого описания я не видел.
                                  В численных методах есть два движение.
                                  1. Безошибочные вычисления.
                                  2. Устойчивые к ошибкам вычисления.

                                  Без ошибочные вычисления.
                                  Для предотвращения переполнения используют длинных числа. Вместо десятичный дробей используют рациональных числа.
                                  В базах данных для финансовых вычислений все исчисления идут с 10 числами без конвертации в двоичные.

                                  Стив Макконел даёт эту тему тоже в сколь.
                                  Хотя общие рекомендации такие.
                                  1. Проверка входных и выходных параметров функции.
                                  2. Выделения памяти в общем коде и передачу обработчику уже выделенного диапазона памяти.
                                  3. Сообщения результата о ошибке ниже следующему обработчику для принятия решения. Лично мне результат ошибки нравиться передавать через return, а не вызывать исключение.
                                  Сообщение отредактировано: Pavia -
                                    Цитата simsergey @
                                    Цитата Eric-S @
                                    Насколько я знаю, эта структура, может изменятся.
                                    Я так не думаю :)

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

                                    Цитата simsergey @
                                    double в с++ использует двоичное основание.

                                    Конечно же. Ведь компьютер бинарный. Моё удивление происходило из того, что я , как-то не подумал о столь очевидном факте. Точнее, даже и не задумывался.

                                    Цитата simsergey @
                                    Если я Вас не так понял, мб переформулируете, или другой приведете пример, что же должна делать функция.. :)

                                    Отдельный момент, который всплыл при обсуждении, вы поняли правильно. И ваш вариант со структурой, мне гораздо удобнее, чем функция frexp().

                                    А конкретная функция, должна возвращать число разрядов, которые поместятся в мантиссу без усечения. Если мантисса точностью 52 бита, то в двоичной системе, это 52 разряда. Но в 16-ричной это 13 разрядов. А функция должна вернуть число разрядов мантиссы, для системы счисления, с основанием b.
                                      Цитата Eric-S @
                                      Насколько я знаю, эта структура, может изменятся. Есть даже функции для изменения точности.

                                      Структура может изменяться. Но на самом деле есть стандарт IEEE-754 который и был принят для того чтобы числа не изменялись и на разных архитектура имели одинаковый формат.

                                      Что касается функции изменения точности, так она только зануляет лишние биты из числ в формате IEEE-754. Так что ей пользоваться не стоит. Вообщем она устаревшая. И такой было чуть ли не во время создания Си.
                                        Цитата Pavia @
                                        Числа с плавающей точкой состоят из мантиссы и экспоненты.

                                        Ага, я это уже давно знаю. Выше, даже приведена структура представления в памяти.

                                        Цитата Pavia @
                                        И ещё бывают децентрализованные и нормализованные.

                                        Об этом только слышал. Что за зверь, не представляю.

                                        Цитата Pavia @
                                        Проблема в том что перевод чисел из одной системы счисления в другую идут с ошибками округления. Поэтому тут надо будет ещё аккуратно.

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

                                        Цитата Pavia @
                                        А ещё числа бывают двоичные и десятичные. Десятичные конечно редкость.

                                        Шутите? Угу... Я так и подумал! Знаем, конечно же, и постоянно пользуемся. двоичная и шестнадцатеричная для компа, десятичная для денег, 12 и 24 для часов, 7 ричная для дней недели... И с основанием n, для прикола.

                                        Цитата Pavia @
                                        Формат вывода чисел бывает с фиксированной точкой бывает научный (-d.ddd...E+ddd...)

                                        Угу. Знаемс тоже.
                                        Кстати, давно мучит вопрос, а как в экспоненциальной записи, оформить 16-ричное число? Или научная исключительно для 10-ричной?
                                        Это, если конечно же не использовать специальный значок юникода, а писать латинскую e.


                                        Цитата Pavia @
                                        Мантиса.
                                        Точность мантисы. Точность можно вычислить
                                        http://en.wikipedia.org/wiki/Machine_epsil...n_using_C.2B.2B
                                        Но гораздо проще воспользоваться константой.
                                        В Си есть библиотека констант.
                                        std::numeric_limits
                                        Но так как константу нельзя записать числами из за погрешности при переводи из одной системы счисления(СС) в другую СС.
                                        Поэтому машинную точность определяют через функцию power
                                        EpsSingle=power(2,-24);
                                        EpsDouble=power(2,-53);

                                        Опс... Это интересно... Так, побегу читать.
                                          Цитата Eric-S @
                                          Это, если конечно же не использовать специальный значок юникода, а писать латинскую e.

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

                                          Добавлено
                                          Цитата Eric-S @
                                          Шутите? Угу... Я так и подумал! Знаем, конечно же, и постоянно пользуемся. двоичная и шестнадцатеричная для компа, десятичная для денег, 12 и 24 для часов, 7 ричная для дней недели... И с основанием n, для прикола.

                                          В VAX компьютерах была десятичная арифметика реализована прямо в процессоре.
                                            О! Кажись нашел интересненькое. с std::numeric_limits я уже знаком, но там чего-то не то. Особенно у старого vs 2010.
                                            А вот константа DBL_MANT_DIG возвращает размер мантиссы, для типа long double. Если я конечно правильно понял. И это число, у меня 53. Ха-эм. Ладно, вычтем битик, на знак.

                                            Ладненько, теперь надо подумать, как его пересчитать для нужной системы счисления. Для 2-ичной, я разделил на 1, для 16 ричной, я разделил на 4.

                                            Но забавно, для 10, я тоже должен разделить на 4 и получить 13. Тогда как точно знаю, что у меня влазит 16 разрядов.
                                            Сообщение отредактировано: Eric-S -
                                              Цитата Eric-S @
                                              Но забавно, для 10, я тоже должен разделить на 4 и получить 13. Тогда как точно знаю, что у меня влазит 16 разрядов.

                                              Не делить. Я же привел пример считаешь через логарифмы а потом округляешь.
                                              На само деле все 17 разрядов.
                                                Цитата Pavia @
                                                Поэтому машинную точность определяют через функцию power
                                                EpsSingle=power(2,-24);
                                                EpsDouble=power(2,-53);

                                                ...

                                                Пересчёт констант из одной СС в другую.
                                                Константы легко пересчитать для разной СС.
                                                2^13=10^x
                                                log_10(2^13)=x
                                                Или x=log(2^13)/log(10)

                                                Верно. Я же побежал проверять и не дочитал. Но, ха-эм... с функциями непонятки, кто из них кто?

                                                Да и математику, давно уж забыл. Сейчас со скрипом вспоминал, что вообще такое логарифм. А уж какими функциями возводить число в степень или искать логарифм, никогда и не ведал.

                                                Значит power() это возведение a, в степень b?
                                                А log() это логарифм... Упс, а у него один параметр?
                                                Не, надо лезть в справочник. Не знал не знал и забыл.
                                                  А разве порядок не выясняется через (int)(double >> 52)? (сейчас не проверю)

                                                  С мантиссой в моей Double как Integer разобрались...
                                                    Eric-S
                                                    Цитата Eric-S @
                                                    Значит power() это возведение a, в степень b?
                                                    А log() это логарифм... Упс, а у него один параметр?

                                                    power возведение в степень. Всё верно.
                                                    Логарифм да.
                                                    Цитата Eric-S @
                                                    Не, надо лезть в справочник. Не знал не знал и забыл.

                                                    Также уже забыл.
                                                    Насколько помню log - логарифм по основанию 10, ln - натуральный логарифм, другими словами логарифм по основанию e=2.78..
                                                    По поводу логарифма по произвольному основанию надо посмотреть справку в модуле math должно быть что-то.
                                                    Но можно реализовать и самому через log или ln или через логарифм с любым основанием.
                                                    log(x)/log(b) где b основание.
                                                    ln(x)/ln(b) где b основание.
                                                      Pavia, благодарю! у меня получилось.
                                                        Цитата Pavia @
                                                        Но можно реализовать и самому через log или ln или через логарифм с любым основанием.
                                                        log(x)/log(b) где b основание.
                                                        ln(x)/ln(b) где b основание.

                                                        Круто. Это уже выходит за рамки моих знаний. Но оно работает. Спасибо.

                                                        Цитата Pavia @
                                                        На самом деле все 17 разрядов.

                                                        Ха-эм. На практике у меня 16. Если ставлю 17, то начинаются жуткие проблемы с округлением. Например в последнем разряде, появляются артефакты.

                                                        А вот написанная функция говорит, что 15. Я правда ткнул мантиссу 52 бита.

                                                        ExpandedWrap disabled
                                                          #include <cmath>
                                                          #include <iostream>
                                                           
                                                          int main()
                                                          {
                                                           
                                                          // основание системы счисления
                                                          int b = 10;
                                                           
                                                          // размер мантиссы
                                                          auto m = std::pow( 2.0, LDBL_MANT_DIG - 1 );
                                                           
                                                          // число разрядов
                                                          auto d = std::log( m ) / std::log( static_cast< long double >( b ) );
                                                           
                                                          std::cout << "digits: " << d << std::endl;
                                                           
                                                          return 0;
                                                          }


                                                        Добавлено
                                                        Вот получившаяся функция.
                                                        ExpandedWrap disabled
                                                          // возвращает максимальное число разрядов для указанной системы счисления
                                                          std::size_t get_digits_count( unsigned int b )
                                                          {
                                                           
                                                          // число разрядов
                                                          return static_cast< std::size_t >( std::log( std::pow( 2.0, LDBL_MANT_DIG - 1 ) ) / std::log( static_cast< long double >( b ) ) );
                                                          }


                                                        Это альтернативное решение, не касающееся сабжа. А если вернутся к переполнению, то можно проверять, сравнивая число с максимально допустимым значением std::pow( 2.0, LDBL_MANT_DIG - 1 ).


                                                        Всем спасибо. Тему закрываю.
                                                        Сообщение отредактировано: Eric-S -
                                                          Цитата Pavia @
                                                          Насколько помню log - логарифм по основанию 10, ln - натуральный логарифм, другими словами логарифм по основанию e=2.78..
                                                          У вас смесь из математики и программирования. Дела таковы:
                                                          Математика: ln-натуральный, log-общий
                                                          Программирование: log-натуральный, ln-нет такого (букв мало?)
                                                            Цитата Славян @
                                                            Цитата Pavia @
                                                            Насколько помню log - логарифм по основанию 10, ln - натуральный логарифм, другими словами логарифм по основанию e=2.78..
                                                            У вас смесь из математики и программирования. Дела таковы:
                                                            Математика: ln-натуральный, log-общий
                                                            Программирование: log-натуральный, ln-нет такого (букв мало?)

                                                            С какой-то радости, математику смешивают с программированием? Это уже давно, две разные науки.
                                                            Лично мне, функциями понятнее. Даже если я тех функций не знаю. Но по контексту можно догадатся. А вот матзначки, вынесут мой несчастный мозг...
                                                              Цитата Eric-S @
                                                              С какой-то радости, математику смешивают с программированием? Это уже давно, две разные науки.
                                                              Это сильно завязанные науки. Вот log знают все, это общее, это даже начало слова. Но математикам лень использовать общий логарифм, потому они и ввели ln-для натурального (мега-сокращение,да!?), а lg-для десятичного. А вот программистам две буквы - ну уж слижком коротко (в ассемблере и то - редкость), а логарифм нужен. Потому и решили, что пусть log-натуральный, а log10 - десятичный.
                                                                Программистам букав мало. Две буквы, это всего pow( 26, 2 ), а три буквы уже pow( 26, 3 ). Хотя последнего тоже мало. Не даром ведь придумали всякие namespace.
                                                                И очень жаль, что математики, по прежнему используют всякие ln lg и подобное. Треба водить единый стандарт.
                                                                  Славян
                                                                  Цитата Славян @
                                                                  Математика: ln-натуральный, log-общий
                                                                  Программирование: log-натуральный, ln-нет такого (букв мало?)

                                                                  В разных языках программирования по разному поэтому могу путать.
                                                                    Цитата Pavia @
                                                                    И ещё бывают децентрализованные
                                                                    "Децентрализованные" - это что-то доселе невиданное. Денормализованные.
                                                                      Цитата trainer @
                                                                      "Децентрализованные" - это что-то доселе невиданное. Денормализованные.

                                                                      Да. Авто проверка языка подводит. Без неё у меня в каждом слове по ошибке.
                                                                        Вообще-то Стандарт языка определяет систему счисления для представления только целых типов данных. Что касается типов с плавающей точкой, то он рекомендует, но не обязывает, следовать стандарту IEC-559 (он же IEEE-754), а там обязывания какой-то конкретной системы счисления нет. В интерфейсах <cfloat> (float.h) и <limits> определяются константы FLT_RADIX и std::numeric_limits<>::radix. Вот их и надо пользовать, если очень интересно. Последний, согласно Стандарту, для целочисленных типов должен возвращать 2.

                                                                        Добавлено
                                                                        Цитата Eric-S @
                                                                        Кстати, давно мучит вопрос, а как в экспоненциальной записи, оформить 16-ричное число? Или научная исключительно для 10-ричной?
                                                                        Это, если конечно же не использовать специальный значок юникода, а писать латинскую e.
                                                                        Порядок числа обязательно должен указываться со знаком, поэтому E, определяющая экспоненту однозначно отделяется от E, являющейся частью мантиссы, наличием после себя + или -.

                                                                        Добавлено
                                                                        Цитата Pavia @
                                                                        В VAX компьютерах была десятичная арифметика реализована прямо в процессоре.
                                                                        В НИИ системотехники, где я имел удовольствие одно время работать, разрабатывался на заказ троичный FPU.

                                                                        Добавлено
                                                                        Цитата Eric-S @
                                                                        А вот константа DBL_MANT_DIG возвращает размер мантиссы, для типа long double. Если я конечно правильно понял. И это число, у меня 53. Ха-эм. Ладно, вычтем битик, на знак.
                                                                        В соответствии с IEEE один самый старший бит в 32-х и 64-битных форматах является неявным. Его значение всегда 1 для нормализованных, бесконечностей и нечисел и всегда 0 для денормализованных и нулей. Первые отличаются от вторых смещённым порядком. Порядки 0 и максимальный зарезервированы для спец.форматов, от 1 до макс-1 - для нормализованных.
                                                                          Eric-S, я вспомнил, что немного забыл раньше :)
                                                                          На самом деле, в double число хранится не в явном виде мантисы и порядка (экспоненты), в связи с неявной единицей.
                                                                          Для получения реального значения мантисы, нужно сдвинуть вправо мантису с занесением в первый разряд единицы.
                                                                          И правкой порядка. Порядок вроде бы хранится в "дополнительном коде".
                                                                          Если Вам интересен этот вариант, можно развить ))

                                                                          Напомнили:
                                                                          Цитата Qraizer @
                                                                          Добавлено 40 минут назад
                                                                          Цитата (Eric-S @ Сегодня, 12:54)
                                                                          А вот константа DBL_MANT_DIG возвращает размер мантиссы, для типа long double. Если я конечно правильно понял. И это число, у меня 53. Ха-эм. Ладно, вычтем битик, на знак.
                                                                          В соответствии с IEEE один самый старший бит в 32-х и 64-битных форматах является неявным. Его значение всегда 1 для нормализованных, бесконечностей и нечисел и всегда 0 для денормализованных и нулей. Первые отличаются от вторых смещённым порядком. Порядки 0 и максимальный зарезервированы для спец.форматов, от 1 до макс-1 - для нормализованных.
                                                                            Да ладно. Меня уже всё устраивает. С двоичным представлением, возится лень. Оно мне сейчас не требуется. Но буду иметь в виду.

                                                                            Разрядность я получил. Как сделать проверку узнал. По ходу выяснилось, что она не нужна. Ну да ладно.

                                                                            Система счисления, у меня задаётся опционально. Какая она там по дефолту, уже не важно. Мой класс делает любую от 2-ричной, до 36-ричной включительно.

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

                                                                            Добавлено
                                                                            Цитата Qraizer @
                                                                            Порядок числа обязательно должен указываться со знаком, поэтому E, определяющая экспоненту однозначно отделяется от E, являющейся частью мантиссы, наличием после себя + или -.

                                                                            О! Значит знак обязателен. Это хорошо. Я так и сделал.
                                                                            А нолик обязателен или нет? А то я его выбросил.
                                                                            1.2e+23 или 1.2e+023
                                                                              Успехов в коде :)

                                                                              Цитата Eric-S @
                                                                              С двоичным представлением, возится лень.
                                                                              Не забывайте про производительность. Хотя, железо походу не может обеспечить обработку разных систем счисления напрямую.. Интел подкачал :D
                                                                                Цитата Qraizer @
                                                                                обязывания какой-то конкретной системы счисления нет. В интерфейсах <cfloat> (float.h) и <limits> определяются константы FLT_RADIX и std::numeric_limits<>::radix. Вот их и надо пользовать, если очень интересно. Последний, согласно Стандарту, для целочисленных типов должен возвращать 2.

                                                                                о! Вот даже как. Это везде, куда я вбивал магические двойки, надо подставлять сию константу?

                                                                                Добавлено
                                                                                Цитата simsergey @
                                                                                Успехов в коде :)

                                                                                Спасибо. Вам того же!

                                                                                Добавлено
                                                                                Цитата simsergey @
                                                                                Не забывайте про производительность. Хотя, железо походу не может обеспечить обработку разных систем счисления напрямую..

                                                                                О производительности помню. Хотя, частенько оптимизации откладываю. Особенно в плюшках. Нет уж, прокачать обычной алгеброй, куда надёжнее. Особенно когда есть желание поизвращатся. А стандартный функционал отсутствует вообще.

                                                                                Добавлено
                                                                                Цитата Qraizer @
                                                                                соответствии с IEEE один самый старший бит в 32-х и 64-битных форматах является неявным. Его значение всегда 1 для нормализованных, бесконечностей и нечисел и всегда 0 для денормализованных и нулей. Первые отличаются от вторых смещённым порядком. Порядки 0 и максимальный зарезервированы для спец.форматов, от 1 до макс-1 - для нормализованных.

                                                                                Ха-эм. Так мне что, два бита отнимать? Сколько там реально используется для хранения числа?
                                                                                  Цитата Eric-S @
                                                                                  Так мне что, два бита отнимать? Сколько там реально используется для хранения числа?
                                                                                  А почему 2?
                                                                                  В Double реально хранится 52 бита мантисы. При арифметических операциях процессор при рассчетах подразумевает, что их 53, дорисовывая слева 1.
                                                                                  К примеру, в памяти 010010101010101, а цп эту запись интерпретирует как 1010010101010101. Но в памяти хранится 52 бита.
                                                                                  Почему 2 отнимать? Знак? Так Double занимает 64 бита, из которых: знак числа, порядок и мантиса. Знака мантисы - нет, есть "знак числа", а знак порядка записан в 11 битах порядка, и т.к. порядок представлен в ДК (дополнительный код), то знак порядка хранится там же (не совсем отдельным битом).

                                                                                  Double Wiki

                                                                                  Для справки, есть еще тип Float, работает по тому же принципу, но предоставляет меньшую точность. Взамен - занимает меньше памяти.
                                                                                  Мантиса: 23 бита.
                                                                                  Порядок: 8 бит.
                                                                                  Знак: 1 бит.
                                                                                  Сообщение отредактировано: simsergey -
                                                                                    В десятичных константах в формате с плавающей точкой знак + после буквы e можно не писать.

                                                                                    IEEE-754 задаёт 4 представления с разным количеством бит 16 / 32 (float) / 54 (double) / 128. В C и C++ используются два средних. В качестве long double используется 10-байтовое временное представление процессоров i387. Хотя некоторые компиляторы используют 128-битный формат IEEE
                                                                                      Цитата amk @
                                                                                      В качестве long double используется 10-байтовое временное представление процессоров i387. Хотя некоторые компиляторы используют 128-битный формат IEEE
                                                                                      А расскажите поподробнее, а?
                                                                                        Начиная отсюда: http://ru.wikipedia.org/wiki/IEEE_754-2008 и далее по ссылкам в тексте.

                                                                                        Добавлено
                                                                                        ЕМНИП, в первоначальной версии этого стандарта таки фигурировали 80-битные числа.
                                                                                          Угу. Стандарт, конечно хорошо. Но я, в конкретном компилере имею float и double. Причом есть long double который sizeof(long double) 64.
                                                                                          А где половинная и учетверённая точность?

                                                                                          Добавлено
                                                                                          Цитата amk @
                                                                                          В десятичных константах в формате с плавающей точкой знак + после буквы e можно не писать.

                                                                                          Ну, это меня интересовало, как раз для не десятичной записи. Например шестнадцатиричной, в которой буква "e" имеет значение 14. И в этом случае, без плюсика не обойтись. "0XFFe+10"
                                                                                          Кстати, а в какой системе счисления нужно записывать порядок? В той же или десятичной?

                                                                                          Добавлено
                                                                                          Цитата simsergey @
                                                                                          А почему 2?

                                                                                          Так я и спрашивал, нужно ли что-то отнимать и если да, то сколько.
                                                                                          С форматом уже разобрался, спасибо!

                                                                                          А вот прогулявшись по описанием стандартов, так и не понял, как записывать 0, NaN и +q и -q? Я так понял, это денормализованные значения?
                                                                                            Цитата trainer @
                                                                                            ЕМНИП, в первоначальной версии этого стандарта таки фигурировали 80-битные числа.
                                                                                            Нет, частью стандарта IEEE-754 это представление никогда не было. Оно не соответствует обобщённому формату. Это фсего лишь внутреннее представление чисел в арифметическом сопроцессоре i8087. Более того, судя по ранней документации на i8087 даже инженеры Intel изначально не предполагали использовать его в качестве самостоятельного типа данных (хотя для возможности сохранения состояния процессора предусмотрели возможность его чтения/записи). Просто процессор должен был иметь возможность работать не только с плавающими числами, но и с целыми - 16/32/64 бит - и десятичными - до 20 цифр (включая знак).

                                                                                            Добавлено
                                                                                            Да, словосочетание "переполнение мантиссы" для чисел с плавающей точкой не совсем верно. В этом случае мантисса просто сдвигается на один разряд вправо (больше не надо) и к порядку добавляется единица. И вот тут может произойти переполнение порядка. Процессоры с полной реализацией арифметики IEEE выдают результат равный ±∞ (все разряды характеристики ?— единицы, все видимые разряды мантиссы — нули). Кроме того сопроцессор может сформировать при этом прерывание. Те процессоры, которые не поддерживают арифметику на таком уровне просто генерируют прерывание.
                                                                                              Цитата amk @
                                                                                              Да, словосочетание "переполнение мантиссы" для чисел с плавающей точкой не совсем верно. В этом случае мантисса просто сдвигается на один разряд вправо (больше не надо) и к порядку добавляется единица.


                                                                                              На счёт некоректности фразы - согласен.
                                                                                              Но меня интересовал именно этот момент, когда происходит сдвиг, при заполненной мантиссе. И младшие разряды в мантиссе теряются.

                                                                                              Понятно, что порядок растёт всё время. Но в начале, мантисса просто увеличивает значение, а потом происходит её переполнение, которое нейтрализуется сдвигом мантиссы и изменением порядка.

                                                                                              А на счёт словосочетания, тем более в заголовке. Предложите корректный и я поправлю.

                                                                                              Добавлено
                                                                                              И ещё ссылочку. Я тут уже спрашивал про денормализованные числа. Всё же, ради интереса, решил разобратся. И нашел тут кучу полезного. http://softelectro.ru/ieee754.html
                                                                                              Сообщение отредактировано: Eric-S -
                                                                                                Цитата Eric-S @
                                                                                                Понятно, что порядок растёт всё время. Но в начале, мантисса просто увеличивает значение, а потом происходит её переполнение, которое нейтрализуется сдвигом мантиссы и изменением порядка.

                                                                                                Это справедливо только для частных случаев, когда мантиссы операндов (слагаемых или множителей) имеют ограниченное число двоичных знаков - для целых чисел и конечных двоичных дробей (целых чисел, деленных на некоторую степень 2). Но подавляющее число десятичных дробей, представляются бесконечными двоичными дробями, и соотв-но, 1) занимают все разряды мантиссы, 2) уже сами по себе представляются неточно (с округлением до младшего разряда мантиссы), 3) могут давать "переполнение мантиссы" уже при первом же сложении\умножении.
                                                                                                Поэтому, несмотря на то, что для вещественных чисел в x87 предусмотрена генерация исключения Inexact-Result в случае любого неточного представления мантиссы, на практике этим практически не пользуются - если только в каких-то особых случаях, типа твоих "экспериментальных исследований" :) См. _controlfp, флаг _EM_INEXACT
                                                                                                  Цитата Eric-S @
                                                                                                  И ещё ссылочку.
                                                                                                  Хорошее описание, хотя формат неплохо описан и википедии, в русской описаны двоичные форматы, в английской кроме этого есть описания двоично-кодированных десятичных, да и вообще там подробнее.
                                                                                                    Цитата amk @
                                                                                                    Хорошее описание

                                                                                                    На википедии есть. Я же от туда и ссылочку взял. Но мне понравилась живость и понятность описания. Тем более на русском.
                                                                                                    А может быть, она стала уже понятной, после нашего общения, в сей теме. В прочем, нашлось и кое-что новенькое.
                                                                                                    0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                                                                                    0 пользователей:


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