LINUX.ORG.RU

Ускорить функцию

 ,


1

2

Привет, ЛОР.

Оптимизирую функцию. Удалось снизить время выполнения 100 000 000 итераций с 58 секунд до 32. Дальше пока не лезет. Глянете? Может кто еще какой-нибудь финт сможет предложить: http://paste.org.ru/?iv1p2w

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

Математику знать надо!

Открываем картинку из справочника по геометрии: http://www.calctool.org/CALC/math/trigonometry/sincostan.png

sin α равен отношению катета O к гипотенузе H. Теперь накладывай картинку на ось координат, так, чтобы точка line.p1 была у тебя в начале координат (на одном конце гипотенузы), а точка line.p2 — на другом конце гипотенузы. Катет O у тебя будет численно равен значению Y точки line.p2.

С учетом, что у нас другая система коодинат, сдвигаем в нужную: Y = line.p2.y - line.p1.y.

Итак, sin α у нас равен Y / H.

Смотрим на наши формулы в программе, видим, что H нам считать не обязательно. Сотношение синуса и косинуса не меняется от значения H. Поэтому для простоты H заменяем на 1.

Для косинуса рассуждения аналогичны.

Итого, sin α = line.p2.y - line.p1.y, cos α = line.p2.x - line.p1.x. Значения, как Manhunt и сказал, денормализованы, но для нас это не важно.

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

1. Любые два действительных числа S и C, если только S*S+C*C==1, являются соответственно синусом и косинусом какого-то угла L. Это факт из тригонометрии. Если хочется его прочувствовать и осознать, то это куда-то в учебники/задачники по тригонометрии.

2. Я очень небрежно написал «cos(L)=AB.x, sin(L)=-AB.y». Если писать аккуратно, то нужно сперва ввести нормирующий множитель N=1/sqrt(AB.x*AB.x+AB.y*AB.y), и затем С=AB.x*N, S=-AB.y*N. Теперь можно взять и расписать на бумажке, чему равно S*S+C*C: получится единица. То есть это правильные синус и косинус из пункта 1. Дальше можно протащить нормирующий множитель N через все наши выкладки, и увидеть, что в конце концов он всё равно сокращается. Ну и отдельно нужно рассмотреть, что с нашим кодом происходит в случае AB.x*AB.x+AB.y*AB.y==0, когда значение N не определено и, формально, никаких синусов и косинусов не получается.

3. Нам нужно, чтобы отрезок AB лёг строго на ось OX. Подставляем наши S и C в формулу для поворота AB, и сморим, какие у AB будут новые координаты:

x_new =   AB.x * AB.x*N + AB.y * AB.y*N
y_new = - AB.x * AB.y*N + AB.y * AB.x*N

Видно, что y_new == 0. То есть после поворота отрезок AB лежит на оси OX. Значит, такой выбор S и C нас вполне устроит.

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

О, а вот и ыксперт подтянулся.

Лолчто?

Операции с int64 жрут гораздо больше времени чем операции с int32. Так понятнее, о, наш ыкспертный друг?

int64: 100 000 000 cycle took 34.813816 s
int32: 100 000 000 cycle took 31.315514 s
sambist ★★
() автор топика
Ответ на: комментарий от sambist

Рили? Почему-то никто кроме полезности об этом даже не подозревал?

Так понятнее, о, наш ыкспертный друг?

И что я из этого должен увидеть? Кривость твоих ручёнок?

И да, какие-такие «операции»?

Выкатывай код.

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

Выкатывай код.

Ну если ты не умеешь читать тред, то кто ж тебе виноват? Можешь попробовать еще по ссылке кликнуть.

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

И да, какие-такие «операции»?

На делении и умножении uint64_t всасывать начинает.

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

ну так по мелочи добавь libstd.h, тебе жалко что ли? Царюльке некогда - он в образе. Даже циферки у него сошлись :) Че уж там какие-то заголовки.

anonymous
()

похоже superhackkiller1997 вернулся :-D

anonymous
()

Научите меня правильно пользовать sse. Последний вариант медленее того, что в лоб приблизительно на 10%. Я правильно понимаю, что там загрузка выгрузка убивает весь профит? И да, первый вариант вообще делает хрен знает что. Выгружает числа из xmms в обычные регистры и там и перемножает/прибалвяет/отнимает, после чего загоняет обратно в xmms. Я там понимаю загвоздка в каком то условии, с которым gcc с vector_size не может полноценно юзать sse?

