Вы не знак, расширяющий 24 бита в целое число; старшие биты всегда будут равны нулю. Этот код будет работать независимо от того, какой у вас размер int
:
if (i & 0x800000)
i |= ~0xffffff;
Редактировать: Проблема 2 - ваша постоянная масштабирования. Проще говоря, вы хотите умножить на новый максимум и разделить на старый максимум, предполагая, что 0 остается на уровне 0,0 после преобразования.
const float Q = 1.0 / 0x7fffff;
Наконец, почему вы добавляете 0,5 в финальной конверсии? Я мог бы понять, пытались ли вы округлить до целочисленного значения, но вы идете в другом направлении.
Редактировать 2: Источник, на который вы указываете, имеет очень подробное обоснование вашего выбора. Не так, как я бы выбрал, но, тем не менее, вполне оправданно. Мой совет относительно множителя остается в силе, но максимум отличается из-за добавленного коэффициента 0,5:
const float Q = 1.0 / (0x7fffff + 0.5);
Поскольку положительные и отрицательные величины одинаковы после сложения, это должно правильно масштабировать оба направления.