LINUX.ORG.RU

char это и не signed и не unsigned а непонятно что

 


3

6
> cat main.cpp
#include <type_traits>

int main() {
        static_assert((::std::is_same<char, signed char>::value) == true);
        static_assert((::std::is_same<char, unsigned char>::value) == true);

        return 0;
}

> g++ -Wall -Wextra main.cpp
main.cpp: In function 'int main()':
main.cpp:4:2: error: static assertion failed
  static_assert((::std::is_same<char, signed char>::value) == true);
  ^~~~~~~~~~~~~
main.cpp:5:2: error: static assertion failed
  static_assert((::std::is_same<char, unsigned char>::value) == true);
  ^~~~~~~~~~~~~
★★★★

Ответ на: комментарий от Iron_Bug

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

Я вот наоборот, не понимаю, зачем нужны платформозависимые дефолтные типы. Вот нахрена мне, как программисту, нужен инт, который или 16 или 32 бита? А может все 64? Какая вообще польза? Я знаю, что существует много платформ в которых невыравненный доступ происходит медленнее или даже вообще невозможен, но при чём тут размер инта? Как располагать переменные в стеке или в структуре по умолчанию решает компилятор, так что там где не нужна упаковка он понаставит достаточно отступов. Извращаться с битовыми операциями при чтении из массива байтов придётся только в операциях доступа к элементам массива. Но это копейки. Не копейками это станет только если делать массовые операции, но, как мне кажется, вдолбить начинающим программистам на C идею «всегда используй memcpy/memset, если нужно обработать интервал внутри массива» было бы ненамного сложнее чем вдолбить «sizeof(short) <= sizeof(int) <= sizeof(long)».

Таким образом единственной проблемой осталась бы обработка больших объёмов массивов, для которых непринципиален реальный размер инта, непринципиальна упакованность, memset/memcpy не подходит, зато принципиальна экономия нескольких циклов на доступе. Ну такие случаи как мне кажется, логичнее считать исключительными и тогда уже пердолиться с платформозависимыми тайпдефами или просто сэмулировать выравнивание через замену массива интов массивом структур содержащих 1 поле инт.

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

Я вот наоборот, не понимаю, зачем нужны платформозависимые дефолтные типы. Вот нахрена мне, как программисту, нужен инт, который или 16 или 32 бита? А может все 64? Какая вообще польза?

Вы серьёзно? Это самый быстрый integer для платформы. Чтобы далеко не ходить - посмотрите ради интереса во что for-лупчики разворачиваются с int64_t, особенно в -m32.

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

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

Типы — это мощнейший инструмент для compile-time семантики, то есть для метапрограммирования. В данном контексте я называю ассемблер программированием, а то что на уровень выше - метапрограммированием.

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

Тем не менее, счастье в неведении, и если вы отличный си-программист, где типов особо и нет, то лучше им и оставаться..

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

Зависимые типы, афинные типы — это вообще будущее программирования (или уже настоящее, как посмотреть)
А си принципиально не менялся уже 50 лет... Думаю, он никуда не исчезнет, просто его роль всё больше будет вытесняться в сторону макроассемблера (llvm не везде же есть), а уровнем выше все будут писать на каком-нибудь растопитоне. Знание сишки всё ещё будет очень важным по этой и другим причинам, но хватит уже молиться на её примитивность

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

Зачем мне int64_t в качестве индекса цикла если мне не нужно 64 бита? А если мне необходимы именно 64 бита, нафига мне «быстрый инт», который эти 64 бита не вместит, но зато будет быстрым?

Я понимаю ход мыслей авторов этой идеи, «пусть инт будет удобного для железа размера, у нас тут значения небольшие, авось поместятся», я просто считаю это решение бессмысленным. Если ты уверен что твоему коду хватит и 16 битного инта, почему бы не использовать int16?

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

Если ты уверен что твоему коду хватит и 16 битного инта, почему бы не использовать int16?

Ну при конпеляции там же всё равно 32/64 битные регистры будут в конечном итоге. В си то как раз это имеет большое значение

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

