реклама на сайте
подробности

 
 
> Как рациональнее всего преобразовать float в int?
zheka
сообщение Dec 21 2010, 12:33
Сообщение #1


Гуру
******

Группа: Участник
Сообщений: 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
Go to the top of the page
 
+Quote Post
2 страниц V   1 2 >  
Start new topic
Ответов (1 - 24)
_Pasha
сообщение Dec 21 2010, 12:40
Сообщение #2


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



QUOTE (zheka @ Dec 21 2010, 19:33) *
Но полученный результат является float, а функция, куда будут переданы координаты берет int.

Кто сказал? Если int x,y; то результат будет int sm.gif
Go to the top of the page
 
+Quote Post
fantex
сообщение Dec 21 2010, 12:44
Сообщение #3


Участник
*

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



Если touch_x и touch_y типа int, то и результат будет типа int. Все операции умножения и деления будут выполнятся с целыми числами. И в принципе на округление можно забить, так как палец на тачскрине всё округлит сам.
Go to the top of the page
 
+Quote Post
rezident
сообщение Dec 21 2010, 12:45
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Зачем вам float вообще? Вычисляйте в целых числах. Ведь сами координаты-то точек являются целыми числами.
х=(touch_x*800)>>8;
y=(touch_y*480)>>8;
Если уж так непременно нужны дробные результаты, то и представляйте их в виде дроби с основанием двойки.
Go to the top of the page
 
+Quote Post
zheka
сообщение Dec 21 2010, 13:04
Сообщение #5


Гуру
******

Группа: Участник
Сообщений: 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
Go to the top of the page
 
+Quote Post
sergeeff
сообщение Dec 21 2010, 13:11
Сообщение #6


Профессионал
*****

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



Вы, надеюсь, понимаете, что координаты вашего устройства отображения это сугубо целые числа? Так на кой вам float? Некуда процессорное время девать?

Да и написали бы лучше:

Код
х=((*touch_x)*800)>>8;
y=((*touch_y)*480)>>8;
FillEllipse(800-x, y, 10, 10, clRed);
Go to the top of the page
 
+Quote Post
zheka
сообщение Dec 21 2010, 13:29
Сообщение #7


Гуру
******

Группа: Участник
Сообщений: 2 072
Регистрация: 14-01-06
Пользователь №: 13 164



Цитата
Вы, надеюсь, понимаете, что координаты вашего устройства отображения это сугубо целые числа?


Подозревать человека, который в состоянии собрать отладочную плату и подключить с ней дисплей глупо.


В свою очередь, я надеюсь что вы понимаете что произойдет если unsigned char умножить на 800.

Итог - мой вариант работает, но безусловно тратит процессорное время. Ваш вариант работает как и предложенный резидентом.

Сообщение отредактировал zheka - Dec 21 2010, 13:33
Go to the top of the page
 
+Quote Post
rezident
сообщение Dec 21 2010, 13:42
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 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.
Go to the top of the page
 
+Quote Post
zheka
сообщение Dec 21 2010, 13:49
Сообщение #9


Гуру
******

Группа: Участник
Сообщений: 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.
Go to the top of the page
 
+Quote Post
rezident
сообщение Dec 21 2010, 13:50
Сообщение #10


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(zheka @ Dec 21 2010, 21:48) *
ОДнако на практике - в Вашем варианте, пока я веду стилусом вдоль х, курсор на экране 4 раза пробегает от координаты 544 к координате 800. Значит все таки не происходит конвертации.
Нет смысла обсуждать видимые результаты, если неизвестны причины, порождающие их. Я имею в виду типы переменных и функции, которые вы применяете. Нам о них ничего не известно.
Go to the top of the page
 
+Quote Post
sergeeff
сообщение Dec 21 2010, 14:00
Сообщение #11


Профессионал
*****

Группа: Свой
Сообщений: 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);
Go to the top of the page
 
+Quote Post
zheka
сообщение Dec 21 2010, 15:53
Сообщение #12


Гуру
******

Группа: Участник
Сообщений: 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);

То что вы предложили - не работает.
Go to the top of the page
 
+Quote Post
777777
сообщение Dec 21 2010, 16:13
Сообщение #13


Профессионал
*****

Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357



Цитата(zheka @ Dec 21 2010, 21:53) *
То что вы предложили - не работает.

Код
unsigned char x;
unsigned char y;

int sX;
int sY;

.....

void main ()

.....

GetTouchStat(&x,&y);
sX = x;
sY = Y;

А так работает? С sX, sY выполняешь вычисления. По моим прикидкам 16-разрядного ште должно хватить sm.gif

Сообщение отредактировал 777777 - Dec 21 2010, 16:13
Go to the top of the page
 
