- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
uint32_t multiply (uint16_t a, uint16_t b)
{
return ((a & ( (int16_t)( ( b & (1 << 0) ) << 15 ) ) / ( 1 << 15) ) << 0 ) +
((a & ( (int16_t)( ( b & (1 << 1) ) << 14 ) ) / ( 1 << 15) ) << 1 ) +
((a & ( (int16_t)( ( b & (1 << 2) ) << 13 ) ) / ( 1 << 15) ) << 2 ) +
((a & ( (int16_t)( ( b & (1 << 3) ) << 12 ) ) / ( 1 << 15) ) << 3 ) +
((a & ( (int16_t)( ( b & (1 << 4) ) << 11 ) ) / ( 1 << 15) ) << 4 ) +
((a & ( (int16_t)( ( b & (1 << 5) ) << 10 ) ) / ( 1 << 15) ) << 5 ) +
((a & ( (int16_t)( ( b & (1 << 6) ) << 9 ) ) / ( 1 << 15) ) << 6 ) +
((a & ( (int16_t)( ( b & (1 << 7) ) << 8 ) ) / ( 1 << 15) ) << 7 ) +
((a & ( (int16_t)( ( b & (1 << 8) ) << 7 ) ) / ( 1 << 15) ) << 8 ) +
((a & ( (int16_t)( ( b & (1 << 9) ) << 6 ) ) / ( 1 << 15) ) << 9 ) +
((a & ( (int16_t)( ( b & (1 <<10) ) << 5 ) ) / ( 1 << 15) ) << 10) +
((a & ( (int16_t)( ( b & (1 <<11) ) << 4 ) ) / ( 1 << 15) ) << 11) +
((a & ( (int16_t)( ( b & (1 <<12) ) << 3 ) ) / ( 1 << 15) ) << 12) +
((a & ( (int16_t)( ( b & (1 <<13) ) << 2 ) ) / ( 1 << 15) ) << 13) +
((a & ( (int16_t)( ( b & (1 <<14) ) << 1 ) ) / ( 1 << 15) ) << 14) +
((a & ( (int16_t)( ( b & (1 <<15) ) << 0 ) ) / ( 1 << 15) ) << 15);
}
Умножение двух чисел через битовые маски и сдвиги без условных переходов. Компилятор переведет деление инта на сдвинутую единчку в арифметический сдвиг
Использование ">>" применительно к signed типам - implementation defined http://stackoverflow.com/questions/4009885/arithmetic-bit-shift-on-a-signed-integer/4009922
someone 18.07.2013 06:22 # +1
bormand 18.07.2013 07:24 # +2
ctm 18.07.2013 07:09 # 0
j123123 18.07.2013 08:18 # 0
Вот кстати, какими макросредствами лучше всего убрать копипаст? Встроенный в Си препроцессор тут явно не катит
bormand 18.07.2013 10:07 # +3
Dummy00001 20.07.2013 18:04 # 0
вот только недавно прикольную штуку откапал. в "Bit Twiddling Hacks" (сервак лежит, но страница еще в кэше гугля) - "Counting bits set by lookup table" - глянь как там таблица количества битов заполняется. помедитируй пару минут как эти B2/B4/B6 работают. я этот трюк в голове уже давно держу, но в практике помучать еще не приходилось.
демо, не тестировал, через cpp прогнал выглядит ОК вроде:
bormand 18.07.2013 07:11 # +4
> ((int16_t)(( b & (1 << 0)) << 15)) / ( 1 << 15)
Я так понимаю генерация маски - 0 если бит нулевой, ~0 если не нулевой?
Вот так можно попроще (для беззнаковых b): 1 - (b >> 0) & 1. Только b нужно заранее инвертировать.
P.S. А вообще зачем это понадобилось? Что-то для микроконтроллеров, не умеющих в умножение, типа AVR?
bormand 18.07.2013 07:35 # +5
bormand 18.07.2013 07:44 # +3
А еще забавно будет, если случится то, чего боялся автор, и на данном процессоре >> и / будут выдавать разный результат. В этом случае компилятор либо сфейлится вообще, либо высрет ужасный код, использующий настоящее деление. А судя по тому, что на данной платформе нету даже умножения (иначе зачем бы его запиливали?), то туда вставится софтовая эмуляция оного...
TarasB 18.07.2013 09:50 # +1
А они и так выдают разный результат.
TarasB 18.07.2013 09:49 # +3
Хуюшки. Для signed типов компилятор переведёт деление инта на сдвинутую единичку в говнище, которое сначала проверяет знак, потом для отрицательных прибавляет делитель минус один, и всё это потому, что в блядских пиндосовских процессорах вместо нормального деления - тупая пендосовская хуйня, у которой (-1)/3 = 0 (и остаток -1 лол), а не как у нормальных людей, когда частное -1, а остаток 2 (как и положено - остаток должен быть положительным).
bormand 18.07.2013 10:01 # +3
inkanus-gray 18.07.2013 12:13 # +8
HaskellGovno 18.07.2013 12:14 # +6
dwarf_with_beer 19.07.2013 05:25 # +2
bormand 19.07.2013 05:59 # +1
eth0 19.07.2013 19:51 # +3
j123123 18.07.2013 12:12 # +2
Циклические сдвиги http://software.intel.com/sites/products/documentation/studio/composer/en-us/2011Update/compiler_c/intref_cls/common/intref_allia_integer_arithmetic.htm
SSE2 http://software.intel.com/sites/products/documentation/studio/composer/en-us/2011Update/compiler_c/intref_cls/common/intref_sse2_int_shift.htm
Но обычного арифметического сдвига там нет, увы
Тут http://graphics.stanford.edu/~seander/bithacks.html#IntegerAbs тоже int сдвигается вправо
Более того, там сказано следующее:
I've read that ANSI C does not require values to be represented as two's complement, so it may not work for that reason as well (on a diminishingly small number of old machines that still use one's complement).