BFE>Верен ли такой assert:
Нет, конечно.
Например из-за того, что в IEEE754 для числел отдельно хранится мантисса и экспонента. Твоя проверка зависит от изменения экспоненты (читай от умножения n на 2), а точность представления во float — нет (разумеется, до переполнения экспоненты, но это невозможно для unsigned, так как FLT_MAX значительно больше).
А чем тебя такая простая проверка не устраивает?
n == (unsigned)(float)n
Ну а если тебя теория интересует, то критерий представимости unsigned в IEEE754 float будет примерно таким:
Если положить n = t * 2k, где t нечётное или 0, то n будет представим только если t < 224.
Если ты хочешь найти непрерывный интервал [0, nMax] такой, что любое число из этого интервала точно представляется в формате float, то вроде верно. Но следует учитывать, что есть другие числа вне этого интервала, которые тоже точно представляются в формате float.
BFE>И если да, то может уже существует в стандартных инклюдах константа, значение которой равно вычисляемому nMax?
10 ^ FLT_DIG — 1 ? Как константу не встречал, можно самому что-нибудь компайл-тайм навычислять.
Re[2]: сконвертировать unsigned int в float без потери точности
Здравствуйте, 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 без потери точно
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, и добавить проверку
Здравствуйте, B0FEE664, Вы писали:
BFE>Здравствуйте, watchmaker, Вы писали:
W>>А в мантиссе не всегда присутствует неявный старший бит. BFE>А это о чём говорит?
В разных реализациях хранения чисел с плавающей точкой может использоваться или нет hidden bit (он же implicit bit). При прочих равных без него арифметика может работать быстрее, но с ним числа при хранении занимают меньше места (ровно на один бит, очевидно). В ieee754 используется неявный старший бит, который расположен ровно перед запятой. В других реализациях, он может либо вовсе отсутствовать, либо присутствовать, но стоять на другом месте (вот, например, обзор), .
Но если ты не собираешься запускать свою программу на таких архитектурах прямо сейчас (в чём я сильно уверен), то ими можно не заморачиваться — максимум просто оставляешь в коде static_assert, который не даст программе молча скомпилироваться, если вдруг числа с плавающей точкой внутри окажутся по другому устроены.