Извините, ничего не найдено.

Не расстраивайся! Лучше выпей чайку!
Регистрация
Справка
Календарь

Вернуться   forum.boolean.name > Программирование в широком смысле слова > Алгоритмика

Алгоритмика Об алгоритмах вообще; методы, обсуждения способов решения

Ответ
 
Опции темы
Старый 04.09.2006, 18:48   #1
SubZer0
Администратор
 
Аватар для SubZer0
 
Регистрация: 03.09.2005
Сообщений: 2,408
Написано 301 полезных сообщений
(для 996 пользователей)
Радость ATAN2 своими руками

Привет всем! вот наконец я и добрался рассказать как мучался с такой вещью в JAVAME без матлиб и т.п.

для чего такая байда нужна? обычно нужно чтобы объект научился "смотреть" на другой...

заключается сия функция в расчете углов по двум координатам (а-ля угол вектора)

покопался в нете, нарыл формулу по которой раскладывается атан: atn=32*x*x + 9*y*y;

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

так! где я там остановился... ага... атан, мать его! ну короче мучались мы поисками мучались, нифига не нашли, и PAX замутил код:
 public float atan2(float x, float y) {
      float atn,atn1;
      atn1=32*x*x + 9*y*y;
      if (atn1==0) {//если угол перпендикулярен оси х
        if (x>0) {return 90;} else{ return 270; }
      }
          atn=32*(x*y)/atn1;
      if (x>=0) {
        if (y>=0){
          return atn;//первая четверть
        }else{
          return 360-atn;//четвертая четверть
        }
      }else{
        if (y>=0){
          return 90+atn;//вторая четверть
        }else{
          return 270-atn;//третья четверть
        }
      }
    }
но меня это все не устраивало... казалось мне, что можно более простой вариант придумать... тем более что у меня в игре не 360 углов а всего 16... этот код еще преобразовывать надо было бы...

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

итак:

сначала рисунок:


пестровато конечно, но попробую объяснить всю суть моей затеи...

по прямой OY координата Y равна нулю, точно также и по ОХ. По синей прямой кордината X будет всегда равна Y... уже половину углов можно описать простейшими условиями, и без вычислений... Но это всеголишь 8 углов... а у меня 16... и я придумал такую весчъ!

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

для угла 45 градусов результат будет 1, для угла в 22.5 градуса высчитывается по формуле cos(22,5)/sin(22,5), и все это равно 2,414213562373... теперь мы точно можем сказать, что если результат деления одной координаты на другую получился в пределах от 1 до 2,41, то нужно повергуться на угол гдето между двойкой и тройкой!

но это маленько не то, что нам было нужно... нам нужно знать примерный угол "3"! для этого поделим секторы между (2 и 3) и (3 и 4) еще пополам... таким образом у нас получились лучи расположенные под углами 11.5 и 33.75... высчитаем у них результаты деления одной координаты на другую...

cos(11,25)/sin(11,25)*=*5,027339492126
cos(33,75)/sin(33,75)*=*1,496605762665

вот теперь то, что надо! теперь если результат деления одной координаты на другую будет больше чем 5, то это будет угол 4 (красный сектор), если от 1.49 до 5 то угол 3 (зеленый сектор), а если меньше 1.49, то угол 2...

и такими темпами есь круг... итого требудется всего одно деление и условия (которые обрабатываются значительно быстрее)...

