LINUX.ORG.RU

Производительность; илитный запил оптимальных реализаций и основы матчасти.

 , , ,


21

17

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

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

Изначально я хотел написать про то: что такое бесплатные вычисления на примере is_range() + сумма елементов массива, но тут выявилась смешная особенность, поэтому пока без is_range().

Начнём с простого - сумма елементов(float) массива. Как написать её быстро? Обычный крестопоц сделает так:

auto summ = accumulate(begin(vec), end(vec), 0.)

Этот код выдаёт 5.6GB/s(мы всё бенчим в л1д 32килобайта массив). Казалось бы, если бы мы слушали всяких «гуру», которые нам говорят: accumulate() - оптимизирован, «ты что умнее создатели stl"а?», «конпелятор умнее тебе - сам всё делает оптимально», «руками что-то делать слишком сложно и не нужно» - то мы бы там и остались с этими 5.6ГБ, но мы пойдём дальше и поймём почему так, и является ли это тем, что намн ужно.

Но посмотрев на код - он не векторизован:

	addq	$4, %rdx
	vcvtss2sd	-4(%rdx), %xmm2, %xmm2
	vaddsd	%xmm2, %xmm1, %xmm1

Почему? Патамучто это основная флоатпроблема: Он не ассоциативен - флоат не имеет в себе точных представлений всех чисел входящих в диапазон его «представления» т.е. порядкопроблемы.

Поэтому конпелятор НЕ ВЕКТОРИЗУЕТ флоат по умолчанию, ну никак. Даже такую банальщину.

Для решения этих проблем - есть ключик -funsafe-math-optimizations, который входит в -ffast-math, который кладёт на точность при вычислениях. Добавив его мы получаем уже 44.9GB/s.

Но теперь мы получаем ещё одну проблему - надо думать: «как бэ сунуть эту ключик не повредив там, где этот ключик не нужен».

Поэтому ноцанам, которые хотят быстро и не хоятт рандомных жоп из-за тупости конпелятора - пишут всё руками. Допустим на той же сишке это пишется так:

double memadd_autovec(buf_t buf) { //5.609465GB/s, либо 44.969652GB/s с ffast-math
  float * it = buf_begin(buf), * end = buf_end(buf), summ = 0.;
  do {
    summ += *it++;
  } while(it != end);
  return summ;
}

double hsumf(__v8sf v) {
  return (v[0] + v[1] + v[2] + v[3] + v[4] + v[5] + v[6] + v[7]);
}

double memadd_vec(buf_t buf) { //45.652002GB/s и класть на ffast-math
  __v8sf * it = buf_begin(buf), * end = buf_end(buf), summ = {};
  do {
    summ += *it++;
  } while(it != end);
  return hsumf(summ);
}

Т.е. разницы никакой нет, кроме нужной нам реализации горизантального сложение вектора. Когда я говорил пацану: «векторную сишку для написания быстрого кода юзать намного проще, чем плюсы» - поцан нипонимэ, да и любые пацаны скажут - ну дак с -ffast-math оба выдают по 45гигов - нахрен эта сишка нужна?

А вот зачем:

double memadd(buf_t buf) { //132.878440GB/s
  __v8sf * it = buf_begin(buf), * end = buf_end(buf), summ = {};
  do {
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;
  } while(it != end);
  return hsumf(summ);
}

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

Если бы мы слушали всяких «гуру», которые нам вещают: «анрол говно и не нужен» - мы бы так и седели с 45-ю гигами, а так мы сидим с 132.878440GB/s. Т.е. анролл нам дал немного не мало ~300%.

Но основная мысль, которую толкают всякие «гуру» - это не надо следить за тактами/считать такты и прочее. Но мы о5 сделаем наоборот и посмотрим что будет.

Т.к. наш юзкейс упирается на 99% в throughput и дёргается одна инструкция, то нам достаточно просто считать теоретическую производительность для моего камня. 4.5(частота камня)*8(т.е. у нас камень с avx, то там вектор 32байта, либо 8флоатов.)*1(throughput нашей инструкции - в данном случае vpaddps из интел мануала). Т.е. 36гигафлопс, либо ~144гига. Т.е. мы сняли овер 90% теоретической производительности - остальные 10% у нас ушли в наши циклы, всякие горизонтальные суммы вектора и прочее, ну и конечно же чтение данных из кеша.

