Вот моя короткая реализация Русское Крестьянское Умножение. как это может быть улучшено?
Ограничения: работает только когда a> 0, b> 0
for(p=0;p+=(a&1)*b,a!=1;a>>=1,b<<=1);
@Lance да, вы правы, я это изменю
Мой положительный отзыв, потому что короткие отступы онлайн МОГУТ быть плохими. Хотя было бы очень приятно читать красивый код с отступами.
spx выглядит так, будто люди тебя ненавидят. я не уверен, почему
да, люди меня ненавидят, ненавидят только все вокруг. Не знаю почему, может у вас есть ответ? компактный код порождает ненависть, я не могу сказать, что он был дидактическим / поучительным в какой-либо мыслимой форме. намерением очевидным намерением было тщеславие (гореть в аду, я буду). это может быть возможным объяснением той ненависти, о которой вы говорите. Что вы думаете ?





Я думаю, что он неполный, и его очень трудно читать. Какую конкретную обратную связь вы искали?
a, b - числа, после цикла for p будет их произведение. там нетрудно читать.
его труднее читать, чем нужно, и человек, который его написал, не тот человек, который может судить, трудно ли это читать. Что плохого в добавлении нескольких переносов строк?
добавление переносов строк нарушает компактность :)
вы имеете в виду "добавление переносов строк делает нечитаемым". Не меняет скомпилированный размер.
Почему бы вам просто не написать на ассемблере и перестать возиться с этими игровыми языками, такими как C. Вы, очевидно, выдающийся программист, и вам, вероятно, следует заняться преподаванием или консультированием.
p не инициализирован.
Что произойдет, если a равен нулю?
Что произойдет, если a отрицательный?
Обновлять: Я вижу, что вы обновили вопрос, чтобы решить вышеупомянутые проблемы. Хотя теперь ваш код работает так, как указано (за исключением проблемы переполнения), он все еще менее читабелен, чем должен быть.
p должен быть инициализирован с умножением 0, здесь работает только для a> 0, b> 0 :) спасибо за вопрос
Я думаю это ужасно Это точно такой же код с точки зрения компилятора и (надеюсь) намного более понятный
int sum = 0;
while(1)
{
sum += (a & 1) * b;
if (a == 1)
break;
a = a / 2;
b = b * 2;
}
И вот уже выписал, понимаю.
да, это была моя первая реализация :) потом вспомнил некоторые хитрости :)
Надеюсь, мне никогда не придется писать с вами код. Я не понимаю, почему кто-то мог взять что-то подобное вышеупомянутому и произвести то, что есть у вас, если только они не предприняли полубезнадежную попытку записи конкурса «Обфусцированный C». : |
Роб, задним числом это очевидно, но я действительно думал, что ты с самого начала говоришь со мной, а не с spx2!
Я бы подумал, что сдвиг бит будет быстрее, чем деление или умножение, и я не уверен, что все компиляторы будут делать это таким образом. (Хотя могут, здесь не уверен).
битовый сдвиг происходит быстрее, чем умножение или деление, НО любой достойный компилятор оптимизирует умножение на константу в набор битовых сдвигов, если это вообще возможно. Единственный компилятор, с которым я столкнулся, который этого не сделал, - это компилятор IAR H8. Я подозреваю, что это не целевая платформа.
Эй, пока вы занимаетесь этим, почему вы не заменили a & 1 на a % 2? И почему бы также не заменить sum += ... на sum = sum + ...? Я имею в виду, просто чтобы сделать это ДЕЙСТВИТЕЛЬНО ужасным. Эй, если кто-то не умеет читать C, ему следует искать работу VB. ;)
Влад - Я тоже умею читать по-английски, но это не значит, что я предпочитаю читать это так.
В цикле еще есть умножение. Если вы хотите снизить стоимость умножения, вы можете использовать вместо этого:
for(p=0;p+=(-(a&1))&b,a!=1;a>>=1,b<<=1);
да, это правда мой друг, фантастика! спасибо :) но ограничение b> 0 спасло вас здесь, если бы не это, вы были бы неправы.
Это для конкурса по обфускации кода? Я думаю, у тебя получится лучше. Для начала используйте вводящие в заблуждение имена переменных вместо бессмысленных.
int RussianPeasant(int a, int b)
{
// sum = a * b
int sum = 0;
while (a != 0)
{
if ((a & 1) != 0)
sum += b;
b <<= 1;
a >>= 1;
}
return sum;
}
Его можно улучшить, добавив пробелы, правильные отступы и правильное тело функции:
int peasant_mult (int a, int b) {
for (p = 0;
p += (a & 1) * b, a != 1;
a /= 2, b *= 2);
return p;}
Видеть? Теперь понятно, как используются три части объявления for. Помните, что программы написаны в основном для человеческого глаза. Нечитаемый код - это всегда плохой код.
А теперь, для моего личного развлечения, хвостовая рекурсивная версия:
(defun peasant-mult (a b &optional (sum 0))
"returns the product of a and b,
achieved by peasant multiplication."
(if (= a 1)
(+ b sum)
(peasant-mult (floor (/ a 2))
(* b 2)
(+ sum (* b (logand a 1))))))
Я не считаю это особенно ужасным, запутанным или нечитаемым, как говорят другие, и я не понимаю всех этих отрицательных голосов. При этом, вот как я бы "улучшил" это:
// Russian Peasant Multiplication ( p <- a*b, only works when a>0, b>0 )
// See http://en.wikipedia.org/wiki/Ancient_Egyptian_multiplication
for( p=0; p+=(a&1)*b, a!=1; a>>=1,b<<=1 );
Есть действительно простой способ улучшить это:
p = a * b;
У него даже есть то преимущество, что a или b могут быть меньше 0.
Если вы посмотрите, как это работает на самом деле, вы увидите, что это просто обычное ручное умножение, выполняемое в двоичном виде. Ваш компьютер делает это внутренне таким образом (1), поэтому самый простой способ использовать русский крестьянский метод - использовать встроенное умножение.
(1) Возможно, у него более сложный алгоритм, но в принципе вы можете сказать, что он работает с этим алгоритмом.
Ответ без умножения и деления:
function RPM(int a, int b){
int rtn;
for(rtn=0;rtn+=(a&1)*b,a!=1;a>>=1,b<<=1);
return rtn;
}
err ... (a & 1) * b ЯВЛЯЕТСЯ умножение. :)
Мне нравится оптимальный код, поэтому я дам вам голос, но вы должны были признать в приведенных выше комментариях, что ваш предварительно отредактированный пост не был инициализирован.