Как хранить double значения в int?

Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Ellissar
Встал на лапы
Сообщения: 135
Зарегистрирован: Чт май 09, 2013 10:50:04

Как хранить double значения в int?

Сообщение Ellissar »

Написал код для опроса датчика SHT30. Контроллер STM32F303VC.
Всё работает, но я задался таким вопросом. Как переделать функцию чтоб данные хранились не с плавающей точкой, а как целое число?
Например в int хранится температура в виде "2646", что равно реальной температуре "26,46". В даташите к датчикам BMP280 есть пример но как сделать именно для SHT30 не пойму.
Подскажите как выполнять такие преобразования не используя типы с плавающей точкой?
Спойлер

Код: Выделить всё

	float Tc; //температура в градусах цельсия
	float Tf; //температура в фаренгейтах
	float RH; //влажность в %

	uint8_t data[6] = { 0 };
	uint16_t St, Srh;

	St = (data[0] << 8) | data[1]; //значение температуры, полученное с датчика SHT30
	Tc = -45.0 + 175.0 * ((float) St / 65535.0);
	Tf = -49.0 + 315.0 * ((float) St / 65535.0);

	Srh = (data[3] << 8) | data[4]; //значение влажности, полученное с датчика SHT30
	RH = 100.0 * ((float) Srh / 65535.0);
P.S. поисковиком пользовался - ничего похожего не нашел.
P.P.S. это не реальная необходимость, а скорее из "спортивного" интереса.
Реклама
Аватара пользователя
ПростоНуб
Собутыльник Кота
Сообщения: 2723
Зарегистрирован: Пт сен 07, 2018 20:20:02
Откуда: деревня в Тульской губернии

Re: Как хранить double значения в int?

Сообщение ПростоНуб »

Воспользуйтесь libfixmath
Там для такого преобразования inline функции fix16_from_float() b fix16_from_double() в libfixmath/fix16.h.
Реклама
Аватара пользователя
Starichok51
Модератор
Сообщения: 19053
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Re: Как хранить double значения в int?

Сообщение Starichok51 »

вообще не надо никаких преобразований.
после вывода "26" сам принудительно выводишь десятичную точку и потом выводишь оставшиеся цифры ("46").
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Ellissar
Встал на лапы
Сообщения: 135
Зарегистрирован: Чт май 09, 2013 10:50:04

Re: Как хранить double значения в int?

Сообщение Ellissar »

Я, видимо, объяснил не понятно. Постараюсь по другому объяснить.
Я получил с датчика какое-то число St (uint16_t).
Подставляю это число в формулу Tc = -45 + 175 * (St / 65535), где Tc например int32_t.
Если я буду подставлять как есть, то после вычислений в Tc будет -45 т.к. St < 65535.
Вопрос в том что мне необходимо изменить в формуле чтоб получить реальное значение в виде "2646"? и возможно вообще это сделать или нет?
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
Eddy_Em
Собутыльник Кота
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01
Контактная информация:

Re: Как хранить double значения в int?

Сообщение Eddy_Em »

Привести к uint32 и умножить все на 100.
Пример для одного знака после запятой.
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Реклама
Аватара пользователя
ПростоНуб
Собутыльник Кота
Сообщения: 2723
Зарегистрирован: Пт сен 07, 2018 20:20:02
Откуда: деревня в Тульской губернии

Re: Как хранить double значения в int?

Сообщение ПростоНуб »

Tc=-45L<<16+175L*St
В старших двух байтах Tc будет целая часть. В младших - дробная. Значение будет завышено, примерно, на 0.0001%
Реклама
Аватара пользователя
Starichok51
Модератор
Сообщения: 19053
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Re: Как хранить double значения в int?

Сообщение Starichok51 »

Ellissar писал(а):Я, видимо, объяснил не понятно
как спросил, так я и ответил.
Ellissar писал(а):Tc = -45 + 175 * (St / 65535)
делить надо на 65536.
на ассемблере это делается вообще без плавающей точки, только в целых числах.
2 байта умножаются на 2 байта и от 4-байтового результата отбрасываются 2 младших байта, что эквивалентно делению на 65536.
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Аватара пользователя
КРАМ
Друг Кота
Сообщения: 25266
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Re: Как хранить double значения в int?

Сообщение КРАМ »

[uquote="Ellissar",url="/forum/viewtopic.php?p=3746456#p3746456"]Я, видимо, объяснил не понятно. Постараюсь по другому объяснить.
Я получил с датчика какое-то число St (uint16_t).
Подставляю это число в формулу Tc = -45 + 175 * (St / 65535),[/uquote]
Эдди Вам чуть ранее ответил, но почему то привел объемный пример вместо одной строки:
Tc = -45 + 175 * ((uint32_t)St / 65536).
Аватара пользователя
Starichok51
Модератор
Сообщения: 19053
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Re: Как хранить double значения в int?

Сообщение Starichok51 »

уже был ответ одной строкой:
ПростоНуб писал(а):Tc=-45L<<16+175L*St
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
jcxz
Мудрый кот
Сообщения: 1726
Зарегистрирован: Вт авг 15, 2017 10:51:13