Ну, так как мы обсуждаем гипотетический си с нормальными типами, это будет либо UB при переполнении, т.е. 32767 + 1 может не гарантироваться равенство с -1, хоть тип и называется 16битным. Тогда компилятору вообще ничего не нужно делать, просто использовал бы родные 32битные регистры. Либо он гарантировал бы правильное переполнение, тогда в некоторых местах пришлось бы добавить битовое И.

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

Если ты уверен что твоему коду хватит и 16 битного инта, почему бы не использовать int16?

Потому что его может вовсе не быть на данной архитектуре? Для примера

char, signed char    16 bits
pointers (data)
  small memory mode  16 bits
  large memory mode  23 bits
pointers (function)  24 bits
long long            40 bits

Note: C55x Byte is 16 Bits
By ISO C definition, the size of operator yields the number of bytes required
to store an object. ISO further stipulates that when sizeof is applied to char,
the result is 1. Since the C55x char is 16 bits (to make it separately addressable), a byte is also 16 bits. This yields results you may not expect; for example, sizeof (int) == 1 (not 2). C55x bytes and words are equivalent (16 bits).

Оно просто не умеет читать меньше машинного слова. Правда кривой long long, не осилила эта железка минимальных требования по размеру. Говорят, что есть какие-то DSP с byte == 32 бита.

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

Во-первых, непринципиально. Считаешь что int16 не нужен - используй int32. Во-вторых, как не нужен? Во времена доса/win16 был нужен как тот самый быстрый целочисленный тип. Сейчас тоже нужен, simd же и автоматическая векторизация циклов. Если платформа умеет бить SIMD-регистры на 16битные, то вот этот int16 увеличит пропускную способность цикла вдвое. В-третьих, как я уже писал, UB на переполнении или достаточно умный компилятор - всё это решит проблему неоптимальной кодогенерации. В любом случае, это меньшая проблема чем ломающийся при смене компилятора корректный код, и проявляться такие проблемы будут в одних и тех же случаях, когда код компилируется под платформу с размером регистра, отличным от того, который имел в виду программист.

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

Во-первых, непринципиально. Считаешь что int16 не нужен - используй int32.

Принципиально. int32 тоже не нужен, нужен в первую очередь int, о чём вам и пытаются втолковать

Если платформа умеет бить SIMD-регистры на 16битные, то вот этот int16 увеличит пропускную способность цикла вдвое.

Продолжайте свои технопатические фантазии, очень интересно. Вот есть у меня в процессоре блок умножения двух 32-битных чисел, ты как его собрался загружать своим говнокодом на int16? Даже сложение ты нормально не сплитнешь, там надо будет разряды переносить между двумя int16. Только побитовые операции можно так упаковать, как ты хочешь.

Во времена доса/win16 был нужен как тот самый быстрый целочисленный тип.

Правильно, и он тоже может и должен быть скрыт за алиасом int

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

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

В любом случае, это меньшая проблема чем ломающийся при смене компилятора корректный код

Так не пишите код, который ломается при смене компилятора

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

Короче, чувак, я всё объяснил. Если ты настолько тупой, что тебе что о стенку горох - я не обязан тратить на тебя время. Просто отвечу что весь твой коммент - безграмотный бред.

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

Короче, чувак, я всё объяснил. Если ты настолько тупой, что тебе что о стенку горох - я не обязан тратить на тебя время. Просто отвечу что весь твой коммент - безграмотный бред.

Симметрично

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

В целом, я советую каждому участнику любых жарких технических споров ради профилактики периодически задаваться вопросом «а что, если дебил в этом разговоре на самом деле я?».

Это немного меняет взгляд на мир и позволяет проще относиться к собственным тезисам

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

Так ты и есть дебил. Вот берём твой «убийственный» аргумент с 32битным алу и умножением на нем int16. Как же быть? Просто читаешь доку по языку, если там написано, что переполнение UB - просто загружаешь числа в 32битные регистры и умножаешь. 5*5=25 независимо от того байты это или qword. Если результат получился не тот, значит код некорректный.

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

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

Короче, чувак, я всё объяснил. Если ты настолько тупой, что тебе что о стенку горох - я не обязан тратить на тебя время. Просто отвечу что весь твой коммент - безграмотный бред.

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

Если ты уверен что твоему коду хватит и 16 битного инта, почему бы не использовать int16?

