Всем привет.
Есть переменная (float), которая вычисляется из строковой переменной "2.19".
вычисляется посимвольно: (первый символ - '0') + (float)(третий символ - '0')/10 + (четвертый символ - '0')/100
В результате получается 2.1899998
Компилятор AVR GNU Toolchain (Atmel Studio 6.2)
Подскажите, как корректнее вычислить эту самую переменную, что бы в результате получить именно 2.19
AVR: float
- Реклама
-
dmmedia
- Первый раз сказал Мяу!
- Сообщения: 27
- Зарегистрирован: Вт сен 06, 2011 18:00:36
- Откуда: Tallinn, Estonia
- Контактная информация:
Re: AVR: float
Никак, это принцип работы чисел с плавающей запятой.
Используйте округление.
добавил:
как воркэраунд, если нужно работать всегда с 2-мя цифрами после запятой, то работать с целыми числами, а при выводе делить на 100 и форматировать вывод.
Используйте округление.
добавил:
как воркэраунд, если нужно работать всегда с 2-мя цифрами после запятой, то работать с целыми числами, а при выводе делить на 100 и форматировать вывод.
Re: AVR: float
спасибо за инфу и хорошую идею. пожалуй, так и поступлюdmmedia писал(а):Никак, это принцип работы чисел с плавающей запятой.
Используйте округление.
добавил:
как воркэраунд, если нужно работать всегда с 2-мя цифрами после запятой, то работать с целыми числами, а при выводе делить на 100 и форматировать вывод.
Re: AVR: float
В контроллерах, не имеющих FPU, вещественные типы без крайней нужды лучше вообще не использовать. Это сильно раздувает код и замедляет его выполнение.
Лучше всего использовать целочисленные переменные - например, если нужны сотые, просто умножить используемые величины на сто и вести расчеты с учетом такой договоренности. Если без вещественных чисел ну вообще никак (например, "честное" преобразование HSV->RGB), стоит посмотреть в сторону фиксированной точки. И только в самом крайнем случае использовать float.
Следует отметить, что безусловная необходимость в вещественных типах может возникнуть в основном только при решении СЛАУ и подобных задачах с суровым математическим уклоном. В подавляющем большинстве остальных случаев хватает самой простой методики с умножением - например, если это вольтметр, представлять напряжение не в Вольтах, а в милливольтах, и т.п.
Кроме того, вещественные числа имеют много особенностей вроде невозможности точного представления дробей со знаменателем, не приводимым к степени двойки (на что вы и натолкнулись), потери точности при вычислениях и прочего.
Лучше всего использовать целочисленные переменные - например, если нужны сотые, просто умножить используемые величины на сто и вести расчеты с учетом такой договоренности. Если без вещественных чисел ну вообще никак (например, "честное" преобразование HSV->RGB), стоит посмотреть в сторону фиксированной точки. И только в самом крайнем случае использовать float.
Следует отметить, что безусловная необходимость в вещественных типах может возникнуть в основном только при решении СЛАУ и подобных задачах с суровым математическим уклоном. В подавляющем большинстве остальных случаев хватает самой простой методики с умножением - например, если это вольтметр, представлять напряжение не в Вольтах, а в милливольтах, и т.п.
Кроме того, вещественные числа имеют много особенностей вроде невозможности точного представления дробей со знаменателем, не приводимым к степени двойки (на что вы и натолкнулись), потери точности при вычислениях и прочего.
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Re: AVR: float
это как?YS писал(а): Если без вещественных чисел ну вообще никак, стоит посмотреть в сторону фиксированной точки.
что за тип данных?
- Реклама
Re: AVR: float
Фиксированная точка - это когда мы договариваемся, что внутри в общем-то целочисленной переменной n бит будет дробной частью. В общем случае, умножение на степень десяти - тоже фиксированная точка, но обычно под этим понятием имеют в виду именно дроби с основанием, равным степени двойки - это позволяет использовать быстрые битовые сдвиги.
Основная идея - мы представляем число как целое + числитель / знаменатель, равный степени двойки, причем храним знаменатель в той же переменной. Например, 1.1 - это примерно 1 + 26/256.
Итак, например, мы хотим иметь точность два десятичных знака после запятой. Выберем знаменатель для нашего представления равным 256. 1/256 ~ 0.004, так что будет небольшой запас. Таким образом, под дробную часть понадобится 8 бит. Для собственно переменной, с учетом сдвигов, которые нам понадобятся, имеет смысл выбрать четырехбайтовый целый тип - uint32_t (да, лучше использовать типы из stdint.h).
Последний байт числа будем считать "дробным", первый для простоты оставим для обеспечения безопасных сдвигов. Таким образом, под собственно число останется 16 бит.
1.1, с учетом вышесказанного, запишется как 0x0000011A. Складываются/вычитаются такие числа как обычно, умножение и деление производятся чуточку хитрее, про это написано по ссылке выше.
Можете посмотреть, как я писал преобразование HSV в RGB на фиксированной точке.
Кстати, почитайте еще про особенности плавающей точки.
Основная идея - мы представляем число как целое + числитель / знаменатель, равный степени двойки, причем храним знаменатель в той же переменной. Например, 1.1 - это примерно 1 + 26/256.
Итак, например, мы хотим иметь точность два десятичных знака после запятой. Выберем знаменатель для нашего представления равным 256. 1/256 ~ 0.004, так что будет небольшой запас. Таким образом, под дробную часть понадобится 8 бит. Для собственно переменной, с учетом сдвигов, которые нам понадобятся, имеет смысл выбрать четырехбайтовый целый тип - uint32_t (да, лучше использовать типы из stdint.h).
Последний байт числа будем считать "дробным", первый для простоты оставим для обеспечения безопасных сдвигов. Таким образом, под собственно число останется 16 бит.
1.1, с учетом вышесказанного, запишется как 0x0000011A. Складываются/вычитаются такие числа как обычно, умножение и деление производятся чуточку хитрее, про это написано по ссылке выше.
Можете посмотреть, как я писал преобразование HSV в RGB на фиксированной точке.
Кстати, почитайте еще про особенности плавающей точки.
Разница между теорией и практикой на практике гораздо больше, чем в теории.