Но самое смешное - на моём хасвеле умножение имеет throughput 0.5 - т.е. на хасвеле умножение быстрее сложения. Это новая забористая трава у интела.

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

Поэтому очень смешно слушать, когда какие-то пацаны говорят: «float point имеет такую же производительность как и инты» - нет, оно имеет такоу же производительность лишь по причине того, что на штеуде инты тормазят так же, как и float.

И чтобы окончательно в этом убедится - мы взглянем на fma(вариации умножения со сложением/вычитанем), которые имеют throughput 0.5 - да, да - на хасвеле умножение+сложение в 2раза быстрее просто сложения. Это уже не просто трава - это что-то принципиально новое.

У целочисленного сложения же throughput 0.5 и казалось бы, если мы поменяем в нашей функции float на int - у нас будет сложение работать в 2раза быстрее, но это не так. Оно выдаёт те же 130гигов, а почему?

Вообще у камня есть такая фича, допустим у нас:

add $1, %reg0//вот тут инструкция add залочит регистр reg0
add $1, %reg0//а эта инструкция уйдёт в лок до особождения предыдущей инструкцией регистра reg0

Чтобы такой жопы небыло - есть специальная фича:

add $1, %reg0//lock reg0
add $1, %reg0//И тут вместо того, чтобы уйти в лок - камень вместо reg0 даёт инструкции любой свободный регистр.

Эта фича называется прееименование регистров, либо как-то так - мне лень гуглить.

Дак вот штука в том, что фича работает через жопу. Мне лень читать мануал и искать почему так, но штука в том, что она ограничивает throughput. На умножении и целочисленном сложении она огранивает throughput c 0.5 до 1.

И вот я решил заюзать сложении через fma:

__v8sf fmaadd(__v8sf a, __v8sf b) {
  return _mm256_fmadd_ps(_mm256_set1_ps(1.), a, b);// a + b * 1. == a + b.
}

double memadd_fma(buf_t buf) {
  __v8sf * it = buf_begin(buf), * end = buf_end(buf), summ = {};
  do {
    summ = fmaadd(summ, *it++);
  } while(it != end);
  return hsumf(summ);
}

Но меня ждала жопа: 27.347290GB/s, причем не анролл и ничего не помогал. Я уж подумал, что мануал наврал, но позже до меня допёрло: у неё latency 5тактов и ((4.5×8)÷5)×4 ~= 29гигов - т.е. я получаю производительность с её latency, но какой жопой оно так?

Потом я вспомнил, что гцц гинерит анрольный код вида:

add $1, %reg0
add $1, %reg0
//а не
add $1, %reg0
add $1, %reg1

Т.е. на неё вообще не работает переименовывание регистров - и инструкции постоянно в локе. Я это проверил и оказался прав. Ну и я написал такой мемадд:


__v8sf fmaadd(__v8sf a, __v8sf b) {
  return _mm256_fmadd_ps(_mm256_set1_ps(1.), a, b);
}

inline void fma_10way_finality(__v8sf * cache, __v8sf * it, __v8sf * end) {
  switch(end - it) {
    case 8:
      *(cache + 7) = fmaadd(*(cache + 7), *(it + 7));
      *(cache + 6) = fmaadd(*(cache + 6), *(it + 6));
    case 6:
      *(cache + 5) = fmaadd(*(cache + 5), *(it + 5));
      *(cache + 4) = fmaadd(*(cache + 4), *(it + 4));
    case 4:
      *(cache + 3) = fmaadd(*(cache + 3), *(it + 3));
      *(cache + 2) = fmaadd(*(cache + 2), *(it + 2));
    case 2:
      *(cache + 1) = fmaadd(*(cache + 1), *(it + 1));
      *(cache + 0) = fmaadd(*(cache + 0), *(it + 0));
    case 0:
      break;
    default: error_at_line(-1, 0, __FILE__, __LINE__, "bad_aligned");
  }
}