Использование shorts полезно только если оно позволяет сэкономить на memory bandwidth. Ну, если совсем на пальцах - пробежаться по int16_t[1000000] будет ровно в 2 раза быстрее чем по int32_t[1000000]. Использование размеров отличных от register size для temporaries - преступление за которое в приличных домах больно бьют по рукам (и не только). Погуглите «partial register stall». Не благодарите.

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

Ещё один безграмотный «учитель» вылез.

Вопрос как будут использоваться регистры - это вообще не твоя забота. Ты пишешь на языке высокого уровня. Кодогенерацией занимаешься не ты. Эти самые partial register stalls - это просто частный случай проблем конкретной архитектуры с которыми должен разбираться компилятор. Ситуация «операции с половинками регистров выполняются медленно» ничем не хуже ситуации «операции с половинками регистров вообще не поддерживаются». Однако и это легко решается компилятором. Вообще даю подсказку: операции над 16битными числами необязательно делать в 16битном регистре.

Кроме того я привел пример, автоматическая векторизация для SIMD-архитектуры. Почему-то тот факт, что огульное использование 32 бит снизит скорость такой обработки в 2 раза вообще никого не беспокоит, а то что криво написанный компилятор под x86 может нагенерить кода с partial register stall вдруг стало проблемой. Проблемой, за которую отвечает не автор кривого компилятора, а автор прикладного кода.

Что характерно: языки, спроектированные в последнюю пару десятков лет все как-то не решились повторять этот фокус. И не то что бы авторы языков никогда не слышали о C. Не то что бы не существовали миллионы программистов, привыкших писать int и ожидающих непонятое с размерностью. Максимум - сделают алиас int для удобства, на конкретный целочисленный тип, чтоб каждый программист знал, что int - это 32 бита. При этом всякие шорты/лонги - не, вот вам ребята типы с прописанной явно битностью. А если язык не пытается мимикрировать под C, тот же Rust например, так из него инт специально выкинут, типа бросайте эту вредную привычку. Всем очевидно, что копеечная экономия на сложности кодогенератора не стоит ошибок связанных с переполнением. Однако паре фанатиков C лорчика конечно виднее.

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

А если достаточно счета до 2^10, что мешает сделать спец MCU с такой ширирой машинного слова (и ригстров)? Должно стать неудобно перед уважаемым Rust’ом, которые жестко вшил размеры? Проще схема, энергоэффективней, дешевле. Можно выбрать любую сетку - 12, 24, 48, 96 бит, например. Типы вообще не обязаны быть кратны 8 битам, ничто не помешат спец железкам забить на ожидания свидителей 8 битных байтов.

привыкших писать int и ожидающих непонятое с размерностью

Нет там непонятного, тебе гарантируют минимум.

kvpfs ★★
()
Последнее исправление: kvpfs (всего исправлений: 1)

K: А давай сделаем кросс-платформенный ассемблер

R: Ну ведь всё равно получится херово, машслово везде разное

K: Тогда сделаем алиас int для машслова

R: Но ведь это не позволит использовать все трюки платформы

K: Ну пусть делают ассемблерные вставки, если им int не хватает

R: Ладно, пошёл писать макроассемблер... Кстати, как язык назовём?

<50 years later>

Некий хрюндель с ЛОРа: Ух пля, это что ещё за кроссплатформенный инт?! Да вы раст вообще видели?

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

Тут меня можно ткнуть носом, что int таки перестал (?) быть машсловом на x86_64, и всё на самом деле не так просто.. Ну, сишники поправят, если я что не так говорю

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

Вопрос как будут использоваться регистры - это вообще не твоя забота.

Тем не менее - меня очень даже волнует результат, и целенаправленно отстреливать себе ногу я не собираюсь.

Ты пишешь на языке высокого уровня. Кодогенерацией занимаешься не ты. Эти самые partial register stalls - это просто частный случай проблем конкретной архитектуры

Вы реально так думаете?

с которыми должен разбираться компилятор.

И знаете что он думает - «наверное этот дурачок всё таки имел в виду int, и вроде как ничего не сломается если подменить int16 им, а ну ка…».

Кроме того я привел пример, автоматическая векторизация для SIMD-архитектуры.

