|
Как рациональнее всего преобразовать float в int? |
|
|
|
Dec 21 2010, 12:33
|
Гуру
     
Группа: Участник
Сообщений: 2 072
Регистрация: 14-01-06
Пользователь №: 13 164

|
Господа, есть небольшая задачка. Работаю с дисплеем и тачскрином. Как вы сами понимаете, координаты дисплея и координаты тачскрина - это две большие разницы (или, как говорят в Одессе, четыре маленьких)) ).
координаты дислпея вычисляются следующим образом: х=touch_x*800/256 y=touch_y*480/256
Но полученный результат является float, а функция, куда будут переданы координаты берет int. Естественно, такой вариант как скажем Circle (touch_x*800/256, touch_y*480/256 .....) не прокатит.
Мне хочется с наименьшими процессорными затратами получить округленные числа типа int, как это сделать? Ибо способов существует несколько, а вот какой быстрее....
Спасибо.
Сообщение отредактировал zheka - Dec 21 2010, 12:34
|
|
|
|
|
Dec 21 2010, 12:44
|
Участник

Группа: Свой
Сообщений: 54
Регистрация: 4-11-05
Пользователь №: 10 480

|
Если touch_x и touch_y типа int, то и результат будет типа int. Все операции умножения и деления будут выполнятся с целыми числами. И в принципе на округление можно забить, так как палец на тачскрине всё округлит сам.
|
|
|
|
|
Dec 21 2010, 13:04
|
Гуру
     
Группа: Участник
Сообщений: 2 072
Регистрация: 14-01-06
Пользователь №: 13 164

|
rezident, сейчас переварю, то что Вы написали, а пока для сравнения, вот что у меня было: Код _X=(float)*touch_x*800/256; _Y=(float)*touch_y*480/256; FillEllipse(800-(int)(_X),(int)(_Y),10,10,clRed); Это затратнее чем Ваш вариант? Проверил. Мой вышеприведенный вариант позволял рисовать на экране стилусом. Ваш вариант в моем использовании: FillEllipse(800-((*touch_x*800)>>8),((*touch_y*480)>>8),10,10,clRed); рисует в правом верхнем углу экрана, в квадрате со стороной 256х256 пикселей. У тачпанель 0,0 находятся в правом верхнем углу экрана. touch_x у меня типа unsigned char
Сообщение отредактировал zheka - Dec 21 2010, 13:07
|
|
|
|
|
Dec 21 2010, 13:11
|
Профессионал
    
Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007

|
Вы, надеюсь, понимаете, что координаты вашего устройства отображения это сугубо целые числа? Так на кой вам float? Некуда процессорное время девать? Да и написали бы лучше: Код х=((*touch_x)*800)>>8; y=((*touch_y)*480)>>8; FillEllipse(800-x, y, 10, 10, clRed);
|
|
|
|
|
Dec 21 2010, 13:29
|
Гуру
     
Группа: Участник
Сообщений: 2 072
Регистрация: 14-01-06
Пользователь №: 13 164

|
Цитата Вы, надеюсь, понимаете, что координаты вашего устройства отображения это сугубо целые числа? Подозревать человека, который в состоянии собрать отладочную плату и подключить с ней дисплей глупо. В свою очередь, я надеюсь что вы понимаете что произойдет если unsigned char умножить на 800. Итог - мой вариант работает, но безусловно тратит процессорное время. Ваш вариант работает как и предложенный резидентом.
Сообщение отредактировал zheka - Dec 21 2010, 13:33
|
|
|
|
|
Dec 21 2010, 13:42
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
zheka, а вы дроби из курса начальной школы не забыли еще? Например, запись 0,125 означает 125/1000. И числитель и знаменатель дроби являются целыми числами. Цитата(zheka @ Dec 21 2010, 21:29)  В свою очередь, я надеюсь что вы понимаете что произойдет если unsigned char умножить на 800. В соответствии со стандартом Си произойдет конвертация в тип signed integer, в котором эти числа и будут перемножены. Однако если переменные x и y у вас тоже типа char, то результат умножения будет преобразован к типу char. Вывод: вычислять нужно, приведя операнды к типу long.
|
|
|
|
|
Dec 21 2010, 13:49
|
Гуру
     
Группа: Участник
Сообщений: 2 072
Регистрация: 14-01-06
Пользователь №: 13 164

|
Да нет же, я не о целых и дробях, я о том, что touch_x не может быть равен больше 255, если прибавить к 245 число 20, получится не 265, а 10. У пишущих здесь есть возможность проверить это в компиляторе? В моем варианте я оперирую с float, а затем по окончании привожу float к int, не только потому что я, как ни странно знаю, что координаты это целое число, а еще и потому, что функция не возьмет float. Цитата В соответствии со стандартом Си произойдет конвертация в тип signed integer, в котором эти числа и будут перемножены. ОДнако на практике - в Вашем варианте, пока я веду стилусом вдоль х, курсор на экране 4 раза пробегает от координаты 544 к координате 800. Значит все таки не происходит конвертации. Цитата Вывод: вычислять нужно, приведя операнды к типу long. То есть то же самое, что у меня, только приводя к long, так? СРазу вопрос работа с long менее затратна, чем с float ? Поверьте, мне нужно не просто чтобы работало, а чтобы работало быстро настолько, насколько это возможно силами C.
|
|
|
|
|
Dec 21 2010, 14:00
|
Профессионал
    
Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007

