Машинный максимум double на С++

Всем доброго вечера. У меня есть задача - определить максимально возможное значение, которое может храниться в типе double, но использовать библиотеку limits при решении нельзя. Решаю задачу с помощью возведения двойки в степень, при котором значение выходит за пределы типа. Нагляднее покажу в коде:

    double infmax_d = 2.0;
    double almostinf_d = 1.0, infinity_d = 1.0;
    int counter_max_d = 0, counter_notmax_d = -1;

    while (infmax_d > almostinf_d) {
        almostinf_d = infmax_d;
        infmax_d = infmax_d * 2.0;
        counter_max_d++;
        counter_notmax_d++;

    }

    //cout << counter_notmax_d << endl;

    for (int t = 0; t < counter_notmax_d; t++) {
        infinity_d = infinity_d * 2.0;
    }

    cout << "Max value for double type: " << infinity_d << endl;

Вывод программы в данном случае:

Max value for double type: 8.98847e+307

Это значение в два раза меньше истинного. При умножении на два сразу происходит вывод inf. Если отнять от infinity_d 0.5 и умножить на 2, результат тот же. Но если отнимать 5e300, то получается найти ближайшее к нужному число. Как можно модифицировать код, чтобы добиться нужного результата?


Ответы (1 шт):

Автор решения: tr1ang1e

Как уже заметил @gbg в комментарии, в соответствии со стандартом, единственный корректный способ узнать максимально возможное значение - причем не только типа double, но и любого арифметического типа - использовать ту самую библиотеку.

Можете открыть последний черновик N4868 последнего стандарта и найти там в § 6.8.2 описания для всех арифметических типов. В частности, в пункте 12 сообщается о числах с плавающей точкой.

  1. ... The value representation of floating-point types is implementation-defined. ... Specializations of the standard library template std::numeric_limits shall specify the maximum and minimum values of each arithmetic type for an implementation.

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

  • 0 бит = знак числа
  • 1 - 11 биты = смещенный порядок
  • 12 - 63 биты = абсолютная часть мантиссы

Я воспользовался библиотекой limits, чтобы получить максимальное double , а затем посмотрел, как оно представлено в памяти.

double d = numeric_limits<double>::max( );    // 1.79769e+308

//    0   11111111110   11...11               // представление в памяти  
//    ^   ^         ^   ^     ^ 
//    0   1        11   12   63

Со знаковым битом все понятно, если бы там была единица, мы бы получили отрицательное число. Но, как видите, и 11ый бит тоже выставлен в 0. Значит, прямолинейное выставление всех битов в единички не сработает. Если Вы все же попробуете, то вывод, скорее всего, окажется nan то есть "not a number".

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

→ Ссылка