Некоторое время назад я создал набор макросов C для манипулирования значениями с фиксированной точкой. Воодушевленный несколькими вопросами и ответами по SO, я надеялся получить прирост производительности в той части моей программы, которая требует интенсивных вычислений. Хотя код, кажется, дает правильные результаты, мне интересно, не слишком ли он наивен / упрощен, потому что на самом деле он работает для меня медленнее, чем обычные версии моих подпрограмм с плавающей запятой (я выполняю бикубическую интерполяцию изображений в Wintel). Не могли бы вы взглянуть на этот небольшой фрагмент кода, содержащий мои макросы, и предложить некоторые улучшения, особенно в отношении производительности? Спасибо.
// these are architecture-dependent
typedef short int fixed16;
typedef int fixed32;
typedef __int64 fixed64;
// value of 2^n
#define POW2(n) (1 << n)
// create 16bit integer-based fixed point value from a floating point value, n is the number of bits reserved for the fractional part
#define FP_MAKE16(x, n) ((x) > 0.0 ? static_cast<fixed16>(floor((x) * POW2(n) + 0.5)) : static_cast<fixed16>(ceil((x) * POW2(n) - 0.5)))
// the same, 32bit
#define FP_MAKE32(x, n) ((x) > 0.0 ? static_cast<fixed32>(floor((x) * POW2(n) + 0.5)) : static_cast<fixed32>(ceil((x) * POW2(n) - 0.5)))
// and 64bit
#define FP_MAKE64(x, n) ((x) > 0.0 ? static_cast<fixed64>(floor((x) * POW2(n) + 0.5)) : static_cast<fixed64>(ceil((x) * POW2(n) - 0.5)))
// convert a fixed-point integer from one (n) format to another (m) assuming n < m
#define FP_CONVERT_UP(x, n, m) ((x) << (m-n))
// same for n > m
#define FP_CONVERT_DOWN(x, n, m) ((x) >> (n-m))
// convert floating-point value back to float
#define FP_FLOAT(x, n) (static_cast<float>(x) / POW2(n))
// same for double
#define FP_DOUBLE(x, n) (static_cast<double>(x) / POW2(n))
// and for int. fractional part will be discarded!
#define FP_INT(x, n) ((x) >> n)
// arithmetic operations for same-format numbers
#define FP_NEG(a) ((~a)+1)
#define FP_ADD(a, b) ((a) + (b))
#define FP_SUB(a, b) ((a) + FP_NEG(b))
#define FP_MUL(a, b, n) (((a) * (b)) >> n)
#define FP_DIV(a, b, n) (((a) << n) / (b))
#define FP_POW2(a, n) (((a) * (a)) >> n)
#define FP_POW3(a, n) (((((a) * (a)) >> n)*(a)) >> n)
// arithmetic for different-format numbers, assuming n is the target (result) format and n > m
#define FP_ADD_UP(a, b, n, m) ((a) + ((b) << (n-m)))
#define FP_SUB_UP(a, b, n, m) ((a) + FP_NEG((b) << (n-m)))
#define FP_MUL_UP(a, b, n, m) (((a) * (b)) >> m)
#define FP_DIV_UP(a, b, n, m) (((a) << m) / (b))
// same for n < m
#define FP_ADD_DOWN(a, b, n, m) ((a) + ((b) >> (m-n)))
#define FP_SUB_DOWN(a, b, n, m) ((a) + FP_NEG((b) >> (m-n)))
#define FP_MUL_DOWN(a, b, n, m) (((a) * (b)) >> m)
#define FP_DIV_DOWN(a, b, n, m) (((a) << m) / (b))
РЕДАКТИРОВАТЬ: В основном ответы и комментарии касались этих двух пунктов:
- Код ужасен, его сложно использовать и поддерживать: Я полностью согласен и найду время, чтобы инкапсулировать его внутри класса. У меня были некоторые опасения по поводу производительности, которые были решены, и я был убежден, что они были необоснованными, и я пошел на все зря. :)
- С фиксированной точкой в любом случае не стоит беспокоиться: Хотя это может быть правдой на моей платформе, я создавал ее, чтобы повысить скорость выполнения моего кода на платформе, где не было оборудования с плавающей точкой. Там операции с плавающей запятой занимали слишком много времени, и было решено исправить это. Я тестировал это только на Intel, потому что в данный момент у меня нет доступа к целевому оборудованию.
Хотя я чрезвычайно благодарен за предоставленное до сих пор понимание, я надеялся услышать от кого-то, кто действительно сделал некоторые вычисления с фиксированной точкой, чтобы сказать мне, действительно ли эти арифметические операции действительно подходят. Возможно, есть какие-то дополнительные хитрые биты, о которых я не знаю, которые имеют значение в отношении производительности или точности? Другими словами, если мне нужно инкапсулировать этот код, могу ли я сохранить те же арифметические инструкции во встроенных операторных функциях в основном такими же, как сейчас, или мне следует как-то их изменить?
C
, так как это неC
код. - person Puppy   schedule 17.03.2011#define FP_ADD(a, b) ((a) + (b))
в коде, который был вынужден поддерживать, я был бы глубоко обеспокоен. - person meagar   schedule 17.03.2011C
компиляторы идиотски относились к функциям, не означает, чтоC++
компиляторы таковыми. Класс с арифметическими операторами вообще не будет иметь дополнительных накладных расходов на разумный современный компилятор. И это будет в миллиард раз безопаснее и правильнее. - person Puppy   schedule 17.03.2011