Подтвердить что ты не робот

Минимальное положительное значение поплавка прямым вычислением отличается от FLT_MIN в <float.h>

Я хочу напрямую вычислить минимальное значение типа float, и вот мой алгоритм (предположим, что кодирование числа с плавающей запятой подтверждает стандарт IEEE 754):

#include <math.h>
#include <limits.h>
#include <float.h>
#include <stdio.h>

float float_min()
{
    int exp_bit = CHAR_BIT * sizeof(float) - FLT_MANT_DIG;
    float exp = 2 - pow(2, exp_bit - 1);

    float m = pow(2, -(FLT_MANT_DIG - 1));

    return m * pow(2, exp);
}

int main()
{
    printf("%g\n", float_min());
}

Выходной сигнал 1.4013e-45. Однако, я считаю, что значение FLT_MIN в C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\float.h равно 1.175494351e-38F. Кто не прав?

4b9b3361

Ответ 1

Несмотря на то, что этот вопрос задавали и отвечали несколько раз раньше, я не вижу ответа, который на самом деле правильный. Ключ в том, что FLT_MIN - наименьшее нормализованное значение, которое может быть представлено. В прежние времена это было важно. Затем появилась Intel и представила значения subnormal, которые уменьшают точность, чтобы представлять значения ближе к 0. Поднормальные значения - это значения с минимальным показателем и дроби, чьи старшие биты - все нули. Из этого следует, что наименьшее ненулевое субнормальное значение имеет дробь, что все нули, за исключением младшего бита, который равен 1. Это наименьшее значение, которое может быть представлено, но когда вы там внизу, меняете немного здесь и там изменяется большое значение, поэтому эти вещи нужно использовать с большой осторожностью.

ИЗМЕНИТЬ, чтобы уточнить "нормализацию":

Предположим, что мы пишем десятичные значения: 6.02x10 ^ 23,.602 * 10 ^ 24, 60.2 * 10 ^ 22. Все они имеют одинаковое значение, но они явно выглядят по-разному. Поэтому давайте ввести правило для записи десятичных значений: каждое значение должно иметь ровно одну ненулевую цифру слева от десятичной точки. Таким образом, "нормализованная" форма этого значения равна 6.02x10 ^ 23, и если у нас есть значение, записанное в ненормированной форме, мы можем переместить десятичную точку и настроить экспонента для сохранения значения и поместить его в нормализованную форму.

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

Когда мы записываем десятичные значения, которые действительно близки к 0, это не проблема: мы можем сделать показатель меньшим, чем нам нужно, поэтому мы можем писать числа, такие как 6.02 * 10 ^ -16384. С значениями с плавающей запятой мы не можем этого сделать: есть минимальный показатель, который мы не можем опустить ниже. Чтобы разрешить меньшие значения, требования IEEE говорят, что когда показатель экспоненты является наименьшим представимым значением, фракция не должна быть нормализована, то есть она не должна иметь 1 в своем высоком бите. При написании десятичных значений, как и высказывание, мы можем иметь 0 слева от десятичной точки. Поэтому, если наше десятичное правило говорит, что наименьший допустимый показатель составляет -100, наименьшее нормированное значение будет 1,00x10 ^ -100, но меньшее значение может быть представлено как ненормированное: 0.10 * 10 ^ -100, 0.01 * 10 ^ - 100 и т.д.

Теперь добавьте требование к нашим десятичным правилам, что мы можем иметь только три цифры: одну слева от десятичной точки и две вправо. Это подобно фракции с плавающей запятой, в которой оно имеет фиксированное количество цифр. Поэтому для небольших нормальных значений мы имеем три цифры, чтобы играть с: 1.23 * 10 ^ -100. Для меньших значений мы используем начальные нули, а остальные цифры имеют меньшую точность: 0.12 * 10 ^ -100 имеет две цифры, а 0.01 * 10 ^ -100 имеет только 1. Это также как с плавающей точкой субнормальные работы: вы получаете меньше и меньше значимых бит, когда вы становитесь все дальше и дальше ниже минимального нормированного значения, пока не закончите бит, и вы получите 0.

EDIT: чтобы уточнить терминологию, стандарт IEEE-754 ссылался на те значения, которые больше 0 и меньше, чем минимальное нормированное значение как denormals; последняя версия IEEE-754 относится к ним как субнормальные. Они означают одно и то же.

Ответ 2

Ваш результат 1.4013e-45 - это денормальное минимальное положительное значение поплавка, также известное как FLT_TRUE_MIN, которое равно 1.401298464e-45F.

FLT_MIN - нормированное минимальное положительное значение поплавка (1.175494351e-38F)