LINUX.ORG.RU

64 бита в выражении с unsigned short'ами


0

0

Допустим есть такой код:

float op(float a, float p, float q) { return a * p * q; }

a, p, q дробные числа в диапазоне [0, 1]

нужно реализовать то же самое, но с unsigned short, т.е. fixed point:

u_int16_t op(u_int16_t a, u_int16_t p, u_int16_t q) { return a * p * q / (65535UL * 65535UL); }

я думал, что по логике оно должно без проблем скомпилиться в что-то типа:

mov ax, [arg_a] ; ax = a mov dx, [arg_p] ; dx = p imul dx ; dx:ax = a*p xor ecx, ecx mov cx, [arg_q] ; ecx = q imul ecx ; edx:eax = a*p*q idiv 0xfffe0001 ; eax = a*p*q/(65535*65535), edx = остаток ret ; результат в eax

Но op упорно возвращает 0 вместо 65535. Помогает смена типа аргументов на u_int64_t (с u_int32_t тоже возвращает 0).

Должен ли компилятор автоматически расширять операнды до 64 бит? Можно как-то заставить gcc (а в идеале, любой компилятор) юзать эти 64 бита? Или надо явно указывать преобразование в u_int64_t? Думаю, мне будет полезно посмотреть код какого-нибудь alpha blending'а в 16битах, никто не знает библиотеки, реализующей подобное?


>Должен ли компилятор автоматически расширять операнды до 64 бит?

Нет. Это Си, аля "универсальный ассемблер".

>Но op упорно возвращает 0 вместо 65535.

Понятно, "a * p * q" уж тогда лучше "((a*p)/65535UL)*q/65535UL)", хотя бы из 32 разрядов не выйдешь.

mky ★★★★★
()

Размер результата не будет больше, чем размер операндов. Проще всего произвести явное преобразование первого аргумента к 64 битам.

sf ★★★
()
Ответ на: комментарий от sf

> Размер результата не будет больше, чем размер операндов.

Мне и не нужно. Результат помещается в short.

AMDmi3
() автор топика
Ответ на: комментарий от mv

> По скорости отстой будет.
Угу

> to AMDmi3: Как на счёт mmx/sse? В самый раз для таких вещей.
Хочется скорее чистый портабельный код, нежели быстродействие.

Выяснилось (-O0, 100,000,000 итераций):
(u_int64_t)a * (u_int64_t)b * (u_int64_t)c / (65535UL * 65535UL)
=> 3.61 сек

((u_int32_t)a * (u_int32_t)b * (u_int64_t)c) / (65535UL * 65535UL)
=> 3.37 сек

a * b / 65535 * c / 65535
=> 1.07 сек

Однако выбор очевиден.

AMDmi3
() автор топика
Ответ на: комментарий от AMDmi3

> Fixed point не рулит без MMX/SSE?

Он продолжает нерулить и с MMX/SSE, т.к. для float есть SSE2 :) А так, fixed point своё преимущество по скорости начал терять после появления p166mmx (без учёта векторной обработки с mmx).

mv ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.