Russian Qt Forum
Ноябрь 22, 2024, 20:23 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 [2]   Вниз
  Печать  
Автор Тема: Вычислить кадр мувика  (Прочитано 19351 раз)
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #15 : Май 25, 2017, 14:43 »

Цитировать
1. uint step - для отрицательных чисел у вас алгоритм вычисляет неправильно(автору не нужно)
Да вроде и с отрицательными работает нормально)

Цитировать
2. при x0 == x1 у вас T == 0 -> %T сгенерирует ошибку и программа упадет без обработчика
Да, согласен)

Цитировать
4. имхо, через деление выражение ((x + step % T) % T) быстрее будет
Не знаю.. думаю сейчас, это больше от компилятора зависит..

Цитировать
5. std::min и max тоже можно убрать повысив производительность, if((sign>0 && currentFrame<x0 ?&& currentFrame>x1) || (sign<0 && currentFrame<x1 ?&& currentFrame>x0)) throw std::logic_error("out of range");
Здесь, думаю, тож спорно в плане производительности.. Я за читабельность в данном случае)
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
deMax
Хакер
*****
Offline Offline

Сообщений: 600



Просмотр профиля
« Ответ #16 : Май 25, 2017, 15:10 »

Да вроде и с отрицательными работает нормально)
9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 10 9 8 7 6 5 6 7 8 9 10 9 8 7 6 5 6 7 8
9 18 17 16 15 14 13 12 11 10 9 18 17 16 15 14 13 12 11 10 9 8 7 6 5 6 7 8 9 10 9 8 7 6 5 6 7 8 9 10
нет ерунда, да еще за диапазон вышла. Но автор сказал не надо, значит uint

Цитировать
Не знаю.. думаю сейчас, это больше от компилятора зависит..
Моя функция 20млн.раз выполняется за 301мс(с поддержкой отрицательного шага 324), а ваша 640.
Возможно лямбда здесь лишняя, кстати зачем она тут?

имхо это сильно быстрее ваших двух остатков от деления(жирная операция)
Код:
    posCurrentFrame -= (posCurrentFrame / sizeWithBack) * sizeWithBack;
    if(posCurrentFrame<0) posCurrentFrame += sizeWithBack; // это для отрицательных шагов(т.е. удалить), т.к. -0.5 округляют не в меньшую сторону, а к нулю(можно floor использовать)

Цитировать
Здесь, думаю, тож спорно в плане производительности.. Я за читабельность в данном случае)
перемудрил:
 if((currentFrame<x0 && currentFrame<x1) || (currentFrame>x1 && currentFrame>x0)) throw std::logic_error("out of range");
но ваше std::min читается получше, хоть и медленнее. хотя, имихо, это условие вообще должно вне функции проверяться, чтобы не терять производительность), т.к. эта функция скорее всего принимает curFrame как свое возвращаемое значение.
« Последнее редактирование: Май 25, 2017, 15:22 от deMax » Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #17 : Май 25, 2017, 15:35 »

Цитировать
нет ерунда, да еще за диапазон вышла.
Я вот на таком тесте
Код
C++ (Qt)
#include <iostream>
#include <random>
#include <cmath>
#include <stdexcept>
 
 
inline int NextFrame_m_ax(int currentFrame, int step, int x0, int x1) throw (std::logic_error)
{
   if ((currentFrame < std::min(x0, x1)) || (currentFrame > std::max(x0, x1)))
       throw std::logic_error("out of range");
 
   if (x0 == x1) return x0;
 
   const int sign = (x1 > x0) ? 1 : -1;
 
   const int T = 2*sign*(x1 - x0);
 
   auto toFrame = [&](int x)->int
   {
       return (x <= T/2) ? (x0 + sign*x) : (sign*(T - x) + x0);
   };
 
   int x = sign*(currentFrame - x0);
 
   return toFrame((x + step % T) % T);
}
 
 
int NextFrame_deMax(int currentFrame, int step, int x0, int x1) {
   int dPosFirst = x1>x0? 1: -1; // направление в первой последовательности
   int size = abs(x1-x0)+1;
 
   int posCurrentFrame = (currentFrame - x0) * dPosFirst;
   if(posCurrentFrame >= size || posCurrentFrame<0) return 0; //TODO error: число не принадлежит последовательности
 
   posCurrentFrame += step; // new Frame;
 
   if(x0 == x1)return x0; // если один кадр
   int sizeWithBack = size*2 - 2; // размер последовательности включая обратную(не правильно считает для одного кадра x0==x1, но этот случай отсекли)
   posCurrentFrame -= (posCurrentFrame / sizeWithBack) * sizeWithBack; // теперь новый кадр будет лежать в диапазоне [0, sizeWithBack), так как данная последовательность повторяется
 
   return posCurrentFrame < size? x0 + posCurrentFrame * dPosFirst:
                                  x0 + (sizeWithBack - posCurrentFrame) * dPosFirst;
}
 
 
int main()
{
   int f0 = 5;
   int f1 = 10;
   int frame = 9;
 
   std::cout << "m_ax \t deMax" << std::endl;
 
   for(int i=-20; i<20; ++i)
   {
       std::cout <<  NextFrame_m_ax(frame, i, f0, f1) << "\t" << NextFrame_deMax(frame, i, f0, f1) << std::endl;
   }
 
   return 0;
}
 