Щаз. Когда вы последний раз на disasm смотрели? Оставьте уже эти свои влажные мечты.

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

Вот есть у меня в процессоре блок умножения двух 32-битных чисел, ты как его собрался загружать своим говнокодом на int16?

А разве если твой умножитель может принять на умножение 32-битные числа (то есть умножитель 64-битный и результат помещается), то в чем проблема ему умножить 16-битные числа? Аппаратура же может просто сделать zero-extend до 32-ух бит. Я как-то занимался обратной задачей, когда блок умножения меньшей битности, чем результат умножения, на riscv на verilog: у меня на плисе был аппаратный dsp, который умеет выдавать 45-битный результат умножения, что при умножении 32-ух битных чисел порождало неэффективную топологию и я вот как раз разделял числа по 16 бит и умножал уже 16x16 бит.

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

А разве если твой умножитель может принять на умножение 32-битные числа (то есть умножитель 64-битный и результат помещается), то в чем проблема ему умножить 16-битные числа? Аппаратура же может просто сделать zero-extend до 32-ух бит.

Проблема в падении перфа. Если есть умножитель, который умеет умножать два 32-битных числа, то не надо в него умножения 16-битных пихать. Обе операции займут один тик [1], но умножать нативную разрядность эффективнее. Внезапно, когда пишешь на сях, надо думать об эффективности, о боже мой!

[1] Фиксированное число тиков, вообще говоря, но для изложения несущественно

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

Мы уже сейчас живём в мире распространившихся векторных CPU. И x86, и ARM имеют векторные расширения, я уж не говорю о всяких специализированных. При этом никого не беспокоит, что стандартный C не поддерживает эту векторность вообще никак, fp-арифметику делают используя части SSE регистров, оптимизирующие компиляторы сами изгаляются пытаясь развернуть циклы в векторный код. Но всё чем обеспокоены эксперты с лорчика - потерей 2х бит при компиляции int8_t на архитектуру с 10 битами или генерацию 4 сложений вместо 1 для 32битного инта.

Нет там непонятного, тебе гарантируют минимум.

Какой минимум? Вот в Борланд C, компиляторе на котором учились современные бородатые сионисты, это было 16 бит. Это уже минимум, или допустимы int и меньшего размера?

Представь, что вместо идиотского набора short, int, long в C добавили бы in8, in16, in32, in64. Куча программистов привыкли бы писать in16 ещё со времени DOS. У них бы изначально голова так работала, типа если для данной задачи очевидно что хватает 16 бит то и нечего требовать больше. Ты бы копировал этот код со стековерфлоу и компилировал бы его не глядя, а компилятор эмулировал бы in16 2мя 10битными словами. А если бы ты захотел вот этот кусок оптимизировать, ты бы просмотрел, убедился бы что ничего не ломается и разрядности хватает, и руками бы в нем заменил на in10, которого в стандарте языка нет, зато компилятор твоей платформы знает. В обратную сторону аналогично, взял бы кто твою программу, офигел от странных типов, но парой тайпдефов смог бы заставить этот код работать.

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

1 и 3 пункт противоречат друг другу.

Вывод: решение было ошибочным. Что характерно: уже в C добавили типы с определенной битностью, только из-за того что момент упущен пришлось называть их int32_t.

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

Вывод: решение было ошибочным. Что характерно: уже в C добавили типы с определенной битностью, только из-за того что момент упущен пришлось называть их int32_t.

https://en.cppreference.com/w/cpp/types/integer

Алиасов тебе на любой вкус. Можешь пользоваться int, int32_t, int_fast32_t, int_least32_t. Или ты опять скажешь, что всё это не нужно?

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

Но всё чем обеспокоены эксперты с лорчика - потерей 2х бит при компиляции int8_t на архитектуру с 10 битами или генерацию 4 сложений вместо 1 для 32битного инта.

Да, именно так

И благодаря нам, экспертам с лорчика, чайники с лорчика (такие как ты) получают по башке за свой говнокод, даже высказанный литературно в виде фантазий.

Потому что нечего молодёжь дурному учить. Пишите программы эффективно, да благословит вас Дональд Эрвин Кнут. Аминь.

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

