LINUX.ORG.RU

Объясните сишную магию v2

 ,


1

3

В продолжение темы: Объясните сишную магию

Ковыряю сорцы Skia и наткнулся на такой забавный ужас (ссылка):

int fLastMoveToIndex = 5; // любое число
fLastMoveToIndex ^= ~fLastMoveToIndex >> (8 * sizeof(fLastMoveToIndex) - 1);

Экспериментально удалось выяснить, что данный код меняет знак и отнимает 1 только если число положительное. Как он это делает - я даже знать не хочу.

Вопрос: что мешало написать банальный if, или хотя бы оставить комментарий? Типичное сишное какерство?

PS: производительно данного куска кода на погоду не влияет.

PS: производительно данного куска кода на погоду не влияет.

Вот с этим я не соглашусь. Я не уверен что компиляторы достаточно умные чтоб развернуть if в парочку дешевых логических операций, а не в условный переход.

timdorohin ★★★ ()

Вопрос: что мешало написать банальный if, или хотя бы оставить комментарий? Типичное сишное какерство?

Ответить можно только тестированием в цикле. Даешь варианты в тему:

  • subj
  • res = () ? : ;
  • if()
anonymous ()

что мешало написать банальный if

ИМХО микрооптимизации с минимизацией переходов, чтобы не сбрасывать на них конвейер. Хотя, если, как выясняется, кусок не горячий и его производительность роли особо не играет, то «оптимизация ради оптимизации», да.

или хотя бы оставить комментарий

Лень. С комментариями, даже в коммерческих сорцах всё грустно, sad but true.

SkyMaverick ★★ ()

Экспериментально удалось выяснить, что данный код меняет знак и отнимает 1 только если число положительное.

а ты внимательный и сообразительный. там двумя строками выше:

#if 0
  if (fLastMoveToIndex >= 0) {
      fLastMoveToIndex = ~fLastMoveToIndex;
  }
#else
  fLastMoveToIndex ^= ~fLastMoveToIndex >> (8 * sizeof(fLastMoveToIndex) - 1);
#endif

он не меняет знак и не отнимает единицу, он делает бинарный NOT, который выглядит как изменение знака и отнимание единицы.

anonymous ()

Вот уж действительно, «фанатизм заменяет знания».

[quote][code=c] fLastMoveToIndex ^= ~fLastMoveToIndex >> (8 * sizeof(fLastMoveToIndex) - 1);

[/code][/quote]

Ну что тут сложного, объясни?

Правая часть — все единички, если (fLastMoveToIndex < 0), и все нули иначе. Почему? Потому что two’s complement, старший бит — знаковый бит, выставлен тогда и только тогда, когда число отрицательное; а операция знакового сдвига вправо на (N-1), где N — количество бит в нашем числе, — это означает «расплодить знаковый бит».

Xor с этим значением — значит, инвертировать все биты, если (fLastMoveToIndex < 0), и не сделать ничего иначе. Надеюсь, не нужно объяснять, почему?

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

Потому что всё равно бранч. Компиляторы вообще умеют такие конструкции превращать в branchless-код, но последний gcc что-то сильно тупит в этом отношении. Лучше уж не полагаться на компилятор, а самому запилить бранчлесс.

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

Не стоит. Если код вокруг сложный, то компилятор может затупить. Подумать, что один из бранчей маловероятен и засунуть его куда-то в задницу. У меня так было на последнем gcc, и ничего он не понимал (даже __builtin_expect_with_probability(…, 0.5), лол), кроме как такого кода.

anonymous ()

Тут что-то непонятно может быть только тому, кто не имеет ни малейшего понятия как работают компьютеры. Ну веб-макакам всяким или там «программистам на пистоне».

Во-первых, это в общем-то три простейших операции: Нумер раз - инвертировать число. Нумер два - скопировать знаковый бит во все биты (для макак - «получить знак числа» - если число положительное то результат 0, если отрицательное то -1). Нумер три - XOR можно рассматривать как инверсию битов первого операнда, которым во втором операнде соответствуют единицы.

Всё тупо и просто, и читается на раз. Очень удобно, нет условных переходов, если эта операция посторяется миллиарды раз, то выигрыш может быть весьма ощутимым. Компилятор такое вряд-ли соптимизирует из if( i >= 0 ) { i = ~i }.

