Страница 1 из 1
Как правильно сделать приведение типов в Си?
Добавлено: Сб сен 12, 2020 11:12:12
lonelywalker
Здравствуйте.
Делаю на микроконтроллере AVR частотомер.
Как правильно привести тип результата, для отображения на экране или передаче через UART.
У меня выходят вообще неправильные результаты именно из-за преобразования.
Например 234 или 000000. А должно быть 1024 с желательно с дробной частью (или без), хотя бы какого то результата.
По ниже приведенной формуле не работает. Получаются нули, а должно получиться 10004,03085khz
или хотя бы 10004 или 100040308
mesurImp = 10171;
baseImp = 16267043;
unsigned long result = (16000000UL*(unsigned long)mesurImp)/baseImp;
Как получить правильный результат ?
Re: Как правильно сделать приведение типов в Си?
Добавлено: Сб сен 12, 2020 12:56:41
КРАМ
Ну, наверное, следует просто на калькуляторе проверить разрядность произведения и тут же обнаружить, что она равна 40. То есть 32-разрядный тип тут никак не подходит. Нужен 64-разрядный.
Re: Как правильно сделать приведение типов в Си?
Добавлено: Сб сен 12, 2020 15:26:51
lonelywalker
Спасибо. А как проверить разрядность на калькуляторе ?
Re: Как правильно сделать приведение типов в Си?
Добавлено: Сб сен 12, 2020 15:28:59
Reflector
[uquote="lonelywalker",url="/forum/viewtopic.php?p=3891559#p3891559"]А как проверить разрядность на калькуляторе ?[/uquote]
А как ты с такими знаниями частотомер делаешь? В простейшем случае достаточно проверить помешается ли результат умножения в 32 бита, т.е. не превышает ли он 2^32.
Re: Как правильно сделать приведение типов в Си?
Добавлено: Сб сен 12, 2020 17:10:50
NStorm
[uquote="lonelywalker",url="/forum/viewtopic.php?p=3891559#p3891559"]Спасибо. А как проверить разрядность на калькуляторе ?[/uquote]
Ну вообще нужен логарифм по основанию 2. Но в калькуляторе виндовом проще перевести в двоичный или шеснадцатиричный вид, да увидеть кол-во разрядов.
Добавлено after 11 minutes 46 seconds:
с желательно с дробной частью
Код: Выделить всё
double result = (16000000.0*mesurImp)/baseImp;
(или без)
Код: Выделить всё
uint16_t result = ((uint64_t)16000000*mesurImp)/baseImp;
Re: Как правильно сделать приведение типов в Си?
Добавлено: Сб сен 12, 2020 19:39:12
lonelywalker
Поставил разные типы переменных.
Пробовал по разному выводить в usart.
Вот так выводит в usart, но обрезает дробную часть
Код: Выделить всё
unsigned long result = (double)(16000000UL*(float)mesurImp)/(float)baseImp;
USART_sendString(buff,16);
Так выводит только знак вопроса "?"
Код: Выделить всё
double result = (16000000UL*(double)mesurImp)/(double)baseImp;
USART_sendString(buff,16);
Хотя в codeblocks пробовал все работает, а в AVR GCC нет.
и unsigned long long то же самое
Код: Выделить всё
unsigned long long result = (unsigned long long)(16000000UL*(float)mesurImp)/(float)baseImp;
sprintf(buff, "%16llu",freq2);
Re: Как правильно сделать приведение типов в Си?
Добавлено: Сб сен 12, 2020 21:02:52
NStorm
Ваша функция USART_sendString просто не умеет выводить float/double. А в codeblocks вы используете стандартный printf. Если что, в avr-gcc он тоже есть.
Re: Как правильно сделать приведение типов в Си?
Добавлено: Вс сен 13, 2020 13:45:24
lonelywalker
Нашел решение.
Для Atmel studio надо было изменить настройки компилятора.
поставить галочку vprintf library(-Wl,-u,vfprintf).
И установить флаг -lprintf_flt
Подробнее здесь
https://startingelectronics.org/article ... -studio-7/
Re: Как правильно сделать приведение типов в Си?
Добавлено: Вс сен 13, 2020 14:02:44
iddqd
[uquote="lonelywalker",url="/forum/viewtopic.php?p=3891559#p3891559"]Спасибо. А как проверить разрядность на калькуляторе ?[/uquote] Даже и без калькулятора: 16 миллионов - примерно 24 бита (2:24 = 16777216, ака 16 мегабайтов). Значит остается не более 8 битов сверху на умножение, т.е. порядка 256. Если взять больше - тогда это уже не 32 бита.
Re: Как правильно сделать приведение типов в Си?
Добавлено: Вс сен 13, 2020 14:08:02
КРАМ
[uquote="lonelywalker",url="/forum/viewtopic.php?p=3891654#p3891654"]и unsigned long long то же самое
Код: Выделить всё
unsigned long long result = (unsigned long long)(16000000UL*(float)mesurImp)/(float)baseImp;
sprintf(buff, "%16llu",freq2);
[/uquote]
Зачем вам флоат, особенно если вы его все равно приводите к целому и дробной части вам не видать как своих ушей? Если делаете в 64 разрядах, то флоат без нужды. Только лишние вычислительные затраты на перевод во флоат и обратно. Для дробной части нужно использовать фикспойнт (fixed-point). То есть домножить числитель на дробное смещение (скажем, для получения трех знаков после запятой в децимальном формате на 1000).