оптимизирующие компиляторы сами изгаляются пытаясь развернуть циклы в векторный код

А где тут проблема? Зачем мне делать это самому? Но если очень хочется, то развернуть цикл самостоятельно - не проблема (во всяком случае в крестах).

Какой минимум? Вот в Борланд C, компиляторе на котором учились современные бородатые сионисты, это было 16 бит. Это уже минимум, или допустимы int и меньшего размера?

int - at least 16 bits.

в C добавили бы in8, in16, in32, in64.

открой для себя <cstdint>

а компилятор эмулировал бы in16 2мя 10битными словами

И ты говорил про векторные вычисления … Ты представляешь какой это костыль? Это люто тормозная какашка. В этом и плюс сишных неточных размеров - на нестандартной архитектуре он сгенерит быстрый код, а ты утонешь в правках этого говнокода.

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

Чувак, ты этот бред написал уже раза 3. И за всё это время так и не пояснил, почему это умножать нативную ширину эффективнее. Нет, я не спорю, если ты пишешь либу для криптографии и делаешь длинные операции, то круче использовать ALU на полную ширину, а не эмулировать 2048битное умножение через int8_t на 32битном процессоре.

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

Я вот погуглил насчёт латентности команды imul на x86 процессорах. Разницы нет. Ну т.е. есть, относительно старые процессоры типа Core 2 умножают 32 бита чуть-чуть быстрее чем 64. Но всё меняется если посмотреть на idiv. Даже на самых современных процессорах деление 8битных чисел быстрее чем 16 битных, а 16битных быстрее чем 32. Так что ты попал пальцем в небо, операции с меньшим чем родная размерность по меньшей мере не медленнее, а скорее всего и быстрее.

Почему же для перемножения небольших чисел используют 32битные Инты? 1) потому что не хотят париться определением правильного типа и 2) потому что int писать удобнее. Производительность тут вообще никаким боком

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

Не удержался.

Всем очевидно, что копеечная экономия на сложности кодогенератора

Я так понимаю - кто-то с десяток компиляторов написал и знает о чём говорит.

не стоит ошибок

Что вы знаете о стоимости ошибок?

Однако паре фанатиков C лорчика конечно виднее.

Я бы ярлыки не вешал. Но вам тут многие пытались мозги вправить. Походу - бесполезно.

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

Алиасов тебе на любой вкус. Можешь пользоваться int, int32_t, int_fast32_t, int_least32_t. Или ты опять скажешь, что всё это не нужно?

Слышь, я уже понял что ты туп как пробка, но у всего должны быть границы. Я пишу что даже в C осознали как тупо было не фиксировать размерность типов и потому добавили все эти типы, только с неудобными названиями. Ты в ответ мне показываешь на эти самые алиасы и предлагаешь мне доказать что они не нужны. Нет, тупица, я утверждаю что они нужны, а не нужен был как раз оригинальный int непонятной длины

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

И благодаря нам, экспертам с лорчика, чайники с лорчика (такие как ты) получают по башке за свой говнокод

Вот только пока что это ты дважды обосрался, один раз когда тебе пришлось объяснять как на 32битном алу умножать 16битные числа, а потом когда не проверив нес чушь про якобы неоптимальность операций меньшей битности

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

А где тут проблема? Зачем мне делать это самому?

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

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

int - at least 16 bits.

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

И ты говорил про векторные вычисления … Ты представляешь какой это костыль? Это люто тормозная какашка

Представляю. Если чё, я даже лабораторку про умножение методом Тоома-Кука когда-то писал, а уж тупое умножение в столбик 2-4значных чисел меня вот ни капли не пугает. И тем более не пугает, если я знаю, что это всё напишут авторы компилятора.

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

Зачем мне удалять? Вообще любопытно что все 3 идиота в данной теме неспособны хоть что-то ответить по существу и при этом не обосраться.

Лучше всего получается только аргументация типа «ха-ха-ха пацталом»

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

Но C как-то обходится без поддержки векторности со стороны языка. Если компилятор сможет сам - хорошо, ну или ассемблерную вставку делай, или интрисики используй, непереносимые. И ты таким положением дел не возмущается, не смотря на то что сейчас эта проблема очень важна.

