Страница 1 из 2
Как хранить double значения в int?
Добавлено: Сб ноя 30, 2019 14:14:49
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. это не реальная необходимость, а скорее из "спортивного" интереса.
Re: Как хранить double значения в int?
Добавлено: Сб ноя 30, 2019 14:29:06
ПростоНуб
Воспользуйтесь
libfixmath
Там для такого преобразования inline функции fix16_from_float() b fix16_from_double() в libfixmath/fix16.h.
Re: Как хранить double значения в int?
Добавлено: Сб ноя 30, 2019 14:40:19
Starichok51
вообще не надо никаких преобразований.
после вывода "26" сам принудительно выводишь десятичную точку и потом выводишь оставшиеся цифры ("46").
Re: Как хранить double значения в int?
Добавлено: Сб ноя 30, 2019 15:44:09
Ellissar
Я, видимо, объяснил не понятно. Постараюсь по другому объяснить.
Я получил с датчика какое-то число St (uint16_t).
Подставляю это число в формулу Tc = -45 + 175 * (St / 65535), где Tc например int32_t.
Если я буду подставлять как есть, то после вычислений в Tc будет -45 т.к. St < 65535.
Вопрос в том что мне необходимо изменить в формуле чтоб получить реальное значение в виде "2646"? и возможно вообще это сделать или нет?
Re: Как хранить double значения в int?
Добавлено: Сб ноя 30, 2019 16:31:56
Eddy_Em
Привести к uint32 и умножить все на 100.
Пример для одного знака после запятой.
Re: Как хранить double значения в int?
Добавлено: Сб ноя 30, 2019 16:40:53
ПростоНуб
Tc=-45L<<16+175L*St
В старших двух байтах Tc будет целая часть. В младших - дробная. Значение будет завышено, примерно, на 0.0001%
Re: Как хранить double значения в int?
Добавлено: Сб ноя 30, 2019 17:02:24
Starichok51
Ellissar писал(а):Я, видимо, объяснил не понятно
как спросил, так я и ответил.
Ellissar писал(а):Tc = -45 + 175 * (St / 65535)
делить надо на 65536.
на ассемблере это делается вообще без плавающей точки, только в целых числах.
2 байта умножаются на 2 байта и от 4-байтового результата отбрасываются 2 младших байта, что эквивалентно делению на 65536.
Re: Как хранить double значения в int?
Добавлено: Сб ноя 30, 2019 17:27:19
КРАМ
[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).
Re: Как хранить double значения в int?
Добавлено: Сб ноя 30, 2019 17:38:35
Starichok51
уже был ответ одной строкой:
ПростоНуб писал(а):Tc=-45L<<16+175L*St
Re: Как хранить double значения в int?
Добавлено: Сб ноя 30, 2019 17:54:13
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.
Re: Как хранить double значения в int?
Добавлено: Сб ноя 30, 2019 19:45:17
Ellissar
[uquote="ПростоНуб",url="/forum/viewtopic.php?p=3746512#p3746512"]Tc=-45L<<16+175L*St[/uquote]
Что-то не то. При значении St = 0x66CF у меня Tc = 0x00
КРАМ писал(а):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 использовать?
Re: Как хранить double значения в int?
Добавлено: Сб ноя 30, 2019 19:55:42
BlackKilkennyCat
uint32_t unsigned то есть, беззнаковый, то есть, отрицательные там не хранятся. Признаком отрицательности является самый левый бит, что дает возможность записывать абсолютные значения либо больше в 2 раза (unsigned), либо меньше (signed)
Re: Как хранить double значения в int?
Добавлено: Сб ноя 30, 2019 20:08:26
jcxz
[uquote="Ellissar",url="/forum/viewtopic.php?p=3746624#p3746624"]Что-то не то. При значении St = 0x66CF у меня Tc = 0x00

[/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. Как хранить - не важно, важно как потом использовать его.
Re: Как хранить double значения в int?
Добавлено: Вс дек 01, 2019 13:34:15
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. Буду читать

Re: Как хранить double значения в int?
Добавлено: Вс дек 01, 2019 14:05:01
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]И это правильно.
PS: Почитайте ещё это:
http://en.wikipedia.org/wiki/Q_(number_format) - это из той же оперы. Только в общем случае десятичная точка может стоять в любой позиции, где удобно, даже за пределами разрядной сетки регистра. И может перемещаться в результате арифметических операций с числами.
Re: Как хранить double значения в int?
Добавлено: Вс дек 01, 2019 15:51:31
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, и получаем влажность в сотых долях процента.
Re: Как хранить double значения в int?
Добавлено: Пн дек 02, 2019 07:07:16
Ellissar
[uquote="Starichok51",url="/forum/viewtopic.php?p=3747086#p3747086"]берем не 175, а 17500. и берем не 45, а 4500.[/uquote]
Это как раз то, что я искал. Спасибо)
Получается мы все числа в формуле умножили на 100, и сначала выполнили умножение, а уже потом деление чтоб при делении не получился ноль.
Но теперь меня заинтересовал формат числа с фиксированной точкой))
Re: Как хранить double значения в int?
Добавлено: Пн дек 02, 2019 15:40:32
jcxz
[uquote="Starichok51",url="/forum/viewtopic.php?p=3747086#p3747086"]для влажности делаем то же самое. в формуле для влажности (для твоей микры) берем не 100, а 10000[/uquote]Но появляется необходимость в операции деления. В моём варианте деления нет.
Re: Как хранить double значения в int?
Добавлено: Пн дек 02, 2019 16:38:23
Starichok51
у меня тоже деления нет.
я уже выше сказал, что операция деления тут не нужна.
деление на 65536 производится отбрасыванием двух младших байтов или (то же самое) сдвигом вправо 16 раз.
Re: Как хранить double значения в int?
Добавлено: Пн дек 02, 2019 17:21:31
jcxz
[uquote="Starichok51",url="/forum/viewtopic.php?p=3747752#p3747752"]у меня тоже деления нет.
я уже выше сказал, что операция деления тут не нужна.[/uquote]Нужна чтобы сотые доли градуса отделить от целых градусов при их передаче функции printf().