LINUX.ORG.RU

ускоренная математика (вычисление atan2, sqrt) c++

 ,


0

2

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

П.С. https://github.com/theGABS/lsdDraw вот проект если интересно.

★★★

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

Stil, проблемка в том что у меня это вычисляется для пикселей, коих на моем мониторе 2 миллиона. Все будет нормально? Мне её делать вручную(создать массив куда посчитать значения для каждого пикселя) или есть встроенные методы для любой функции? (Qt)

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

И atan, и sqrt — функции с одним аргументом. При чём здесь твои миллионы пикселей?)

Я бы начал враппера над нужными функциями и хешем, раз у тебя Qt. Ты, кстати, уверен, что тормоза у тебя там?

Stil ★★★★★
()

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

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

. Ты, кстати, уверен, что тормоза у тебя там?

Думаю да. atan2, два аргумента.

atan.resize(height());
    for(int y = 0; y < height(); y++){
        atan[y].resize(width());
        for(int x = 0; x < width(); x++){
            atan[y][x] = atan2(centerY - y, centerX - x);
        }
    }

получил прирост производительности на 50%

abs ★★★
() автор топика

в либах апачевских есть быстрый арктангенс но это для java

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

если точность не нужна то можно подобрать подходящий полином

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

если использовать одномерный массив то операция resize будет занимать меньше времени

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

abs ★★★
() автор топика

Можно приближенно считать, простыми операциями, если это не принципиально

yoghurt ★★★★★
()

ко всему прочему

float fast_atan2(float y, float x)
{
    const float ONEQTR_PI = M_PI / 4.0;
    const float THRQTR_PI = 3.0 * M_PI / 4.0;
    float r, angle, abs_y = fabs(y) + 1e-10f;
    if (x < 0.0f) {
        r = (x + abs_y) / (abs_y - x);
        angle = THRQTR_PI;
    } else {
        r = (x - abs_y) / (x + abs_y);
        angle = ONEQTR_PI;
    }
    angle += (0.1963f * r * r - 0.9817f) * r;
    return (y < 0.0f) ? -angle : angle;
}
mix_mix ★★★★★
()
Ответ на: комментарий от buddhist

Считай по таблице.

И если таблица не влезет в кеш, то получать проседания из-за cache-miss.

andreyu ★★★★★
()
  1. Заполнять image стоит не в paintEvent, а в отдельном потоке.
  2. Воспользуйся OpenMP для распараллеливания первого цикла
  3. Сгенерированные изображения можно и кешировать.
AlexVR ★★★★★
()
Ответ на: комментарий от AlexVR

Сгенерированные изображения можно и кешировать.

Так у меня динамическая картинка. в функциях вычисления цвета пикселя фигурирует переменная frame(кадр).

Воспользуйся OpenMP для распараллеливания первого цикла

Думал об этом, также думал это на openGL перенести.

Заполнять image стоит не в paintEvent, а в отдельном потоке.

А почему так?

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

«Delay your variable definitions until as late as possible, if they're only needed inside of an if statement for example then declare them inside of the if statement's body, this way, if the if statement evaluates to false then the objects are not created, saving time and memory. Scott Meyers backs me up, that alone is enough of a reason to take my advice. God I love Scott Meyers.» (c)

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

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

AlexVR ★★★★★
()

1. Нужно убедиться что тормозит именно эта часть

2. Можно попросить считать быстрее.