И ещё, у шланга быстрее получается. Хехе. Почему не знаю, дисасемблер пока не копал.

Дискас?

#include <stdio.h>
#include <stdlib.h>

#if 0


typedef int v2 __attribute__((vector_size(8)));

typedef union {
  v2 v;
  int i[2];
} vv2;

short grad(vv2 *a, vv2 *b, vv2 *t)
{
  vv2 ab; ab.v = b->v - a->v;
  vv2 ab_sqr; ab_sqr.v = ab.v * ab.v;
  vv2 t2; t2.v = t->v - a->v;
  vv2 t3; t3.v = t2.v * ab.v;

  int new_ab_x = ab_sqr.i[0] + ab_sqr.i[1];
  int new_at_x = t3.i[0]  + t3.i[1];

  if(new_at_x <= 0) return 0;
  if(new_at_x >= new_ab_x) return 255;
  return 255 * new_at_x / new_ab_x;
}

int f(int i)
{
  printf("1\n");
  int ret= 0;
  while (i--> 0) {
    vv2 a; a.v = (v2){rand(), rand()};
    vv2 b; b.v = (v2){rand(), rand()};
    vv2 t; t.v = (v2){rand(), rand()};
    ret += grad(&a, &b, &t);
    //printf("%d\n", r);
  }
  return ret;
}

#elif 0

struct point
{
  int x;
  int y;
};

short grad(struct point *a, struct point *b, struct point *t)
{
  int ab_x = b->x - a->x; //0
  int ab_y = b->y - a->y; //3
  int new_ab_x = ab_x * ab_x + ab_y * ab_y; //9
  int new_at_x = (t->x - a->x) * ab_x + (t->y - a->y) * ab_y; //3
  if(new_at_x <= 0) return 0;
  if(new_at_x >= new_ab_x) return 255;
  return 255 * new_at_x / new_ab_x;
}

int f(int i)
{
  printf("0\n");
  int ret  =0;
  while (i--> 0) {
    struct point a = {ret + 1, ret + ret + 10};
    struct point b = {ret + 2, ret + ret + 20};
    struct point t = {ret + 3, ret + ret + 30};
    ret += grad(&a, &b, &t);
  }
  return ret;
}


#else

#include <emmintrin.h>

#define AL16 __attribute__((aligned(16)))

struct Point
{
  int x;
  int y;
};

short grad(__m128i a, __m128i b, __m128i t)
{
  /*int av[] AL16 = {_a->x, 0, _a->y, 0};
  int bv[] AL16 = {_b->x, 0, _b->y, 0};
  int tv[] AL16 = {_t->x, 0, _t->y, 0};

  __m128i a = _mm_load_si128((__m128i *)av);
  __m128i b = _mm_load_si128((__m128i *)bv);
  __m128i t = _mm_load_si128((__m128i *)tv); */

  __m128i ab = _mm_sub_epi32(b, a);
  t = _mm_sub_epi32(t, a);

  __m128i abx = _mm_mul_epu32(ab, ab);
  __m128i abx2 = _mm_shuffle_epi32(abx, _MM_SHUFFLE(1, 0, 3, 2));
  abx = _mm_add_epi32(abx, abx2);

  t = _mm_mul_epu32(t, ab);
  __m128i t2 = _mm_shuffle_epi32(t, _MM_SHUFFLE(1, 0, 3, 2));
  t = _mm_add_epi32(t, t2);

  //int av[4] AL16;
  //int bv[4] AL16;

  //_mm_store_si128((__m128i *)av, abx);
  //_mm_store_si128((__m128i *)bv, t);

  int new_ab_x = abx[0];
  int new_at_x = t[0];
  if (new_at_x <= 0) return 0;
  if (new_at_x >= new_ab_x) return 255;
  return 255 * new_at_x / new_ab_x;
}

int f(int i)
{
  printf("2\n");
  int ret  =0;
  while (i--> 0) {
    /*struct Point a = {rand(), rand()};
    struct Point b = {rand(), rand()};
    struct Point t = {rand(), rand()};*/
      int v1[] = {ret + 1, 0, ret + ret + 10, 0};
      int v2[] = {ret + 2, 0, ret + ret + 20, 0};
      int v3[] = {ret + 3, 0, ret + ret + 30, 0};
    ret += grad(_mm_load_si128((__m128i *)v1),
      _mm_load_si128((__m128i *)v2),
      _mm_load_si128((__m128i *)v3));
  }
  return ret;
}


#endif

int main()
{
  printf("%d\n", f(10000000));
}
nanoolinux ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.