Оно может и надо, но не в стандарте (хотя пытаются что-то протащить), слишком изменчиво, новые наборы, разные размеры регистров. Оно спокойно может существовать в виде сторонних либ, например вот https://github.com/root-project/veccore, с ходу загуглил (не ковырял), в общем это надо как-то так решать, а не втаскиванием в стандарт.

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

Вообще любопытно что все 3 идиота в данной теме

Вы всегда о себе во множественном числе? Я подозревал что всё запущено - но не настолько же…

Лучше всего получается только аргументация типа «ха-ха-ха пацталом»

Дык, вам и так подсказывали, и эдак. И куда смотреть, и какие у народа проблемы бывают. Именно от вас не видно конкретики, а только общие, ничем не подтверждённые (имхо - ложные) утверждения.

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

Чувак, ты этот бред написал уже раза 3. И за всё это время так и не пояснил, почему это умножать нативную ширину эффективнее. Нет, я не спорю, если ты пишешь либу для криптографии и делаешь длинные операции, то круче использовать ALU на полную ширину, а не эмулировать 2048битное умножение через int8_t на 32битном процессоре.

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

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

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

Здесь ты, по-моему, даже в русском языке запутался. Не увеличит, а уменьшит. И не производительность, а эффективность (читай внимательнее, пожалуйста).

Эффективность здесь определяется через утилизацию процессорных блоков. Для начала, давай заменим умножение на сложение, умножение — это слишком сложно. Также для простоты возьмём типы с квалификатором unsigned, про UB поговорим в другой раз, чтобы не раздувать скоуп дискуссии. Операция uint32+uint32=uint32 не содержит UB при любом значении операндов.

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

  • Далее, есть некий говнокод от хрюнделя, который использует сложение uint16. Примем, что компилятор сделает zero-extension и твой код будет использовать этот 32-битный блок сложения.
  • А также есть чуть-менее-говнокод от чуть-более-умного-и-сбавившего-гонор хрюнделя, который использует сложение uint32 уже на уровне языка

Сравним эффективность этих кодов. Первый использует лишь половину ширины регистров обоих операндов. Второй полностью. Это означает, что у более глупого хрюнделя его процессор гоняет 50% мусорных данных (нули складываются с нулями). А более умный хрюндель использует свой процессор на 100% и радуется жизни. Разница в эффективности ровно в 2 раза. За то же самое время, что первый хрюндель обрабатывает 1 гигабайт данных, второй успевает обработать 2 гигабайта. Разницу видишь?..

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

Я вот погуглил насчёт латентности команды imul на x86 процессорах. Разницы нет. Ну т.е. есть, относительно старые процессоры типа Core 2 умножают 32 бита чуть-чуть быстрее чем 64. Но всё меняется если посмотреть на idiv. Даже на самых современных процессорах деление 8битных чисел быстрее чем 16 битных, а 16битных быстрее чем 32. Так что ты попал пальцем в небо, операции с меньшим чем родная размерность по меньшей мере не медленнее, а скорее всего и быстрее.

Делением вообще нужно пользоваться по минимуму, оно просто медленное. Если у тебя в коде много делений, лучше это исправить. Но хорошо, что ты начал что-то гуглить для ответов мне. Значит, я не зря пишу. А за комплимент про небо спасибо.

P.S. Если ты ответишь на этот коммент культурно, то я даже могу попробовать в 5-ый раз. Вчера ты как-то совсем жёстко быдлил, сегодня вроде пытаешься разобраться. Не обижайся, обнял.

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

Дык, вам и так подсказывали, и эдак. И куда смотреть, и какие у народа проблемы бывают. Именно от вас не видно конкретики, а только общие, ничем не подтверждённые (имхо - ложные) утверждения.

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

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

Сравним эффективность этих кодов. Первый использует лишь половину ширины регистров обоих операндов. Второй полностью. Это означает, что у более глупого хрюнделя его процессор гоняет 50% мусорных данных (нули складываются с нулями).

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