double memaddfma_10way(buf_t buf) {
  __v8sf * it = buf_begin(buf), * end = buf_end(buf), summ = (__v8sf){};
  __v8sf * cache = (__v8sf[10]){{}};
  uint64_t i = 0;
  while((it += 10) <= end) {
    *(cache + i) = fmaadd(*(cache + i), *(it - i - 1));++i;
    *(cache + i) = fmaadd(*(cache + i), *(it - i - 1));++i;
    *(cache + i) = fmaadd(*(cache + i), *(it - i - 1));++i;
    *(cache + i) = fmaadd(*(cache + i), *(it - i - 1));++i;
    *(cache + i) = fmaadd(*(cache + i), *(it - i - 1));++i;
    *(cache + i) = fmaadd(*(cache + i), *(it - i - 1));++i;
    *(cache + i) = fmaadd(*(cache + i), *(it - i - 1));++i;
    *(cache + i) = fmaadd(*(cache + i), *(it - i - 1));++i;
    *(cache + i) = fmaadd(*(cache + i), *(it - i - 1));++i;
    *(cache + i) = fmaadd(*(cache + i), *(it - i - 1));++i;
    i = 0;
  }
  fma_10way_finality(cache, (it - 10), end);
  summ = (*(cache + 0) + *(cache + 1) + *(cache + 2) + *(cache + 3) +
	  *(cache + 4) + *(cache + 5) + *(cache + 6) + *(cache + 7) +
	  *(cache + 8) + *(cache + 9));
  return hsumf(summ);
}

Пришлось хреначить финалити, ибо тут «анролл» на 10, а почему на 10 - для максимального throughput"а - надо, чтобы каждый каждый регистр юзался через 5тактов - т.е. 10регистров.

И вся эта порятнка нужна для борьбы с тупостью конпелятора.

Это уже: 214.167252GB/s(раельно там в районе 250 - просто мой бенч говно). 107 гигафлопс на ведро. Из теоретических 144, но тут уже влияние кеша. Причем 50+ из которых выкидываются и просто бесплатные.

Теперь вопрос к пацанам - что нам дадут эти гагфлопсы, когда у нас будет массив не 32килобайта, а 32мегабайта? Зачем нужно выживать максимум, когда скорость памяти отсилы 20-30гигабайт и нам хватит даже С++ кода с ffast-math?

Ну и призываются упомянутые мною пацаны: mv - этот тот експерт, что вещал про «руками переименовывать регистры не надо» и «анрол ваще ненужен», emulek вещал про ненужность счёта тактов, и не понимал что такое «беслпатно», AIv - не понимал в чем проблема плюсов, ck114 - так же не понимал в чем проблема плюсов.

Бенчи: https://gist.github.com/superhackkiller1997/606be26fa158ef75501d - вроде я там ничего не напутал.

P.S. - не выпиливайте пж, пусть пацаны «нужно» или «не нужно». Мне интеерсно. Ну и там рекомендации пацанов.



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

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

часто имеет смысл сначала отсортировать(ранжировать) данные. Для примера посчитай сумму 1-½+⅓-¼… Точность будет ниже плинтуса. А зачем нужна твоя скорость, если точность ниже плинтуса?

PS: когда ты складываешь два float'а, ты получаешь 2⁻²³ бит ☣(в лучшем случае). Внимание, вопрос: сколько точных битов ты получишь после своего сложения в лучшем случае?

Ответ — нисколько.

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

Раскрой тему - почему нельзя складывать массив float?

можно. Только смысла в этом никакого нет. Максимум 100 float'ов можно складывать с пользой, а результат дальнейшего прибавления годен разве что как хреновый ГПСЧ.

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

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

что-то я сомневаюсь…

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

Это ты о проблеме всех операций с плавающей точкой (и тогда это капитанство)

нет, не капитанство. Только ТС мог додуматься складывать 32К float'а. А если складывать массивы по 30..50 чисел, то всё нормально получается. Можно и 500 чисел сложить, но не так тупо и топорно, как это делает ТС.

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