|
Цитата(zheka @ Dec 21 2010, 20:29)  Подозревать человека, который в состоянии собрать отладочную плату и подключить с ней дисплей глупо.
В свою очередь, я надеюсь что вы понимаете что произойдет если unsigned char умножить на 800.
Итог - мой вариант работает, но безусловно тратит процессорное время. Ваш вариант работает как и предложенный резидентом. Ну вы же нам исходя, видимо, из соображений секретности, даже не сказали, что за процессор/компилятор пользуете. Как вы там объявили свои х, тouch_x - тайна, покрытая мраком. У вас int, часом, не 16-бит? Так почему надо упорно лезть во float, а не применить, действительно, что-нибудь типа long (хотя это тоже загадка, что этот long на вашем процессоре из себя представляет)? Ну да, вы же в разделе AVR. int он и есть 16-бит. Сделайте так: Код х=(((long int)touch_x)*800L)>>8; y=(((long int)touch_y)*480L)>>8; FillEllipse(800-x, y, 10, 10, clRed);
|
|
|
|
|
Dec 21 2010, 15:53
|
Гуру
     
Группа: Участник
Сообщений: 2 072
Регистрация: 14-01-06
Пользователь №: 13 164

|
У меня CodeVision 2, процессор - atmega32 Сейчас попробую то что вы написали. Объявлял так Код unsigned char x; unsigned char y; unsigned char *touch_x; unsigned char *touch_y;
int sX; int sY;
.....
void main ()
.....
touch_x = &x; touch_y = &y; Получаю координаты функцией GetTouchStat(touch_x,touch_y); То что вы предложили - не работает.
|
|
|
|
|
Dec 21 2010, 16:23
|
Профессионал
    
Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007

|
Цитата(zheka @ Dec 21 2010, 22:53)  У меня CodeVision 2, процессор - atmega32 Сейчас попробую то что вы написали. Объявлял так Код unsigned char x; unsigned char y; unsigned char *touch_x; unsigned char *touch_y;
int sX; int sY;
.....
void main ()
.....
touch_x = &x; touch_y = &y; Получаю координаты функцией GetTouchStat(touch_x,touch_y); То что вы предложили - не работает. Делаем так: Код unsigned char x; unsigned char y;
int sX; int sY;
.....
void main ()
.....
GetTouchStat(&x, &y);
sX=(int)((((long int)x)*800L)>>8); sY=(int)((((long int)y)*480L)>>8); FillEllipse(800-sX, sY, 10, 10, clRed); Кстати. Touchscreen выдает координаты в диапазоне 0...255 или более того?
|
|
|
|
|
Dec 21 2010, 16:28
|
Гуру
     
Группа: Участник
Сообщений: 2 072
Регистрация: 14-01-06
Пользователь №: 13 164

|
Код sX=(int)((((long int)x)*800L)>>8); sY=(int)((((long int)y)*480L)>>8); FillEllipse(800-sX, sY, 10, 10, clRed); Вот это другое дело! Работает, так как надо. И, судя по тому, что рисуемые на большой скорости передвижения стилуса точки получаются гуще - работает быстрее. Спасибо! Цитата Touchscreen выдает координаты в диапазоне 0...255 или более того? 0-255. Иначе зачем я делил на 256?
|
|
|
|
|
Dec 21 2010, 16:34
|
Профессионал
    
Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007

|
Надеюсь вы поняли, что проблема была в ваших Код unsigned char x; unsigned char y; Я уже писал на форуме и вам советую - забудьте про float и double. Не нужны они в 99,99% случаев.
|
|
|
|
|
Dec 22 2010, 04:15
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(zheka @ Dec 21 2010, 21:28)  Код sX=(int)((((long int)x)*800L)>>8); sY=(int)((((long int)y)*480L)>>8); FillEllipse(800-sX, sY, 10, 10, clRed); И, судя по тому, что рисуемые на большой скорости передвижения стилуса точки получаются гуще - работает быстрее. Я так думаю, что сейчас львиную долю времени занимает FillEllipse. Попробуйте выводить одну точку или хотя бы крестик из двух отрезков. Кстати, a*3.125 это a*25/8 aka (a*25)>>3 (впрочем, я бы может округление добавил, (a*25+4)/8), что вполне считается для Вашего диапазона даже не в long т.е. очень быстро.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Dec 22 2010, 04:18
|
Профессионал
    
Группа: Участник
Сообщений: 1 264
Регистрация: 17-06-08
Из: бандустан
Пользователь №: 38 347

|
Цитата Кстати, в полученном коде все-таки каждый раз косвенно высчитывается 800/256 и 400/256. Нельзя ли еще сократить? можно. арифметику, дроби в каком классе проходят ? тренируйте мозги: 800/256 = (800 / 32) / (256 / 32) = 25 / 8 = 25 >> 3; 400/256 = (400 / 16) / (256 / 16) = 25 / 16 = 25 >> 4; вместо long теперь достаточно unsigned int.
Сообщение отредактировал ukpyr - Dec 22 2010, 04:23
|
|
|
|
|
Dec 27 2010, 07:37
|
Участник

Группа: Участник
Сообщений: 53
Регистрация: 24-06-07
Из: ukraine
Пользователь №: 28 658

|
вообще то на сколько я замечал то сдвиг для умножения/деления работает быстрее чем это множить или делить, но есть недостаток, множить или делить только кратное 2.
|
|
|
|
|
Dec 31 2010, 16:09
|

Знающий
   
Группа: Свой
Сообщений: 966
Регистрация: 27-05-06
Из: СПб
Пользователь №: 17 499

|
Я думаю Жеке не надо напоминать, что наш любимый CV преобразование типов не делает B появление в правой части выражения char первым, хоть в левой и long или int стоит , будет вызывать переполнение и неадекватный результат.  обычно это делается так, хотя и выглядит криво не a=b*c; а так: а=b; b*=с; Интересно, что работает быстрее, чем "принудительное" приведение к int
|
|
|
|
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|