сконвертировать unsigned int в float без потери точности
От: B0FEE664  
Дата: 02.12.15 15:43
Оценка:
Верен ли такой assert:
float CastToFloat(unsigned int n)
{
    assert(n <= [](){ unsigned int nMax = 0; for(int i = 0; i < FLT_DIG; i++) nMax = nMax * 10 + 9; return nMax;}());
    return static_cast<float>(n);
}

?
И если да, то может уже существует в стандартных инклюдах константа, значение которой равно вычисляемому nMax?
И каждый день — без права на ошибку...
Re: сконвертировать unsigned int в float без потери точности
От: watchmaker  
Дата: 02.12.15 15:53
Оценка: +1
Здравствуйте, B0FEE664, Вы писали:


BFE>Верен ли такой assert:

Нет, конечно.
Например из-за того, что в IEEE754 для числел отдельно хранится мантисса и экспонента. Твоя проверка зависит от изменения экспоненты (читай от умножения n на 2), а точность представления во float — нет (разумеется, до переполнения экспоненты, но это невозможно для unsigned, так как FLT_MAX значительно больше).

А чем тебя такая простая проверка не устраивает?
n == (unsigned)(float)n



Ну а если тебя теория интересует, то критерий представимости unsigned в IEEE754 float будет примерно таким:
Если положить n = t * 2k, где t нечётное или 0, то n будет представим только если t < 224.
Отредактировано 02.12.2015 16:06 watchmaker . Предыдущая версия .
Re: сконвертировать unsigned int в float без потери точности
От: BulatZiganshin  
Дата: 02.12.15 16:02
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>float CastToFloat(unsigned int n)


оба типа (в msvc) — 32-битные
Люди, я люблю вас! Будьте бдительны!!!
Re: сконвертировать unsigned int в float без потери точности
От: uzhas Ниоткуда  
Дата: 02.12.15 16:07
Оценка: 2 (1) +1
Здравствуйте, B0FEE664, Вы писали:


BFE>Верен ли такой assert:


Если ты хочешь найти непрерывный интервал [0, nMax] такой, что любое число из этого интервала точно представляется в формате float, то вроде верно. Но следует учитывать, что есть другие числа вне этого интервала, которые тоже точно представляются в формате float.

BFE>И если да, то может уже существует в стандартных инклюдах константа, значение которой равно вычисляемому nMax?

10 ^ FLT_DIG — 1 ? Как константу не встречал, можно самому что-нибудь компайл-тайм навычислять.
Re[2]: сконвертировать unsigned int в float без потери точности
От: B0FEE664  
Дата: 02.12.15 16:32
Оценка:
Здравствуйте, watchmaker, Вы писали:

BFE>>Верен ли такой assert:

W>Нет, конечно.
W>Например из-за того, что в IEEE754 для числел отдельно хранится мантисса и экспонента. Твоя проверка зависит от изменения экспоненты (читай от умножения n на 2), а точность представления во float — нет (разумеется, до переполнения экспоненты, но это невозможно для unsigned, так как FLT_MAX значительно больше).

Как правильно понял uzhas, я хочу проверить, что моё число лежит в "непрерывном" интервале целых чисел [0, nMax] таком, что любое целое из этого интервала точно представимо в float, поэтому эта проверка меня не устраивает:
W>А чем тебя такая простая проверка не устраивает?
n == (unsigned)(float)n


Из вашего комментария я понимаю, что этот интервал определяется размером мантиссы, т.е. assert должен быть таким:

assert(n <= (1U << FLT_MANT_DIG) — 1);

Верно?
И каждый день — без права на ошибку...
Re[3]: сконвертировать unsigned int в float без потери точно
От: watchmaker  
Дата: 02.12.15 16:52
Оценка: 4 (1)
Здравствуйте, B0FEE664, Вы писали:


BFE>Из вашего комментария я понимаю, что этот интервал определяется размером мантиссы, т.е. assert должен быть таким:


BFE>assert(n <= (1U << FLT_MANT_DIG) — 1);


BFE>Верно?


Нет, не учтено разложение на произведение чётного и нечётного чисел. Так если FLT_MANT_DIG = 24 и FLT_RADIX = 2, то твоё условие сводится к assert(n ≤ 16777215). То есть число 16777216 не удовлетворяет ему, хотя оно и точно представимо в IEEE754-float, и непосредственно прилегает к отрезку [0, 16777215] — то есть этот отрезок на самом деле может быть увеличен.

В остальном практически всё верно.

Но формально это не переносимо. FLT_RADIX не всегда равен 2. А в мантиссе не всегда присутствует неявный старший бит.
Если же исправить ошибку с числом 16777216, и добавить проверку
static_assert(std::numeric_limits<float>::is_iec559, "IEEE 754 floating point");
то будет вполне надёжно.
Отредактировано 02.12.2015 16:56 watchmaker . Предыдущая версия .
Re[4]: сконвертировать unsigned int в float без потери точно
От: B0FEE664  
Дата: 02.12.15 17:30
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>А в мантиссе не всегда присутствует неявный старший бит.

А это о чём говорит?
И каждый день — без права на ошибку...
Re[5]: сконвертировать unsigned int в float без потери точно
От: watchmaker  
Дата: 02.12.15 17:51
Оценка: 1 (1)
Здравствуйте, B0FEE664, Вы писали:

BFE>Здравствуйте, watchmaker, Вы писали:


W>>А в мантиссе не всегда присутствует неявный старший бит.

BFE>А это о чём говорит?

В разных реализациях хранения чисел с плавающей точкой может использоваться или нет hidden bit (он же implicit bit). При прочих равных без него арифметика может работать быстрее, но с ним числа при хранении занимают меньше места (ровно на один бит, очевидно). В ieee754 используется неявный старший бит, который расположен ровно перед запятой. В других реализациях, он может либо вовсе отсутствовать, либо присутствовать, но стоять на другом месте (вот, например, обзор), .
Но если ты не собираешься запускать свою программу на таких архитектурах прямо сейчас (в чём я сильно уверен), то ими можно не заморачиваться — максимум просто оставляешь в коде static_assert, который не даст программе молча скомпилироваться, если вдруг числа с плавающей точкой внутри окажутся по другому устроены.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.