В gcc можно сделать `-O1 -ffast-math', тогда вызовы:

call	atan2f
call	sqrt

заменятся на операции:

fpatan
fsqrt
alexanius ★★
()
Ответ на: комментарий от hotpil

Для примитивных типов разницы нет, компилятор соптимизирует - объявление в цикле и за циклом даст одинаковый результат.

Зато если объявлять внутри цикла, то область видимости не засоряется.

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

А, ты об этом. Стремно да, но компилятор все равно оптимизирует.

unt1tled ★★★★
()

Отличная задача для вычисления на видяхе. А если надо именно на проце - то, как уже сказали, OpenMP плюс свой собственный atan2 полиномом Чебышева - примерно как тут в разделе reference implementation, но коэффициенты можно свои посчитать если не лень (это сложно) или нагуглить готовые - например, здесь есть.

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

Быстрее решения, предложенного mix_mix, трудно найти. Там вообще нет циклов.

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

А я и сейчас вменяемый. Просто дофига бандеровщины на ЛОРе последнее время пасется. Даже среди модераторов!

Лучше бы выгнали шому из модераторов и вернули доктора синуса!

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

Хорошим стилем было бы использовать fabsf, да. Но по факту, если считается на FPU, что уже редкость, то там один хрен расширение числа до 80 бит, а если abs на SSE, то там тупо сгенерённой маской верхний бит снимается.

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

В принципе допускаю, что компилятор мог замедлить исполнение такой заменой, но реально нужно по факту смотреть что быстрее будет - call в цикле или fpatan.

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

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

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

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

IEEE 754 везде одинаковый, самый быстрый abs всегда сбросом последнего бита будет :3

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

Если можно заменить angle*dist*0.01 в синусе на просто angle, то atan2 можно выкинуть.

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

сперва залогинься, а потом тявкай :D

anonymous
()

Оооох, и зачем я только попробовал собрать проект...

1. Чем Вы его так собираете, что у вас -std=c++11 по дефолту включён? Мне, например, руками пришлось его в .pro дописывать

2. У меня Qt ругнулось что нет никакого `QImage::Format_RGBA8888', пришлось менять `QImage::Format_RGB888'.

После этого собралось. Нооо:

$ gdb ./lsdDraw
(gdb) r
Starting program: /home/alex/test/lsdDraw/bin/lsdDraw 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
0x0000000000402bde in Widget::Widget(QWidget*) ()

Дальше разбирать не буду. Ну и оформление, конечно, жесть - стиль кодирования отсутствует, исходники прямо в папке с проектом. В общем даже не посмотришь что там реально происходит.

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

Values Format_RGBX8888, Format_RGBA8888 and Format_RGBA8888_Premultiplied were added in Qt 5.2

Как бы можно пометить, что требуется именно 5-ая, или проверку при сборке сделать. Четвёртая ветка всё ещё по дефолту в дистрибутивы ставится.

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

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

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

Чем тебя КОИ8 в качестве локали не устраивает? Отсутствием геморроя, связанного с тем, что 1 байт != 1 символ?

Ты еще предложи systemd вместо нормальной системы инициализации использовать,

Ліл.

хохлище!

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

Отсутствием геморроя, связанного с тем, что 1 байт != 1 символ?

Те едди сидит на кои8 потому что у него геморрой?

хохлище

Лентой с утра обвязался уже?

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

Так у меня динамическая картинка. в функциях вычисления цвета пикселя фигурирует переменная frame(кадр).

           float angle = atan2(HEIGHT/2 - j, WIDTH/2 - i);
            float dist =((HEIGHT/2 - j)*(HEIGHT/2 - j) + (WIDTH/2 - i)*(WIDTH/2 - i));

это таблица. Создаёшь и заполняешь 2 таблицы angle и dist, при ресайзе перезаполняешь.

Я тут попробовал на флоатах 1920*1080@120+фпс на ведро, теоретически можно 300, только толку - оно всё уплывает и нихрена не работает правильно.

Попробуй сделать так, чтобы был чисто флоат. Чиселки писать с суфиксом f, т.е. 1.f, 100.f, 0.01f, функции тоже - sinf/cosf/sqrtf.

Думал об этом, также думал это на openGL перенести.

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

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

только толку - оно всё уплывает и нихрена не работает правильно

Так и должно быть поидеи.

опробуй сделать так, чтобы был чисто флоат.

Да, попробую, спасибо. Мне то точность там вообще не важна(думаю что не важна, посмотрим как поменяется картинка свиду)

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

Я себе для вычисления преобразования Хафа вот так вот табличку синусов-косинусов заполнял (но R вычислял, чтобы сильно много памяти не засирать, хотя при желании можно и R табулировать).

Может поможет?

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

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

Все современные видеокарты умеют double, соответственно, и CUDA уже давно с double работать умеет.

Это со старыми проблемы были (скажем, у меня все видюхи старые, поэтому приходилось все на float'ах считать, потому как double только «софтовый» получался).

anonymous
()

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

А если еще и зеркалируешь относительно 45°, то в 8 раз!

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

Все современные видеокарты умеют double, соответственно, и CUDA уже давно с double работать умеет.

Правильно - умеет, только производительность на уровне штеуда, если это не квадра. Зачем он такой дабл нужен?

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