Это ты о проблеме всех операций с плавающей точкой (и тогда это капитанство)

нет, не капитанство

Именно капитанство.

Только ТС мог додуматься складывать 32К float'а. А если складывать массивы по 30..50 чисел

И что мешает использовать сумматор ТС как основу более навороченного сумматора?

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

Только ТС мог додуматься складывать 32К float'а. А если складывать массивы по 30..50 чисел

И что мешает использовать сумматор ТС как основу более навороченного сумматора?

ненужность этого сумматора.

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

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

Но если не группировать данные, то числа получаются разными, что ведёт к катастрофической потери точности. Причём нет никакой принципиальной разницы, float это, или double.

Ну грубо говоря, если у тебя есть Over9000 маленьких чисел, и одно большое, которое весит ⅒ суммы всех маленьких, то результат на 90% зависит от маленьких. Однако, когда ТС начнёт складывать всё в куче, большое число поглотит все Over9000 маленьких, и ошибка будет около 900% (sic! девятьсот процентов). Зачем нужен _такой_ результат?

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

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

да, про «серьёзные конторы» тут не просто так говорили: в тз точность прописывается _точно_, в отличие от времени. Если твоя программа всегда «думает» 1с, а раз в году 10с, то это не страшно. А вот если она всегда считает точно, но раз в году ошибается в десять раз, то тебя погонят ссаными тряпками. И будут правы. Вот у ТСа как раз такая ситуация: в среднем ошибка небольшая, но _иногда_, она может быть _какая_ _угодно_.

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

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

Почему? Если сделать группу в 32 числа (или 48, чтобы не нарушать твое ограничение 30..50), анролл сработает.

«более навороченный сумматор» сначала рассортирует числа по группам, а потом уже будет складывать эти группы.

«Рассортирует»? Ты говоришь о каскадном суммировании или о чем?

если у тебя скажем 4 группы

А если 400?

то тебе нет смысла «анроллить» каждую группу, намного выгоднее сразу обрабатывать все 4 группы одним потоком

Анролл, если дает эффект, то эффект должен быть даже на 4-6 итерациях.

А если поделить числа на группы, всё будет хорошо, вот только «анролл» приткнуть будет уже некуда,

Кхм. Составляем список смещений начал групп, сортируем его, проходим по нему функцией ТС, но вместо суммирования ее результатов сохраняем их в промежуточный массив. Потом таким же способом суммируем промежуточный массив.

т.к. мы все потоки SIMD уже задействовали.

Чуть выше ты написал, что суммировать будешь в один поток.

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

Анролл, если дает эффект, то эффект должен быть даже на 4-6 итерациях.

На самом деле там эффект будет сразу же.
Причём на более старых процессорах намного сильнее заметен.

// Вообще, с emulek спорить нет смысла. Он уже не в первой теме бред несёт.

devl547 ★★★★★
()

Не компилируется. ;(

-> % gcc-4.8 memad_bench.c -Ofast -march=native -lgomp -fwhole-program -Wall -Wextra -o c_memadd_bench && ./c_memadd_bench
memad_bench.c: In function 'fmaadd':
memad_bench.c:71:3: warning: implicit declaration of function '_mm256_fmadd_ps' [-Wimplicit-function-declaration]
   return _mm256_fmadd_ps(_mm256_set1_ps(1.), a, b);
   ^
memad_bench.c:71:3: error: incompatible types when returning type 'int' but '__v8sf' was expected
memad_bench.c: In function 'fma_10way_finality':
memad_bench.c:103:5: warning: implicit declaration of function 'error_at_line' [-Wimplicit-function-declaration]
     default: error_at_line(-1, 0, __FILE__, __LINE__, «bad_aligned %llu», end - it);
     ^
memad_bench.c: In function 'fmaadd':
memad_bench.c:72:1: warning: control reaches end of non-void function [-Wreturn-type]
 }
 ^
memad_bench.c: In function 'main':
memad_bench.c:163:1: warning: control reaches end of non-void function [-Wreturn-type]
 }
 ^

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

