Поиск наименьшего целого числа, которое не может быть представлено в виде 32-битного числа с плавающей запятой IEEE-754

Возможный дубликат:
Какое первое целое число не может быть точно представлено числом с плавающей запятой IEEE 754?

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

Итак, моя задача — найти наименьшее положительное целое число, которое нельзя представить в виде числа с плавающей запятой IEEE-754 (32 бита). Я знаю, что проверка на равенство для чего-то вроде «5 == 5.00000000001» не удастся, поэтому я подумал, что просто переберу все числа и проверю это следующим образом:

int main(int argc, char **argv)
{
    unsigned int i; /* Loop counter. No need to inizialize here. */

    /* Header output */
    printf("IEEE floating point rounding failure detection\n\n");

    /* Main program processing */
    /* Loop over every integer number */
    for (i = 0;; ++i)
    {
        float result = (float)i;

        /* TODO: Break condition for integer wrapping */

        /* Test integer representation against the IEEE-754 representation */
        if (result != i)
            break; /* Break the loop here */
    }

    /* Result output */
    printf("The smallest integer that can not be precisely represented as IEEE-754"
           " is:\n\t%d", i);


    return 0;
}

Это не удалось. Затем я попытался вычесть целое число «i» из «результата» с плавающей запятой, то есть «i», надеясь получить что-то вроде «0,000000002», которое я мог бы попытаться обнаружить, но это тоже не удалось.

Может ли кто-нибудь указать мне свойство с плавающей запятой, на которое я могу положиться, чтобы получить желаемое условие разрыва?

-------------------- Обновление ниже ---------------

Спасибо за помощь в этом! Здесь я узнал несколько вещей:

  1. Моя первоначальная мысль была действительно правильной и определила результат на машине, на которой она должна была работать (Solaris 10, 32-разрядная), но не работала в моих системах Linux (64-разрядная и 32-разрядная).

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

Спасибо всем!


person LukeN    schedule 08.10.2010    source источник
comment
Как это не удается? Когда я компилирую и выполняю ваш код, на выходе получается 16777217.   -  person Henrik    schedule 08.10.2010
comment
@KennyTM: Черт, а я думал, что умею искать! Извините за дублирование тогда.   -  person LukeN    schedule 08.10.2010
comment
@Henrik: Он просто продолжал возвращаться (INT_MAX -> 0) и никогда не прерывался с результатом.   -  person LukeN    schedule 08.10.2010


Ответы (3)


Проблема в том, что ваш тест на равенство является тестом с плавающей запятой. Сначала переменная i будет преобразована в число с плавающей запятой, и это, конечно же, приведет к такому же числу с плавающей запятой. Преобразуйте float обратно в int, чтобы получить целочисленный тест на равенство:

float result = (float)i;
int truncated = (int)result;
if (truncated != i) break;

Если он начинается с цифр 16, значит, вы нашли правильный вариант. Преобразуйте его в шестнадцатеричный формат и объясните, почему это не помогло получить бонус за оценку.

person Hans Passant    schedule 08.10.2010
comment
Спасибо! Это сработало, и я рад, что моя первоначальная идея оказалась верной :) - person LukeN; 08.10.2010

Я думаю, вы должны рассуждать о представлении плавающих чисел как (база, знак, мантисса, показатель степени)

Вот выдержка из Википедии, которая может дать вам подсказку:

Данный формат включает в себя:

* Finite numbers, which may be either base 2 (binary) or base 10

(десятичный). Каждое конечное число проще всего описать тремя целыми числами: s = знак (ноль или единица), c = мантисса (или «коэффициент»), q = показатель степени. Числовое значение конечного числа равно (−1)s × c × bq, где b — основание (2 или 10). Например, если знак равен 1 (указывающий отрицательное значение), мантиссы равны 12345, показатель степени равен -3, а основание равно 10, то значение числа равно -12,345.

person Luca Martini    schedule 08.10.2010

Это будет FLT_MAX+1. См. float.h.

Изменить: или на самом деле нет. Проверьте функцию modf() в math.h

person Šimon Tóth    schedule 08.10.2010
comment
@Hans Да, определенно есть меньшие числа, которые невозможно представить. - person Šimon Tóth; 08.10.2010
comment
Вместо этого попробуйте (1<<FLT_MANT_DIG)+1. - person R.. GitHub STOP HELPING ICE; 08.10.2010