Написано всё очень даже грамотно, за исключением использования неадекватно длинного имени для переменной, как будто хорошего программиста годами пытали жабой.

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

программист решил, что без бранча лучше. единственный способ выяснить почему он так решил - спросить у него. вполне возможно, что одной из целевых платформ был вообще не x86 и предсказание бранчей там отсутствовало напрочь, поэтому там где это возможно писали бранчлесс.

а может ему просто показалось, что целый бранч для проверки > 0 для элементарной операции - это слишком жирно, и тот кто будет читать код, сможет осилить больше одной строки кода.

anonymous ()
Ответ на: комментарий от SkyMaverick

там такой код повсеместно, это вполне идиоматичное выражение для этой переменной, у неё даже изначальное значение ~0. оп просто не умеет читать, но наверное хочет что-то потырить из скии себе в говнокод на русте. но не может, это его печалит, и он просит объяснить сишную магию на форуме.

врядли поможет конечно. если человек не умеет читать, то как он будет писать?

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

это его печалит, и он просит объяснить сишную магию на форуме.

И правильно делает. Это как минимум интересно, по сравнению с той парашей, которой завален ЛОР под завязку.

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

наверное не без этого. ну так ему же объяснили «сишную магию», а он сбугуртился. хотя он сбугуртился ещё до того как ему объяснили. «я даже знать не хочу». ну не хочет - как хочет.

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

Ну, как-минимум, субъективно основываясь исключительно на собственном опыте команд в которых я работал, за использование микрооптимизационной магии и прочего битолюбства без явной на то необходимости жёстко били по рукам на code review.

Ну, если команда Skia любит трюки без необходимости, ну пусть делает - это их право. Зато все знают, что они умеют в битолюбство и дополнительный код. Ну ок.

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

Тем не менее, жертвовать читаемостью ради микрооптимизаций

А что тут может быть не читаемое? А что-то типа y -= y / 10 это тоже не читаемое, что-ли? Может надо заменить на что-нибудь с if’ами для читаемости? Чем битовые операции хуже арифметических?

Если кто-то не удосужился осилить элементарные операции, то это не значит что все остальные должны перестать их использовать.

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

микрооптимизационной магии и прочего битолюбства

О, ещё раз. Может хоть расскажешь, чем таким битовые операции отличаются от арифметических, и с какого перепугу, например, x >>= 2 это магия, а x = x / 4 внезапно нет?

Stanson ★★★★★ ()
Последнее исправление: Stanson (всего исправлений: 1)
Ответ на: комментарий от Stanson

А что тут может быть не читаемое?

Вот ты видишь эту конструкцию первый раз, НЕ зная заранее, что так делается битовый NOT. Ты поратишь сколько времени, чтобы понять что здесь происходит? Столько же, сколько понять кусок в «комментарии», который можно понять даже не вникая и читая по-диагонали? А если это не такая относительно простая конструкция, а раза в три больше? А если их по коду не одна, а десятка 2-3 и разных?

Вот именно по этому и не надо выёживаться без надобности.

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

Это не отменяет того факта, что это - лютый говнокод и бесполезная оптимизация (разве что SkPath& SkPath::close()) где-то в цикле 100500 раз дёргается. В противном случае сишники говно ложкой наворачивают.

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

а x = x / 4 внезапно нет?

Это тоже магия. Почему 4, а не что-то другое? Претензия же не к сдвигам и т.п., а к сути – для чего делается сдвиг, почему именно на такую величину и т.д.

no-such-file ★★★★★ ()
Ответ на: комментарий от SkyMaverick

Вот ты видишь эту конструкцию первый раз,

Вот вижу в первый раз. И всё предельно ясно.

НЕ зная заранее, что так делается битовый NOT

А может я ещё не знаю что такое сложение и вычитание? Нахера вообще лезть в програмирование если ты не знаешь элементарных операций? Это то же самое что пытаться работать кассиром не зная даже сложения с вычитанием.

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

но можно же придумать такой язык для кассиров, где сложение и вычитание не нужно. свободная касса, посканировал шрихкоды сканером, бип буп, помыл пол и пошёл домой.

anonymous ()
Ответ на: комментарий от SkyMaverick

работает не трожь

Девиз говнохранителей и домохозяек-экономок.

Вообще-то правильнее «NIH на века» и каждый проект бесконечно стремиться к совершенству так и не достигая рабочего состояния. Желательно переписывать на разные более модные ЯП при этом периодически.