итого: надо выбрать четверть, потом восьмую часть (путем сравнения координат кака больше) и поделить координаты!

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

                        xp=PositionX-PositionX1; 
                        yp=PositionY-PositionY1;
                        
                        xp1=xp; if (xp1<0) xp1=-xp1;
                        yp1=yp; if (yp1<0) yp1=-yp1;
                        
                        if (xp>0) {
                            if (yp>0) {
                                if (xp1>yp1) {
                                    if (yp1==0) angle=12; else {
                                        j=(xp1*16)/yp1;
                                        if (j>=80) angle=12;
                                        if (j<80 && j>=24) angle=13;
                                        if (j<24) angle=14;
                                    }
                                } else {
                                    if (xp1==0) angle=0; else {
                                        j=(yp1*16)/xp1;
                                        if (j>=80) angle=0;
                                        if (j<80 && j>=24) angle=15;
                                        if (j<24) angle=14;
                                    }
                                }
                            } else {
                                if (xp1>yp1) {
                                    if (yp1==0) angle=12; else {
                                        j=(xp1*16)/yp1;
                                        if (j>=80) angle=12;
                                        if (j<80 && j>=24) angle=11;
                                        if (j<24) angle=10;
                                    }
                                } else {
                                    if (xp1==0) angle=8; else {
                                        j=(yp1*16)/xp1;
                                        if (j>=80) angle=8;
                                        if (j<80 && j>=24) angle=9;
                                        if (j<24) angle=10;
                                    }
                                }
                            }
                        } else {
                            if (yp>0) {
                                if (xp1>yp1) {
                                    if (yp1==0) angle=4; else {
                                        j=(xp1*16)/yp1;
                                        if (j>=80) angle=4;
                                        if (j<80 && j>=24) angle=3;
                                        if (j<24) angle=2;
                                    }
                                } else {
                                    if (xp1==0) angle=0; else {
                                        j=(yp1*16)/xp1;
                                        if (j>=80) angle=0;
                                        if (j<80 && j>=24) angle=1;
                                        if (j<24) angle=2;
                                    }
                                }
                            } else {
                                if (xp1>yp1) {
                                    if (yp1==0) angle=4; else {
                                        j=(xp1*16)/yp1;
                                        if (j>=80) angle=4;
                                        if (j<80 && j>=24) angle=5;
                                        if (j<24) angle=6;
                                    }
                                } else {
                                    if (xp1==0) angle=8; else {
                                        j=(yp1*16)/xp1;
                                        if (j>=80) angle=8;
                                        if (j<80 && j>=24) angle=7;
                                        if (j<24) angle=6;
                                    }
                                }
                            }
                            
                        }
в ходе кода встретлся с проблемой, низя юзать десятичные дроби, пэтому пришлось юзать умножение... и сравнивать потом с заранее умноженными вариантами... зато теперь теоретически прога должна выполняться быстрее , на каждом проходе получается - 5 условий, одно умножение и одно деление...

вот так вот...
__________________
Как минимум я помог многим (с)
(Offline)
 
Ответить с цитированием
Старый 20.07.2007, 23:28   #2
SubZer0
Администратор
 
Аватар для SubZer0
 
Регистрация: 03.09.2005
Сообщений: 2,408
Написано 301 полезных сообщений
(для 996 пользователей)
Re: ATAN2 своими руками

Ну и заключительный штрих:

строчки: j=(yp1*16)/xp1;

заменить на: j=(yp1<<4)/xp1;

и теперь у нас вообще остается 5 условий и одно деление.

(Offline)
 
Ответить с цитированием
Старый 21.07.2007, 16:21   #3
Taugeshtu
scientist.alien
 
Аватар для Taugeshtu
 
Регистрация: 12.02.2007
Сообщений: 2,098
Написано 1,030 полезных сообщений
(для 2,593 пользователей)
Re: ATAN2 своими руками

Ммм, не думаю, что 5 условий и одно деление будут быстрее, чем 4 умножения (которое всё же быстрее деления) и одно сложение. Тест в студию!
__________________
Public service announcement: вы можете заблокировать отображение сообщений определённого пользователя, добавив его ник в список игнорируемых.
Tau lab.
We LOVE you. We MADE you.
(Offline)
 
Ответить с цитированием
Старый 21.07.2007, 21:55   #4
SubZer0
Администратор
 
Аватар для SubZer0
 
Регистрация: 03.09.2005
Сообщений: 2,408
Написано 301 полезных сообщений
(для 996 пользователей)
Re: ATAN2 своими руками

в коде PAX'a:

atn1=32*x*x + 9*y*y;
atn=32*(x*y)/atn1;
(итого 6 умножений и одно деление)
плюс 4 условия (на 4 угла)

в моем:

одно деление и 7 условий (на 16 углов)


ИМХО тест не нужен ибо преимущество очевидно...

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


PS Условия считал с точки зрения процессора при выполнении кода...

(Offline)
 
Ответить с цитированием
Ответ


Опции темы

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Хвалимся своими достижениями pax С# 25 19.02.2010 04:52
ATan2... Slepetc 2D-программирование 13 21.02.2009 22:16
Линукс своими руками SubZer0 Болтовня 13 13.08.2007 22:27
Что не следует трогать руками jimon Болтовня 0 16.03.2007 23:34


Часовой пояс GMT +4, время: 03:42.


vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot
Style crйe par Allan - vBulletin-Ressources.com