Все предыдущие реализации не используют округление и, следовательно, имеют большую ошибку:
Вот как это сделать в математике с фиксированной точкой:
Я использую предвидение X.1u (1 младший бит используется для дробной части).
//center = (max_x + min_x) / 2
center = max_x + min_x // zero error here
// distance = old_x - center
distance = (old_x << 1) - center // zero error here
//new_x = center + (distance * factor)
new_x = (**1** + center + (distance * factor)) >> 1
return new_x
Если коэффициент также является фиксированной точкой (целым числом) с N битами, описывающими дробь, то new_x можно рассчитать как:
new_x = ( (1 << N) + (center << N) + (distance * factor) ) >> (N + 1)
- (центр << N) </strong> имеет N + 1 дробных бит
- расстояние * коэффициент имеет N + 1 дробных бит
- (1 << N) </strong> - «половина», так как 1 << (N + 1) </strong> - «единица» в приведенной выше точности с фиксированной точкой.
После понимания каждой части вышеприведенную строку можно сжать:
new_x = ( ((1 + center) << N) + (distance * factor) ) >> (N + 1)
Используемый целочисленный тип должен быть достаточно большим, естественно. Если допустимый диапазон неизвестен, следует проверить ввод этой функции и что-то еще. В большинстве случаев это не нужно.
Это так же хорошо, как и в математике с фиксированной запятой. Так HW-схемы выполняют целочисленные математические операции.