+Quote Post
sergeeff
сообщение Dec 21 2010, 16:23
Сообщение #14


Профессионал
*****

Группа: Свой
Сообщений: 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 или более того?
Go to the top of the page
 
+Quote Post
zheka
сообщение Dec 21 2010, 16:28
Сообщение #15


Гуру
******

Группа: Участник
Сообщений: 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?
Go to the top of the page
 
+Quote Post
sergeeff
сообщение Dec 21 2010, 16:34
Сообщение #16


Профессионал
*****

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



Надеюсь вы поняли, что проблема была в ваших

Код
unsigned char x;
unsigned char y;


Я уже писал на форуме и вам советую - забудьте про float и double. Не нужны они в 99,99% случаев.
Go to the top of the page
 
+Quote Post
zheka
сообщение Dec 22 2010, 03:52
Сообщение #17


Гуру
******

Группа: Участник
Сообщений: 2 072
Регистрация: 14-01-06
Пользователь №: 13 164



Не совсем в этом причина.
800/256 - я так написал, чтобы было понятно тем, кому я задаю вопрос.
Я же рассуждая, что каждый раз высчитывть константу затратно в своем коде изначально просто умножал на 3.125, отсюда и возникла работа с float.

Кстати, в полученном коде все-таки каждый раз косвенно высчитывается 800/256 и 400/256. Нельзя ли еще сократить?
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Dec 22 2010, 04:03
Сообщение #18


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (zheka @ Dec 22 2010, 08:52) *
Нельзя ли еще сократить?
Сократить что? Одно умножение и пересылку (сдвиг на 8 это пересылка байта 2 раза, ибо результат у вас двухбайтный)? Маловероятно. Разве что таблицей. У вас есть лишний килобайт флеша?


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
ReAl
сообщение Dec 22 2010, 04:15
Сообщение #19


Нечётный пользователь.
******

Группа: Свой
Сообщений: 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 т.е. очень быстро.


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
ukpyr
сообщение Dec 22 2010, 04:18
Сообщение #20


Профессионал
*****

Группа: Участник
Сообщений: 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
Go to the top of the page
 
+Quote Post
zheka
сообщение Dec 22 2010, 04:27
Сообщение #21


Гуру
******

Группа: Участник
Сообщений: 2 072
Регистрация: 14-01-06
Пользователь №: 13 164



ukpyr
спасибо.

Сообщение отредактировал zheka - Dec 22 2010, 04:28
Go to the top of the page
 
+Quote Post
~phase
сообщение Dec 27 2010, 07:37
Сообщение #22


Участник
*

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



вообще то на сколько я замечал то сдвиг для умножения/деления работает быстрее чем это множить или делить, но есть недостаток, множить или делить только кратное 2.
Go to the top of the page
 
+Quote Post
mempfis_
сообщение Dec 27 2010, 07:48
Сообщение #23


Профессионал
*****

Группа: Свой
Сообщений: 1 001
Регистрация: 27-06-06
Пользователь №: 18 409



Цитата(~phase @ Dec 27 2010, 14:37) *
вообще то на сколько я замечал то сдвиг для умножения/деления работает быстрее чем это множить или делить, но есть недостаток, множить или делить только кратное 2.


Если делимое - переменная величина то сложно чтото придумать кроме как x/y. Но если делимое константа или Вы хотите умножить число на другое дробное число-константу, то всегда можно подобрать такое число что y=a/b где a будет степенью двойки, тогда останется только перемножить на b и результат сдвинуть на log2(cool.gif вправо (эквивалент деления результат на a). Подобные манипуляции существенно ускоряют математику за счёт избавления от деления на число не кратное 2.
Go to the top of the page
 
+Quote Post
defunct
сообщение Dec 29 2010, 20:57
Сообщение #24


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



Цитата(ukpyr @ Dec 22 2010, 09:18) *
вместо long теперь достаточно unsigned int.

Зато сдвиг стал много тяжеловеснее.
Ускорять всяко лучше на асме, где можно сделать умножение U8xU16=U16, или U16xU16 = MSU16(U24) - (опустить расчет младшего байта).
Только думаю смысла нет все это делать, ибо CodeVision и афтар в C плавает - тормозить будет не это так что-то другое.
Go to the top of the page
 
+Quote Post
Serj78
сообщение Dec 31 2010, 16:09
Сообщение #25


Знающий
****

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



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

Интересно, что работает быстрее, чем "принудительное" приведение к int
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 21st July 2025 - 13:09
Рейтинг@Mail.ru


Страница сгенерированна за 0.01606 секунд с 7
ELECTRONIX ©2004-2016