Я хотел бы узнать самый быстрый способ вычисления пропорций, то есть y = x * a/b
, где все значения 32 бит, без знака и a
и b
являются фиксированными (инициализируется один раз , а затем не изменяются), но не известны во время компиляции. Результат гарантированно не переполняется (даже подумал, что промежуточное умножение может понадобиться 64 бит). Язык программирования не имеет большого значения, но Java лучше всего подходит для моего случая. Это должно быть как можно быстрее (наносекунда). В настоящее время я использую:Multiply + Divide, используя только Multiply + Shift (32 бит)
int result = (int) ((long) x * a/b);
Но разделение происходит медленно. Я знаю о Perform integer division using multiplication, так что лучше бы формула типа:
int result = (int) (((long) x * factor) >>> shift);
где factor
и shift
могут быть вычислены из a
и b
(что расчет может быть медленным).
Я попытался просто заменить часть деления исходной формулы, но она не работает, так как результат двух умножений не помещаются в 64 бит:
// init
int shift = 63 - Integer.numberOfLeadingZeros(b);
int factor = ((1L << shift)/b) + 1;
...
// actual calculation
int result = (int) ((long) x * a * factor) >>> shift);
результат не на самом деле должны быть полностью точными в моем случае (с одного на все было бы хорошо).
У меня есть (частичное) решение сейчас: 'shift = 16; factor = ((long) a << 16)/b + 1; '- но он работает только для некоторого диапазона значений. Было бы неплохо иметь общее решение, которое будет работать для всех 32-битных значений без знака, если это возможно. –
Учитывая, что вы знаете о целочисленном делении с инвариантным делителем, неясно, где вы застряли. Учитывая, что 'a, b, x' - все' uint32_t', вычислить неподписанный 'uint64_t' продукт' x * a', затем применить к нему 64-разрядное деление с константным делителем 'b'. Если 'b' - константа времени компиляции, просто используйте оператор деления и пусть компилятор оптимизирует его. Наконец, верните выражение 'uint64_t' обратно в' uint32_t' (согласно спецификациям в вопросе, это гарантировано, что оно будет успешным по конструкции, никаких дополнительных тестов не потребуется). – njuffa
@njuffa К сожалению, значения не известны во время компиляции. Я изо всех сил старался найти элегантное решение с гарантированным поведением для краевых случаев (высокие значения для a, b и x). Думаю, теперь я разобрался. –