Не многие вкусе, что битовые операции осваиваются на раз два и потом с ними не будет никаких проблем. Поэтому они и воспринимаются как магия. Я воевал против бинарных литералов, но местная аудитория почему-то против. Видимо в JS float-point Number не умеет в это – от того и горят пердаки неосиляторов.

Но всё же я склонен к тому, что компилятор должен делать больше, а человек меньше. А не наоборот. Анализ if-else конструкции беглым взглядом быстрее. Не потому что знаешь-не-знаешь, а потому что мозг может держать ограниченное количество образов одновременно. А главное, что работа программиста не стоит того, чтобы напрягаться лишний раз. Если это open-sorce for fun – другое дело. А вот для дяди… – не, нет.

kostyarin_ ()
Ответ на: комментарий от SkyMaverick

Ты поратишь сколько времени, чтобы понять что здесь происходит?

А сколько ты потратишь чтобы понять что происходит здесь: x = x + 123 * sizeof(x)? Вот ровно столько же.

А если это не такая относительно простая конструкция, а раза в три больше? А если их по коду не одна, а десятка 2-3 и разных?

В упор не понимаю в чём проблема. Вот написано x *= 7. Я типа должен впасть в ступор, и долго думать сначала о том, что x *= ... это x = x * ..., а потом скрипя мозгами догадаться что это x = x + x + x + x + x + x + x?

Stanson ★★★★★ ()
Последнее исправление: Stanson (всего исправлений: 1)
Ответ на: комментарий от peregrine

А если я тебе скажу, что вся бинарная магия не желательна в коде, когда в ней нет нужды, у тебя наверное шаблон треснет, да?

У меня трещит шаблон от того, что бинарные операции кто-то на ЛОРе считает магией.

А умножение со сложением вы магией не считаете? А почему?

Для меня нет никакой разницы по восприятию между сложением, умножением, сдвигом, исключающим или и т.п. Это же элементарные операции. Совсем элементарные, элементарнее просто некуда.

+ - * / выучили, а ~ | & ^ не осилили что-ли? Это, сцуко, вообще как??? Деление сложнее всех этих бинарных операций вместе взятых же.

Stanson ★★★★★ ()
Последнее исправление: Stanson (всего исправлений: 4)
Ответ на: комментарий от kostyarin_

проблема в том, что тупые ублюдки придумали ублюдочные компьютеры. они делают какие-то битовые операции и промахиваются мимо кеша когда возникает ветвление. из-за этого так называемые программы тормозят и падают, а если не тормозят и не падают, то хрен поймёшь, что они вообще делают.

когда все нормальные люди соберутся вместе и убьют всех тупых ублюдков, настанет золотая эра компьютинга, надо только подождать.

anonymous ()
Ответ на: комментарий от Stanson

зачем человеку который моет пол сдавать кассу? подготовка и оплата труда такого кассира будет слишком высокой. процесс должен быть построен так, чтобы кассиру даже вес проверять не надо было - эта информация уже должна быть включена в штрихкод. вот зачем нужен такой кассир я не знаю. но технология ещё не достигла того уровня когда подобных кассиров можно со спокойной душой выбросить на мороз.

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

зачем человеку который моет пол сдавать кассу?

Ну а как, приходит менеджер, достаёт деньги из кассы, говорит 100500 рублей не хватает. А «кассир» даже пересчитать не может.

вот зачем нужен такой кассир я не знаю. но технология ещё не достигла того уровня когда подобных кассиров можно со спокойной душой выбросить на мороз.

Уже давно достигла. В заграницах совсем давно, а в РФ уже несколько лет во всяких Метро есть кассы самообслуживания. Даже в Леруа Мерлене сделали. Кассиры не нужны, да. Но это не значит, что арифметику знать не надо.

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

А «кассир» даже пересчитать не может.

так даже лучше. снимаешь с кассира последнюю рубаху и нанимаешь другого.

Уже давно достигла.

ну вот. покайтесь ибо грядёт.

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

И оригинал и обфусцированный вариант дают одинаковый amd64-код для clang https://godbolt.org/z/PvEhsd

Обфусцированный вариант тупо подсмотрен и сворован из сгенеренного кода.

Вердикт: банальный выпендреж.

anonymous ()