В тестовых задачах Яндекса при сложении даблов на каждой итерации из сортированного конктейнера берутся два первых элемента (минимальные), суммируются, один из них замещается суммой, другой удаляется. Т.е. порядок надо поддерживать после каждого элементарного суммирования, дабы достичь максимально возможной точности. Как-то так

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

В тестовых задачах Яндекса при сложении даблов [...]

Это ты к чему - к тому, почему анролл не работает, или к хитрому алгоритму суммирования (алгоритм Кэна?), или... ?

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

Ко всему сразу. Как сделать анролл, если хитрый алгоритм суммирования подразумевает, что данные после каждого сложения (= итерации) придется сортировать?

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

Как сделать анролл, если хитрый алгоритм суммирования подразумевает, что данные после каждого сложения (= итерации) придется сортировать?

Для такого алгоритма - естественно, никак. Я предполагаю каскдное суммирование: http://en.wikipedia.org/wiki/Pairwise_summation

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

Как сделать анролл, если хитрый алгоритм суммирования подразумевает, что данные после каждого сложения (= итерации) придется сортировать?

получив очередную сумму и убедившись, что она больше «ближайших» 2N чисел - можешь спокойно «анроллить» сложение N пар с последующей сортировкой получившихся сумм и оставшихся чисел.

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

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

yyk ★★★★★
()

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

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

Я тоже вот обратил внимание что как-то подозрительно, но решил ничего не писать, так как в С++ я не эксперт

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

Это ICC

Если верить первым строкам искодников, это GCC. Но он точно новее того, что у меня в Wheezy %)

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

Хотя, gcc тоже умеет, по ходу.

Угу, и автор использовал GCC.

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

«Рассортирует»? Ты говоришь о каскадном суммировании или о чем?

о том, что числа нельзя складывать как попало. Если у тебя есть числа 1,2,100,200,10000,20000, то складывать их надо так:

1+2
100+200
10000+20000
а иначе у тебя большое число поглотит меньшее.

Как видишь, этот «анролл» не нужен тупо потому, что он УЖЕ применяется, т.к. группы чисел и так складывают одновременно в SIMD. По большому счёту, Intel и ввела эту вашу SIMD для данных целей, т.к. числа FP нельзя складывать как попало, а надо ранжировать, и проводить операцию отдельно над каждой группой.

Чуть выше ты написал, что суммировать будешь в один поток.

да, 1 поток на одну группу. А групп 4 или больше(если больше, их придётся считать по очереди на 128и битном SIMD).

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

возьми калькулятор, и прибавь к π 1`000`000`000. А потом вычти 1`000`000`000. Получится 0. Откуда вывод: π=0. Ну вот наш ТС такой хренью и занимается.

Ещё раз: float'ы нельзя складывать не глядя. Точнее можно, если ты дрочишь на ГФлопсы, а результат тебя не волнует.

А если на эти float'ы поглядеть, и складывать их как надо, то они и так складываются группами по несколько чисел отдельно. Большие с большими, маленькие с маленькими. Что очень удобно делать на SIMD.

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

float'ы нельзя складывать не глядя.

В большинстве случаев на это можно положить болт.

прибавь к π 1`000`000`000. А потом вычти 1`000`000`000. Получится 0. Откуда вывод: π=0.

Отсюда вывод - при работе с большими числами на мелочь в что-то там после запятой можно наплевать.

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

данные после каждого сложения (= итерации) придется сортировать

для float'ов сортировать очень просто, т.к. достаточно взять 256 корзинок на каждый порядок, и использовать http://en.wikipedia.org/wiki/Radix_sort Т.о. каждый новый float ты можешь засунуть в свою корзинку за O(1), или за несколько тактов.

Естественно «анрол» приткнуть будет некуда, т.к. у нас и так 256 потоков в общем случае.

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

Отсюда вывод - при работе с большими числами на мелочь в что-то там после запятой можно наплевать.

При работе с действительно большими числами, особенно как положительными, так и отрицательными, особенно в большом количестве, порядок ошибки может достигать тысяч (а не чего-то там после запятой).

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

В большинстве случаев на это можно положить болт.

Увы. Если речь идёт про массив из 32768 float'ов — нельзя.

