2013-06-06 2 views
1

Примечание: Я кодирую следующее в варианте Arduino C++.Извлечение десятичной части поплавка точно

Из заданного поплавка (всегда с четырьмя десятичными знаками), я хочу извлечь только десятичную часть («мантисса») в виде целого числа.

Так что я попытался этот метод:

void ExtractDecimalPart(float Value) { 
    int IntegerPart = (int)(Value); 
    int DecimalPart = 10000 * (Value - IntegerPart); //10000 b/c my float values always have exactly 4 decimal places 
    Serial.println (DecimalPart); 
} 

Но полученные результаты в следующем:

ExtractDecimalPart (1234.5677); //prints 5677 
ExtractDecimalPart (1234.5678); //prints 5677 
ExtractDecimalPart (1234.5679); //prints 5678 

Обратите внимание, что последние два распечатывают неправильно; Я предполагаю, что это связано с проблемами точности с плавающей запятой.

Что такое экономичный способ решения вышеуказанного?

+0

Возможно ли использование фиксированной точки? Какой диапазон вы хотите представить? Каковы размеры 'int',' long' и (если поддерживается) 'long long' в вашем компиляторе? Кроме того, поддерживает ли ваш компилятор 'stdint.h', и если да, то какой из них самый большой? – jerry

ответ

2

Это крутой вопрос.

я буду считать, что ardiuno использую IEEE 75 при установке поплавка, равном 1234.5677 числа ближе к тому, который помещается в 4 байта является 1.2345677490234375E3, который выглядит как 0x449A522B в шестнадцатеричном формате.

но когда вы положили 1234.5678 в поплавок, лучшим номером, который он может сформировать, является 1.2345677490234375E3 Который только короткий. В шестнадцатеричном виде это 0x449A522B.

Так что в коротких поплавках просто не может быть сохранен номер, для которого требуется количество цифр, которые вы используете.

+0

Благодарим вас за объяснение, почему это происходит. Если не плавает, то какие другие типы данных существуют для этой цели?(Помимо строк, в отношении которых я ответил на ответ выше.) – boardbite

+0

Откуда берутся ваши номера? Вы заинтересованы в цифрах infront десятичной точки. Может быть, хороший способ использовать длинный. Поплавки - действительно два числа, и экспонент действительно дает широкий диапазон, но он отбирает бит от мантисы, и вы теряете детализацию. –

+0

Хорошие новости. Я попытался использовать два метода, включая ваше предложение о литье в строку. Оба работали хорошо - первый вариант, хранение в _string_ справа от исходного (внешнего измерения), а второй вариант, хранение в длинную и выполняющуюся арифметику с ним и только затем преобразование в float. Оба работают удовлетворительно, поэтому рассмотрим это решение! – boardbite

1

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

EDIT

Я не знаю, как сделать это с версии Arduino о c++ так что не стесняйтесь редактировать свой ответ, чтобы добавить пример всем!

+0

Кастинг на строку будет хорошо работать, и это будет довольно быстрое исправление. Я чувствую, что было бы лучше, если бы вы могли избежать в зависимости от последней цифры в поплавке. –

+0

Хм, я попробовал предложенный подход: Использовал 'char Buffer [20]; dtostrf (значение, 4, 4, буфер); Serial.println (Buffer); 'все еще были ошибки точности и напечатаны ** 1234.5677 **, ** 1234.5677 ** и ** 1234.5679 ** соответственно. – boardbite

+0

Этого следовало ожидать. Точность теряется при сохранении данных в виде поплавка, поэтому сохраните его в поплавке, а затем изменение данных в строку не поможет. Но в зависимости от того, как вы получите данные, вы сможете сохранить строку при ее получении. –

0

32-битные поплавки имеют 23 бит мантиссы, поэтому он может содержать только около 7 цифр точности. В вашем примере используется 8 цифр, поэтому последний из них не уверен. Вы должны использовать тип с плавающей запятой более высокой точности. Я не знаю, поддерживает ли arduino 64-битное удвоение или нет. Если это не так, вы должны написать или использовать некоторую двойную математическую библиотеку. Или вы можете использовать float-float типа double-double типа this. Для более простой реализации вы можете хранить внутреннюю часть и десятичную часть отдельно

+0

Arduino не поддерживает дублирование вообще, если double означает тип данных с более высокой точностью, чем float. Двойной == float для Arduino. – Ibraheem

+0

@Ibraheem это не Arduino не поддерживает двойники, это компилятор не имеет двойных арифметических библиотек. С помощью [произвольной точности арифметики] (https://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic) компьютер может выполнять операции с любой точностью, если у него достаточно памяти (и времени) –

+0

Arduino - это программное обеспечение не аппаратное, хотя Arduino действительно делает фирменные платы Arduino, но они являются просто реализациями чипов Atmega. – Ibraheem

Смежные вопросы