Re: Как хранить double значения в int?

Сообщение jcxz »

[uquote="Starichok51",url="/forum/viewtopic.php?p=3746550#p3746550"]уже был ответ одной строкой:
ПростоНуб писал(а):Tc=-45L<<16+175L*St
[/uquote]И он неправильный. Правильный будет: Tc=(-45l<<16)+175ul*St

Добавлено after 5 minutes 8 seconds:
[uquote="КРАМ",url="/forum/viewtopic.php?p=3746539#p3746539"]Эдди Вам чуть ранее ответил, но почему то привел объемный пример вместо одной строки:
Tc = -45 + 175 * ((uint32_t)St / 65536).[/uquote]St у ТС-а - 16-битное целое. А значит результат данной строки всегда будет == -45.
Ellissar
Встал на лапы
Сообщения: 135
Зарегистрирован: Чт май 09, 2013 10:50:04

Re: Как хранить double значения в int?

Сообщение Ellissar »

[uquote="ПростоНуб",url="/forum/viewtopic.php?p=3746512#p3746512"]Tc=-45L<<16+175L*St[/uquote]
Что-то не то. При значении St = 0x66CF у меня Tc = 0x00 :dont_know:
КРАМ писал(а):Tc = -45 + 175 * ((uint32_t)St / 65536).
Это я пробовал, но всегда возвращается -45. Если я правильно понимаю то при делении St на 65536 получается 0. St всегда меньше 65536.

Добавлено after 13 minutes 36 seconds:
[uquote="jcxz",url="/forum/viewtopic.php?p=3746557#p3746557"]Правильный будет: Tc=(-45l<<16)+175ul*St[/uquote]
Я что-то где-то упускаю, видимо. Не получается.
при St = 0x670e
float у меня вышло = 25.448616
а Tc = 1667730 Tc - uint32_t
И ещё один вопрос. Как в uint32_t будут храниться отрицательные значения? Лучше наверное int32_t использовать?
BlackKilkennyCat
Собутыльник Кота
Сообщения: 2905
Зарегистрирован: Ср ноя 29, 2017 06:58:50

Re: Как хранить double значения в int?

Сообщение BlackKilkennyCat »

uint32_t unsigned то есть, беззнаковый, то есть, отрицательные там не хранятся. Признаком отрицательности является самый левый бит, что дает возможность записывать абсолютные значения либо больше в 2 раза (unsigned), либо меньше (signed)
Меня здесь больше нет
jcxz
Мудрый кот
Сообщения: 1726
Зарегистрирован: Вт авг 15, 2017 10:51:13

Re: Как хранить double значения в int?

Сообщение jcxz »

[uquote="Ellissar",url="/forum/viewtopic.php?p=3746624#p3746624"]Что-то не то. При значении St = 0x66CF у меня Tc = 0x00 :dont_know:[/uquote]Так и должно быть. То выражение - неверное.

[uquote="Ellissar",url="/forum/viewtopic.php?p=3746624#p3746624"]Если я правильно понимаю то при делении St на 65536 получается 0. St всегда меньше 65536.[/uquote]Правильно понимаете. И то выражение - неверное. :)

[uquote="Ellissar",url="/forum/viewtopic.php?p=3746624#p3746624"][uquote="jcxz",url="/forum/viewtopic.php?p=3746557#p3746557"]Правильный будет: Tc=(-45l<<16)+175ul*St[/uquote]Я что-то где-то упускаю, видимо. Не получается.
при St = 0x670e
float у меня вышло = 25.448616
а Tc = 1667730 Tc - uint32_t[/uquote]А как считаете?
Ввёл сейчас как в приведённой формуле в калькуляторе: (0x670e*175-45*2^16)/2^16 получил = 25.4475 - всё ок.
1667730 - это число в форме fixed-point. Т.е. точка там находится в позиции между 15-м и 16-м битами.
Чтобы получить из него целые градусы и их доли нужно сделать:

Код: Выделить всё

uint32 i = ABS32(Tc) + (1u << 15) / 100u; //ABS32() - находит модуль 32-битного числа 
uint r0 = i >> 16;                //целые градусы
uint r1 = (i & 65535u) * 100u >> 16; //сотые доли градуса
А потом воспользоваться советом Starichok51 из первого поста:
printf("%c%u.%02u", ((int32)Tc >> 31 & '-' - '+') + '+', r0, r1);

[uquote="Ellissar",url="/forum/viewtopic.php?p=3746624#p3746624"]Как в uint32_t будут храниться отрицательные значения? Лучше наверное int32_t использовать?[/uquote]Для Tc? Можно и int32_t. Как хранить - не важно, важно как потом использовать его.
Ellissar
Встал на лапы
Сообщения: 135
Зарегистрирован: Чт май 09, 2013 10:50:04

Re: Как хранить double значения в int?

Сообщение Ellissar »