получил следующее:
Код
Bash
m_ax    deMax
9 -1
0 0
1 1
2 2
3 3
4 4
5 5
6 -4
7 -3
8 -2
9 -1
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
10 10
9 9
8 8
7 7
6 6
5 5
6 6
7 7
8 8
9 9
10 10
9 9
8 8
7 7
6 6
5 5
6 6
7 7
8 8
 
т.е. у вас она уходит в отрицательные значения..

Если изменить порядок диапазона:
Код
C++ (Qt)
   int f0 = 10;
   int f1 = 5;
 
то обе реализации выдают ерунду (
Код
Bash
m_ax deMax
9 19
18 18
17 17
16 16
15 15
14 14
13 13
12 12
11 11
10 10
9 19
18 18
17 17
16 16
15 15
14 14
13 13
12 12
11 11
10 10
9 9
8 8
7 7
6 6
5 5
6 6
7 7
8 8
9 9
10 10
9 9
8 8
7 7
6 6
5 5
6 6
7 7
8 8
9 9
10 10
 
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
deMax
Хакер
*****
Offline Offline

Сообщений: 600



Просмотр профиля
« Ответ #18 : Май 25, 2017, 15:58 »

Я написал что добавил строчку, но не выложил код
Код:
inline int NextFrame(int currentFrame, int step, int x0, int x1) {
    int dPosFirst = x1>x0? 1: -1;
    int size = abs(x1-x0)+1;

    int posCurrentFrame = (currentFrame - x0) * dPosFirst;
    if(posCurrentFrame >= size) return 0; //TODO error

    posCurrentFrame += step; // new Frame;
    int sizeWithBack = size*2 - 2;

    posCurrentFrame -= (posCurrentFrame / sizeWithBack) * sizeWithBack;
    if(posCurrentFrame<0) posCurrentFrame += sizeWithBack; // без этой строчки у меня текущий кадр при отрицательном шаге сваливается в отрицательное значение, не из диапазона [0, sizeWithBack) и получается ерунда

    return posCurrentFrame < size? x0 + posCurrentFrame * dPosFirst:
                                   x0 + (sizeWithBack - posCurrentFrame) * dPosFirst;
}
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #19 : Май 25, 2017, 16:00 »

Цитировать
Моя функция 20млн.раз выполняется за 301мс(с поддержкой отрицательного шага 324), а ваша 640.
У меня другие результаты - противоположные..
Может вы её в холостую запускали?

Мой тест приаттачен.
компилятор: gcc 4.9.2
« Последнее редактирование: Май 25, 2017, 16:05 от m_ax » Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #20 : Май 25, 2017, 19:12 »

Цитировать
У меня другие результаты - противоположные..
Сделал вашу функцию инлайн и результаты примерно выровнялись:
Код
Bash
m_ax, total time: 296
deMax, total time: 305
 
m_ax, total time: 296
deMax, total time: 304
 
m_ax, total time: 297
deMax, total time: 303
 
(результаты после 3-х запусков), что говорит о том, что компилятор не видит особой разницы между
Код
C++ (Qt)
posCurrentFrame -= (posCurrentFrame / sizeWithBack) * sizeWithBack;
if(posCurrentFrame<0) posCurrentFrame += sizeWithBack;
 
и этим
Код
C++ (Qt)
return toFrame((x + step % T) % T);
 


 
« Последнее редактирование: Май 25, 2017, 19:18 от m_ax » Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #21 : Май 31, 2017, 10:46 »

Простите мою навязчивость но все же
но хочу обратить Ваше внимание на такую деталь
5, 6, 7, 8, 9, 10, 9, 8, 7, 6, 5, 6...    
...
NextFrame(9, 1) = 10
NextFrame(9, 2) = 9
А "от какого" 9? Не вижу как это учтено в Ваших исходниках.
По-прежнему не вижу где это, please "ткните носиком".   
Записан
deMax
Хакер
*****
Offline Offline

Сообщений: 600



Просмотр профиля
« Ответ #22 : Июнь 01, 2017, 09:39 »

m_ax,
Цитировать
Сделал вашу функцию инлайн и результаты примерно выровнялись:
если удалить "if(posCurrentFrame<0) posCurrentFrame += sizeWithBack;" (у вас то отрицательные позиции не работают), то еще одинаковей будет.

Igors
Цитировать
А "от какого" 9? Не вижу как это учтено в Ваших исходниках.
вроде отвечал уже:
[5 6 7 8 9 10] 9 8 7 6 5 6 7 ... - из основного диапазона (в скобках []) 9-ку брал, можно аргумент ввести если из следующего перевернутого брать
if(isReverseFind==true) posCurrentFrame = sizeWithBack - posCurrentFrame;

если нужно хранить позицию девятки (isReverse = false от x0 к x1; true от x1 к x0)
Код:
inline int NextFrame(int currentFrame, uint step, int x0, int x1, bool &isReverse) {
    int dPosFirst = x1>x0? 1: -1;
    int size = abs(x1-x0)+1;

    int posCurrentFrame = (currentFrame - x0) * dPosFirst;
    if(posCurrentFrame >= size) return 0; //TODO error
    if(isReverseFind == true) posCurrentFrame = sizeWithBack - posCurrentFrame;

    posCurrentFrame += step; // new Frame;
    int sizeWithBack = size*2 - 2;

    posCurrentFrame -= (posCurrentFrame / sizeWithBack) * sizeWithBack;
//    if(posCurrentFrame<0) posCurrentFrame += sizeWithBack; // без этой строчки у меня текущий кадр при отрицательном шаге сваливается в отрицательное значение, не из диапазона [0, sizeWithBack) и получается ерунда
    isReverse = posCurrentFrame >= size;
    return posCurrentFrame < size? x0 + posCurrentFrame * dPosFirst:
                                   x0 + (sizeWithBack - posCurrentFrame) * dPosFirst;
}

но здесь итератор просится, чем эта функция с кучей параметров
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #23 : Июнь 01, 2017, 10:36 »

вроде отвечал уже:

...можно аргумент ввести если из следующего перевернутого брать

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

Код:
inline int NextFrame(int currentFrame, uint step, int x0, int x1, bool &isReverse) {
    int dPosFirst = x1>x0? 1: -1;
    int size = abs(x1-x0)+1;

    int posCurrentFrame = (currentFrame - x0) * dPosFirst;
    if(posCurrentFrame >= size) return 0; //TODO error
    if(isReverseFind == true) posCurrentFrame = sizeWithBack - posCurrentFrame;

    posCurrentFrame += step; // new Frame;
    int sizeWithBack = size*2 - 2;

    posCurrentFrame -= (posCurrentFrame / sizeWithBack) * sizeWithBack;
//    if(posCurrentFrame<0) posCurrentFrame += sizeWithBack; // без этой строчки у меня текущий кадр при отрицательном шаге сваливается в отрицательное значение, не из диапазона [0, sizeWithBack) и получается ерунда
    isReverse = posCurrentFrame >= size;
    return posCurrentFrame < size? x0 + posCurrentFrame * dPosFirst:
                                   x0 + (sizeWithBack - posCurrentFrame) * dPosFirst;
}
Мда, ну как-то "чижело"  Улыбающийся (хотя может и правильно).

но здесь итератор просится, чем эта функция с кучей параметров
И если поступило указание "на 100 собак вперед" - то мы 100 раз зовем ++it, расписываясь в том что "просто посчитать" не умеем. Ну как-то неудобно  Улыбающийся

Да, а мой вариант чем плох? Если нужно и отрицательное смещение (мне нет), то может проще всего свести его к положительному
Код
C++ (Qt)
period = qAbs(R[1] - R[0]) * 2 + 1;
step = (step % period) + period;
В общем, если есть желание - попинайте меня вместо m_ax  Улыбающийся Спасибо
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #24 : Июнь 01, 2017, 12:43 »

Цитировать
И если поступило указание "на 100 собак вперед" - то мы 100 раз зовем ++it, расписываясь в том что "просто посчитать" не умеем. Ну как-то неудобно
И в чём проблема?
Код
C++ (Qt)
it += 100;
 
Это random access итератор.
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #25 : Июнь 01, 2017, 14:19 »

Код
C++ (Qt)
it += 100;
 
Это random access итератор.
Тогда в чем выйгрыш? Все тоже писать только еще оформлять какой-то дурацкий итератор
Записан
deMax
Хакер
*****
Offline Offline

Сообщений: 600



Просмотр профиля
« Ответ #26 : Июнь 01, 2017, 14:44 »

Итератор будет внутри хранить текущую позицию(а не номер фрейма), у него будет расчитан размер...
Вроде все тоже самое что и функция, только первая часть будет вызвана один раз в конструкторе и наружу не лезет всякая ерунда типа reverse, и при вызове функции не инлайн один аргумент - смещение (в стек будет лишний мусор копироваться). Хотя при времени выполнения функции 300/20е6 секунды, может и не стоит этим заниматься.

p.s. можете назвать его по другому, т.к. у вас в отличие от полноценного итератора будет только конструктор и метод сдвига.

как то так:
Код:
class NextFrame
{
    int x0, x1;
    int posCurrentFrame, dPosFirst, size, sizeWithBack;
    bool isReverse;
public:
    NextFrame(int currentFrame, int x0, int x1, bool isReverse): x0(x0), x1(x1), isReverse(isReverse) {
        dPosFirst = x1>x0? 1: -1;
        size = abs(x1-x0)+1;
        sizeWithBack = size*2 - 2;

        posCurrentFrame = (currentFrame - x0) * dPosFirst;
        if(posCurrentFrame >= size) return; //TODO error
        if(isReverse == true) posCurrentFrame = sizeWithBack - posCurrentFrame; }
    int operator+=(uint step)
    {
        posCurrentFrame += step; // new Frame;

        posCurrentFrame -= (posCurrentFrame / sizeWithBack) * sizeWithBack;
        //    if(posCurrentFrame<0) posCurrentFrame += sizeWithBack; // без этой строчки у меня текущий кадр при отрицательном шаге сваливается в отрицательное значение, не из диапазона [0, sizeWithBack) и получается ерунда
        isReverse = posCurrentFrame >= size;
        return posCurrentFrame < size? x0 + posCurrentFrame * dPosFirst:
                                       x0 + (sizeWithBack - posCurrentFrame) * dPosFirst;
    }
};

...

//вроде работает :)
    NextFrame nf(9, 5, 10);
    for(int i=0; i<20; ++i)
        qDebug() << (nf+=1);

Это на скорую руку, если есть желание можно проверить производительность, хотя за счет вызова функции наверное уменьшиться.
« Последнее редактирование: Июнь 01, 2017, 15:06 от deMax » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #27 : Июнь 04, 2017, 10:15 »

Итератор будет внутри хранить текущую позицию(а не номер фрейма), у него будет расчитан размер...
Понял - с идеей инкапсуляции. По-моему особого смысла в ней здесь нет, больше "обвязок" придется писать (а потом читать). Хотя конечно - дело вкуса.

..и при вызове функции не инлайн один аргумент - смещение (в стек будет лишний мусор копироваться). Хотя при времени выполнения функции 300/20е6 секунды, может и не стоит этим заниматься.
...
...если есть желание можно проверить производительность, хотя за счет вызова функции наверное уменьшиться.
Я тоже за производительность, но уверен - это не то место где надо оптимизировать  Улыбающийся
Записан
Страниц: 1 [2]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.23 секунд. Запросов: 23.