Отсюда вывод - при работе с большими числами на мелочь в что-то там после запятой можно наплевать.

тогда зачем вообще складывать Over9000 чисел, если тебе на них наплевать? Выбери максимум, и все дела.

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

Отсюда вывод - при работе с большими числами на мелочь в что-то там после запятой можно наплевать.

А если таких мелочей пару лярдов? :) Может хватит уже «абсолютину» гнать?

yyk ★★★★★
()

Да, это очень хорошо. А теперь сделай такую же оптимизацию для остальных 19 архитектур под которые выпускаются современные ОС.

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

А если таких мелочей пару лярдов? :)

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

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

мой ответ был на конкретные слова без привязки к сабжу

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

И? Много сегодня пишут числодробилок на голом CPU?

Ну я даже не знаю как тебе объснить - все, кроме полигонального граффона и там ещё чего-то.

С чего ты это взял?

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

Примеры из libc приведешь? Или libc тоже пхписты писали?

В этом и суть, суть пхписта - ты кукарекаешь, но даже не знаешь очем. Я надеюсь ты понимаешь, что libc - это описание, а не реализации. Погугли.

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

Ты мне решил рассказать про флоат? Даниужели. И что нового ты мне открыл?

Ну сложил ты 1000чисел порядка 123., 1к чисел порядка 0.00000123 и 1к чисел порядка 0.000000000000123. И что ты получил - правильно жопу в любом случае.

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

Точность твоего выхлопа тоже ниже плинтуса.

PS: когда ты складываешь два float'а, ты получаешь 2⁻²³ бит ☣(в лучшем случае). Внимание, вопрос: сколько точных битов ты получишь после своего сложения в лучшем случае?

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

Ты хочешь со мною посоревноваться в точном и быстром сложении - дерзай.

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

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

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

Ну сложил ты 1000чисел порядка 123., 1к чисел порядка 0.00000123 и 1к чисел порядка 0.000000000000123. И что ты получил - правильно жопу в любом случае.

на практике часто бывает 100500 чисел 0.0001, и пара чисел 5. У меня получится 20, а у тебя 10. Есть разница?

Ты хочешь со мною посоревноваться в точном и быстром сложении - дерзай.

тебе повторить знакопеременный ряд, который даёт ln(2)?

вот и считай.

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

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

Как я люблю анализ нулей.

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

Пример мне сумматора - давай посоревнуемся. Выкатывай свой «полноценный суматор».

Но если не группировать данные, то числа получаются разными, что ведёт к катастрофической потери точности. Причём нет никакой принципиальной разницы, float это, или double.

Очередная бредня. Ты где этих мифов и легенд начитался? Я тебе выше привел пример.

Ну грубо говоря, если у тебя есть Over9000 маленьких чисел, и одно большое, которое весит ⅒ суммы всех маленьких, то результат на 90% зависит от маленьких. Однако, когда ТС начнёт складывать всё в куче, большое число поглотит все Over9000 маленьких, и ошибка будет около 900% (sic! девятьсот процентов). Зачем нужен _такой_ результат?

Чего ты несёшь, какой поглотит - ещё раз для ударенных. Пример этих чисел пожалуста и какой такйо результат будет и что такое 900% - примеры мне, пж.

Я конечно понимаю, что ты обделался и примеров не будет, но всё же обделывайся не так явно.

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

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

Нука, нука - что за «штатные функции в стандартной библиотеке», как так сливаю - мне примеры можно?

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

все, кроме полигонального граффона и там ещё чего-то.

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

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

Пока что выходит так, что ты тут один д'Артаньян, а все остальные вокруг - сплошные пхписты. Не наводит ни на какие мысли?

ты кукарекаешь, но даже не знаешь очем.

Я-то прекрасно знаю, о чем пишу. А вот ты, походу, не совсем. И еще хамишь старшим. Не стыдно так себя вести?
В общем, с тобой уже все ясно: юный и дерзкий, пороху не нюхавший. Подрастешь, может и выйдет из тебя что нибудь толковое, а пока что говорить с тобой не о чем.

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