[uquote="jcxz",url="/forum/viewtopic.php?p=3746653#p3746653"]А как считаете?[/uquote]
Я в отладчике смотрю. (TrueSTUDIO)
[uquote="jcxz",url="/forum/viewtopic.php?p=3746653#p3746653"]Ввёл сейчас как в приведённой формуле в калькуляторе: (0x670e*175-45*2^16)/2^16 получил = 25.4475 - всё ок.[/uquote]
По такой формуле: Tc = ((-45L<<16) + 175L * St) >> 16; у меня получается при St = 0x6543 по формуле из даташита float = 24.2229347, а по выше приведённой формуле int32_t = 24 ровно. Но хотелось бы увидеть в int32_t значение 2422 как в примерах к BMP280.

Похоже догадываюсь откуда у меня непонимание вопроса. Я кроме названия мало что знаю о fixed-point. Буду читать :)
jcxz
Мудрый кот
Сообщения: 1726
Зарегистрирован: Вт авг 15, 2017 10:51:13

Re: Как хранить double значения в int?

Сообщение jcxz »

[uquote="Ellissar",url="/forum/viewtopic.php?p=3746990#p3746990"]По такой формуле: Tc = ((-45L<<16) + 175L * St) >> 16; у меня получается при St = 0x6543 по формуле из даташита float = 24.2229347, а по выше приведённой формуле int32_t = 24 ровно. Но хотелось бы увидеть в int32_t значение 2422 как в примерах к BMP280.[/uquote]Вышеприведённая формула даёт целые градусы. А полностью - целые и доли - я выше написал как получить.

[uquote="Ellissar",url="/forum/viewtopic.php?p=3746990#p3746990"]Похоже догадываюсь откуда у меня непонимание вопроса. Я кроме названия мало что знаю о fixed-point. Буду читать :)[/uquote]И это правильно. :beer:

PS: Почитайте ещё это: http://en.wikipedia.org/wiki/Q_(number_format) - это из той же оперы. Только в общем случае десятичная точка может стоять в любой позиции, где удобно, даже за пределами разрядной сетки регистра. И может перемещаться в результате арифметических операций с числами.
Аватара пользователя
Starichok51
Модератор
Сообщения: 19053
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Re: Как хранить double значения в int?

Сообщение Starichok51 »

Starichok51 писал(а):делить надо на 65536.
прошу прощение. сейчас посмотрел даташит на эту микру, да, делить надо на 65535.
но можно пренебречь вычитаем единички, на точность это практически не повлияет, и тогда делать просто сдвиг вправо 16 раз.
Ellissar писал(а):Но хотелось бы увидеть в int32_t значение 2422
делается это так:
берем не 175, а 17500. и берем не 45, а 4500.
тогда получаем результат сразу в сотых долях градуса.
а далее, как я говорил выше - при выводе на экран ставим точку на нужном месте.
я у себя с датчиком HTU21D так и сделал.
например:
St = 0x6543 = 25923.
25923 * 17500 = 453652500.
сдвигаем 16 раз вправо и получаем целое число 6922.
теперь вычитаем 4500, и получаем 2422.
далее выводим 24, выводим точку и выводим 22.

для влажности делаем то же самое. в формуле для влажности (для твоей микры) берем не 100, а 10000, и получаем влажность в сотых долях процента.
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Ellissar
Встал на лапы
Сообщения: 135
Зарегистрирован: Чт май 09, 2013 10:50:04

Re: Как хранить double значения в int?

Сообщение Ellissar »

[uquote="Starichok51",url="/forum/viewtopic.php?p=3747086#p3747086"]берем не 175, а 17500. и берем не 45, а 4500.[/uquote]
Это как раз то, что я искал. Спасибо)
Получается мы все числа в формуле умножили на 100, и сначала выполнили умножение, а уже потом деление чтоб при делении не получился ноль.

Но теперь меня заинтересовал формат числа с фиксированной точкой))
jcxz
Мудрый кот
Сообщения: 1726
Зарегистрирован: Вт авг 15, 2017 10:51:13

Re: Как хранить double значения в int?

Сообщение jcxz »

[uquote="Starichok51",url="/forum/viewtopic.php?p=3747086#p3747086"]для влажности делаем то же самое. в формуле для влажности (для твоей микры) берем не 100, а 10000[/uquote]Но появляется необходимость в операции деления. В моём варианте деления нет.
Аватара пользователя
Starichok51
Модератор
Сообщения: 19053
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Re: Как хранить double значения в int?

Сообщение Starichok51 »

у меня тоже деления нет.
я уже выше сказал, что операция деления тут не нужна.
деление на 65536 производится отбрасыванием двух младших байтов или (то же самое) сдвигом вправо 16 раз.
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
jcxz
Мудрый кот
Сообщения: 1726
Зарегистрирован: Вт авг 15, 2017 10:51:13

Re: Как хранить double значения в int?

Сообщение jcxz »

[uquote="Starichok51",url="/forum/viewtopic.php?p=3747752#p3747752"]у меня тоже деления нет.
я уже выше сказал, что операция деления тут не нужна.[/uquote]Нужна чтобы сотые доли градуса отделить от целых градусов при их передаче функции printf().
Ответить

Вернуться в «Разные вопросы по МК»