N-разрядные сумматоры и умножители всегда оперируют данными разрядности N. Они по-другому не умеют в принципе. Они так устроены. Если данные имеют меньшую разрядность, то их сначала надо (знако)расширить. (Как иначе можно состыковать аппаратный блок M (multiplier), у которого входы разрядности N, с аппаратными блоками R (register) разрядности N/2? Хотя на самом деле блок R тоже разрядности N, откуда берётся N/2, непонятно.)

И сумматору, и умножителю в принципе наплевать, сколько там нулей и сколько значащих бит из N на входе. Он обрабатывает всегда N бит.

Доступно?

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

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

Я рад, что смог вам доставить это удовольствие

И сумматору, и умножителю в принципе наплевать, сколько там нулей и сколько значащих бит из N на входе. Он обрабатывает всегда N бит.

Доступно?

Ага. Только если значащих бит N1 < N, то эффективность утилизации сумматора падает. До величины N1/N

Доступно?

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

Операция uint32+uint32=uint32 не содержит UB при любом значении операндов.

Вот опять начали хорошо, а закончили «нули складываются с нулями». Тут же дело в другом. Для uint32 переполнение обработается аппаратно, а для uint16 скомпилированному коду надо программно проверять, было ли переполнение, а если было, то корректировать результат.

С другой стороны, khrundel же говорит о предсказуемом поведении на разных платформах. Что будет, если мы перенесём этот код на какой-нибудь 8-битный микропроцессор? Нормально там с int-ом везде работать?

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

закончили «нули складываются с нулями»

Нули с нулями хочет складывать как раз хрюндель, а «3 идиота» (myself, bugfixer, kvpfs) которыми он так любезно назвал своих оппонентов, пытаются его отговорить.

Для uint32 переполнение обработается аппаратно, а для uint16 скомпилированному коду надо программно проверять, было ли переполнение, а если было, то корректировать результат.

Не надо ничего программно проверять. Тип uint16 вообще не надо использовать на 32-битной платформе в «горячем» коде, это есть мой главный месседж в этой дискуссии.

А в «холодном» коде занимайтесь любыми извращениями. Если же у вас вообще нет «горячего» кода, то нахрена вы пишите на си?!

С другой стороны, khrundel же говорит о предсказуемом поведении на разных платформах. Что будет, если мы перенесём этот код на какой-нибудь 8-битный микропроцессор? Нормально там с int-ом везде работать?

Если вы поняли, о чём говорит хрюндель, честь вам и хвала. Какой «этот» код вы собрались переносить, я не понял. Про 8-битные микропроцессоры вам ответит кто-нибудь другой, если захочет.

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

Нули с нулями хочет складывать как раз хрюндель

Так и при uint32 те же нули с нулями будут складываться. В чём разница?

Тип uint16 вообще не надо использовать на 32-битной платформе в «горячем» коде, это есть мой главный месседж в этой дискуссии.

Я выше не видел условия про «горячий» код. И спор изначально был не uint16 vs uint32, а uint с конкретной разрядностью vs uint с неопределённой разрядностью.

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

И спор изначально был не uint16 vs uint32, а uint с конкретной разрядностью vs uint с неопределённой разрядностью.

Так и есть. До сих пор не удалось донести до товарища «Хрюнделя» что применимость фиксированной разрядности довольно узка. В подавляющем числе случаев нужен просто int, и это именно то что будет работать наиболее эффективно.

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

Я выше не видел условия про «горячий» код.

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

Если вас не волнуют такие мелочи, как эффективность регистровой утилизации и прочие HPC штучки, лучше взять другой язык, серьезно. Сишка всегда была про байто*бство.

И спор изначально был не uint16 vs uint32, а uint с конкретной разрядностью vs uint с неопределённой разрядностью.

Спор изначально был действительно об этом, но хрюндель упёрся рогом (пятачком?), что нет ничего плохого в том, что битность типа не матчится с битностью регистров. А я как раз и показываю, чем именно это плохо

Но всё чем обеспокоены эксперты с лорчика - потерей 2х бит при компиляции int8_t на архитектуру с 10 битами или генерацию 4 сложений вместо 1 для 32битного инта.

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

Так и при uint32 те же нули с нулями будут складываться. В чём разница?

Какие «те же»? Надо писать код так, чтобы нули с нулями вообще не складывались! Зачем процессор то зря насиловать?

Crocodoom ★★★★★
()