Это первый раз, когда я решил разобраться с форматом float32 как говорится побитово. И решил что лучше начать разбирательство с написания функции преобразования int в float. Оказывается, числа в диапазоне от -8388607 до +8388607 преобразуются вообще без потери точности. Затем я решил преобразовать 2147483647 чтобы посмотреть погрешность. У меня она получилась гораздо больше чем если преобразовывать аппаратными средствами. Тут я понял что нужно делать правильное округление, а не просто выкидывать девять бит. Но как?
Округление.
Идея была такой: самый значимый из отбрасываемых битов проверяем на 1. Если там единица, то после отбрасывания прибавляем к мантиссе 1 и если возникаем перенос за пределы области мантиссы, то убираем этот перенос, но показатель увеличиваем на 1. После отладки этого кода он таки стал выдавать тот же результат что и аппаратные средства.
Преобразование.
Само преобразование легко мыслить как нормализацию числа если изначально представлять его как разряды после точки и показателем 32. Только перед преобразованием мы отрицательные числа переводим в прямой код. Суть нормализации. Мы сдвигаем число влево пока не избавимся от лидирующих нулей. Попутно уменьшаем показатель. Чтобы не зациклиться мы ноль обрабатываем отдельно (он на выходе дает такой же ноль). Поскольку у нас лидирующий бит почти всегда ноль, нет смысла занимать этот разряд и мы сдвигаем еще раз, а порядок уменяшаем еще на 1. Например, если мы преобразовываем единицу, то мантисса будет ноль, и показатель ноль (мы вычли 32 из 32 и получили ноль). 2 в степени 0 дает нам единицу.
В конце мы упаковываем мантиссу, знак, и показатель смещенный на 127 (как требует формат) и так получаем итоговый float. Перед упаковкой не забываем округлить.