Проблема с большими числами FLOAT
- Войдите на сайт для отправки комментариев
Здравствуйте дорогие друзья!
В общем в интернете долго искал это явление, но так и не нашел или может быть плохо искал, поэтому решил написать сюда, может быть гуру ответят на мой вопрос или может быть кто-то уже также наступил на те-же грабли...
Я в общем для себя уже решил эту проблему, но просто интересно стало...
Суть проблемы такова:
Есть число, которое хранится в переменной FLOAT, например 19087200.00
Это значение счетчика импульсов энкодера, которое накапливается или уменьшается, просто он до этого значения еще никогда не доходил, но с недавних пор стало нужно, чтобы доходил
Ну в общем в эту переменную вводится значение иногда вручную, и вот оно стало нужно
С типами данных до этого я не заморачивался, в конечном итоге мне нужен FLOAT, ну я как-бы сделал все переменные одинаковые, чтобы не думать)))
И тут неожиданно меня удивило!
Если попытаться от этого числа отнять единицу или прибавить, то просто ничего не происходит!
Ну в общем пример такой:
float count; void setup() { count=19087200.00; } void loop() { count = count - 1.00; // count--; Serial.print("COUNT: "); Serial.println(count); delay(100); }
Когда этот код работает, то в переменной count ничего не отнимается, число остаётся тоже, ошибки не происходит и остановки программы тоже не происходит, просто показывает одно и тоже число.
Если ументшить число на один разряд например сделать 1908720.00 , то все считает хорошо.
Зачем мне так нужно было?
Потому что я это число делю на одно, потом на другое и мне нужно получить число с запятой, напрмер:
w = (count/1928.00)/2.00;
Ну вот впринципе и все.
Я обошел эту проблему так:
long count; float w; void setup() { count=19087200; } void loop() { count = count - 1; // count--; w = (float(count)/1928.00)/2.00; Serial.print("COUNT: "); Serial.println(count); Serial.print("W: "); Serial.println(w); delay(100); }
Но мне всеравно интересно что скажут люди.
Спасибо за внимание!
Причина:
С типами данных до этого я не заморачивался, в конечном итоге мне нужен FLOAT, ну я как-бы сделал все переменные одинаковые, чтобы не думать)))
Следствие:
И тут неожиданно меня удивило!
О сколько нам открытий чудных
Готовят просвещенья дух
И опыт, сын ошибок трудных,
И гений, парадоксов друг,
И случай, бог изобретатель.
Сдесь на сайте черным по белому написано "Тип float имеет точность 6-7 знаков, имеются ввиду все знаки, а не только мантисса."
http://arduino.ru/Reference/Float
Romhik, собственно, это проблема на Ваша, а всего нашего школьного образования, которое делает вид, что целые и дробные числа - это почти одно и то же. А это далеко не так. И, соответственно, ни о какой взаимозаменяемости между ними не может быть и речи. Вы вдруг с этим столкнулись.
Просто пока примите к сведению, что целые и дробные числа - совершенно разные объекты с сильно отличающимися свойствами. В частности: целые числа всегда точные, а дробные числа в их компьютеном представлении - всегда приближенные.
Ну и на будущее запомните, для значения счетчика следует использовать исключительно целые числа. Просто потому, что они именно для этого и предназначены. А дробные на эту роль не подходят. С чем, собственно, Вы и столкнулись.
используй long long int, Люк. для большинства применений - хватит. Еще он обзывается int64_t.
Причина:
С типами данных до этого я не заморачивался, в конечном итоге мне нужен FLOAT, ну я как-бы сделал все переменные одинаковые, чтобы не думать)))
Следствие:
И тут неожиданно меня удивило!
О сколько нам открытий чудных
Готовят просвещенья дух
И опыт, сын ошибок трудных,
И гений, парадоксов друг,
И случай, бог изобретатель.
Хм странно)))
А я всегда думал, что причина - это лень
А следствие - это жадность))))
Сдесь на сайте черным по белому написано "Тип float имеет точность 6-7 знаков, имеются ввиду все знаки, а не только мантисса."
http://arduino.ru/Reference/Float
Ну если честно, то я читал эту инструкцию, но видимо плохо посчитал сколько у меня чисел получилось, спасибо за подсказку.
Но вообще конечно точность даже самого описания внушает "Тип float имеет точность 6-7 знаков...", как можно вообще говорить о точности при этом само выражение как бабка на двое сказала: точность 6-7 знаков...)))
Вот это и сбивает с толку точность шесть, семь))) Или семь на восемь)) Хотели написать о точности а вы шло 6-7...)))
Ну если честно, то я читал эту инструкцию, но видимо плохо посчитал сколько у меня чисел получилось, спасибо за подсказку.
вы не на то обратили внимание. Главное, что стоит усвоить из этого случая - для счетчиков использовать ТОЛЬКО ЦЕЛЫЕ числа.
Тип float вообще стоит использовать как можно реже.
Romhik, собственно, это проблема на Ваша, а всего нашего школьного образования, которое делает вид, что целые и дробные числа - это почти одно и то же. А это далеко не так. И, соответственно, ни о какой взаимозаменяемости между ними не может быть и речи. Вы вдруг с этим столкнулись.
Просто пока примите к сведению, что целые и дробные числа - совершенно разные объекты с сильно отличающимися свойствами. В частности: целые числа всегда точные, а дробные числа в их компьютеном представлении - всегда приближенные.
Ну и на будущее запомните, для значения счетчика следует использовать исключительно целые числа. Просто потому, что они именно для этого и предназначены. А дробные на эту роль не подходят. С чем, собственно, Вы и столкнулись.
Ну в общем-то согласен с вами, если-бы нормально объясняли в школе а не тупо читали программу, причем устаревшую и без особого интереса и энтузиазма.
То конечно ожидать многого не стоит. Просто некоторые люди по разному воспринимают информацию и я скажу, что практики нужно больше и тренировки мозга, решения задач, соревнования и т.д...
Ну в общем-то интересно конечно получается, что я это число могу хранить в переменной FLOAT, но ничего с ним не могу сделать никаких математических операций, если я правильно понял конечно.
Но меня самого сбивает вот это выражение, тогда почему это работает
:
float w = (float(count)/1928)/2; Если long count=19087200 - тут не 6-7 знаков а все 8используй long long int, Люк. для большинства применений - хватит. Еще он обзывается int64_t.
Премного вам благодарен, спасибо, теперь буду знать!
Ну если честно, то я читал эту инструкцию, но видимо плохо посчитал сколько у меня чисел получилось, спасибо за подсказку.
вы не на то обратили внимание. Главное, что стоит усвоить из этого случая - для счетчиков использовать ТОЛЬКО ЦЕЛЫЕ числа.
Тип float вообще стоит использовать как можно реже.
Спасибо, ну теперь буду знать, но пока не наступила жажда большего, он хорошо работал и люди были готовы с этим смириться)))) Но только не я))) А вообще конечно выступил хорошим сдерживающим фактором этот случай, считал считал и остановился, ну типа на сегодня хватит, а завтра все сначала начинай))))
как можно вообще говорить о точности при этом само выражение как бабка на двое сказала: точность 6-7 знаков...)))
Вот это и сбивает с толку точность шесть, семь))) Или семь на восемь)) Хотели написать о точности а вы шло 6-7...)))
Вообще-то 24 разряда точно. Естественно - двоичных. А уж как двоичные разряды пересчитаются в десятичные - зависит от числа. Вот, например, 4 двоичных разряда: числа от 0 до 15 - это один десятичный знак или два?
Ну в общем-то интересно конечно получается, что я это число могу хранить в переменной FLOAT, но ничего с ним не могу сделать никаких математических операций, если я правильно понял конечно.
Но меня самого сбивает вот это выражение, тогда почему это работает
:
float w = (float(count)/1928)/2; Если long count=19087200 - тут не 6-7 знаков а все 81. То, что не можете сделать - этому не объективная, а субъективные причина: ене можете потому, что не умеете. Если у Вас не подлучается извлечь из скрипки ни одного звука, от которого соседи не сходили бы с ума, то совершенно необязательно, что проблема в скрипке.
2. А кто Вам сказал, что в числе 19087200 восемь десятичных знаков? В продолжаете путсть между собой целые числа и числда с плавающей точкой - у низ по разному считаются знаки.
Ну в общем-то интересно конечно получается, что я это число могу хранить в переменной FLOAT, но ничего с ним не могу сделать никаких математических операций, если я правильно понял конечно.
Если не сталкивался - разберись что такое число с плавающей точкой и нормализованная запись числа. Не обязательно углубляться в дебри типа перемножения двоичных чисел в таком формате - главное понять как и для чего такая запись используется. И сразу станут понятны органичения при работе с такими формами записи числа.
Но вообще конечно точность даже самого описания внушает "Тип float имеет точность 6-7 знаков...", как можно вообще говорить о точности при этом само выражение как бабка на двое сказала: точность 6-7 знаков...)))
Вот это и сбивает с толку точность шесть, семь))) Или семь на восемь)) Хотели написать о точности а вы шло 6-7...)))
Да просто барыги писали язык программирования: "...ну там, пят-шэст... как хорошему другу дам сэм!".
Тут вон был один ELITE - так тоже страдал. Ему то '\0' в строку не докладывали, то функция размер массива считала не по закону Архимеда.
Я в Romhik-а верю. Он пытается разобраться, а не стонет. Конечно базовых знаний не зватает - значит много граблей соберет. :-)
Огромное Вам спасибо друзья за поддержку.
В самом начале статьи я написал, что в общем-то все решил, пока написал статью, жаль было просто потраченного времени, вот и решил оставить её, возможно для новичков таких как я.
У меня давно все работает и считает прекрасно!
Если честно, да, понимаю, что как бы знаний и опыта мало, что нужно больше учить и читать, экспериментировать, но где на это время найти, когда приходится работать, если бы еще за такие знания и саморазвитие доплачивали деньги)) А так приходится на скорую руку что-то лепить и по быстрому, да еще с гарантией и поддержкой, чтобы потом не остаться без работы...
В общем большое спасибо вашему форуму, вашему вниманию и вообще какие-бы коментарии не были, всеравно прияно находится в обществе умных людей и хоть как-то я вместе с вами развиваюсь.
Ну и последнее, так для интереса, я уже задавал этот вопрос, кому не лень, то может прокоментирует, почему все-таки на ардуино это работает:
Я имею в виду, что делить число float можно а вот прибавлять и отнимать от него или делать инкремент или декремент нельзя.
Или я чего-то не понимаю?
Ромик, давай вместе подумаем твоей башкой. Тебя в школе или этих ваших институтах учили, что действительное число может записываться по-разному, или 15.0643, допустим, или 1.50643Е1 , где Е1 - это 10 в степени 1. Это, так называемая "научная" запись числа. Теперь переведем твой счетчик в научное представление, т.е 19087200 у нас превратица в 1.9087200Е7. Теперь представь, что нам нужно прибавить к этому числу единицу. Запишем ее тоже в научной форме 1.0Е0. Если выровнять порядки (число после Е), то единицу можно записать как 0.0000001Е7, праильно? Теперь, нам говорят, что точность должна быть 6 цифр после запятой, тогда мы отрезаем по одной цифре с конца числа и получаем что?
Праильно, получаем 1.908720Е7 + 0.000000Е7, тоись единица для числа 19087200 находится ЗА ГРАНИЦЕЙ точности float, поэтому результат, матьтваю, НЕ МЕНЯЕТСЯ. Если числа отстоят друг от друга на N порядков, где N - точность представления float, то делать арифметические операцыи с ними - бессмысленно.
В компьютере запись числа - тоже происходит в "научном" формате, только Е - это не 10, как нам привычно а 2, как компу привычно и все дроби представляются приближенно относительно отрицательной степени двойки.
например 0.5 + 0.25 = 0.75 или 0.25 + 0.0625 = 0,3125
Ну и ещё: в МК типа НАНО, УНО, МЕГА нет типа float как природного явления. Эмулируется библиотеками и достаточно непродуктивно. Отсюда: везде где можно НАДО отказываться от float и решать задачу по возможности в целых числах.
Количество(!) тиков энкодера - в природе .. целое число.
В общем, заморочьтесь с типами и прочитайте учебники.
По поводу сложения-вычитания полностью согласен,
а вот по поводу умножения-деления там всё нормально.
Да, я имел ввиду, естесственно, сложение/вычитание.
Ну и ещё: в МК типа НАНО, УНО, МЕГА нет типа float как природного явления. Эмулируется библиотеками и достаточно непродуктивно.
Ох, Архат, писали бы Вы лучше о том, в чем хоть чуть-чуть разбираетесь...
Есть на всех типах Ардуино float. Причем, разумеется, по стандарту. И ни о какой эмуляции вообще речи быть не может. (Вопрос на засыпку: что именно нужно эмулировать?)
Ну а по поводу продуктивно/непродуктивно - вполне продуктивно, хотя и не слишком быстро. Аппаратной поддержки операций с плавающей точкой в Ардуино, разумеется, нет.
Поэтому к дальнейшему вполне разумно прислушаться (особенно к последней фразе):
Отсюда: везде где можно НАДО отказываться от float и решать задачу по возможности в целых числах.
Количество(!) тиков энкодера - в природе .. целое число.
В общем, заморочьтесь с типами и прочитайте учебники.
Ну и ещё: в МК типа НАНО, УНО, МЕГА нет типа float как природного явления. Эмулируется библиотеками и достаточно непродуктивно. Отсюда: везде где можно НАДО отказываться от float и решать задачу по возможности в целых числах.
Количество(!) тиков энкодера - в природе .. целое число.
В общем, заморочьтесь с типами и прочитайте учебники.
Давайте поясню ситуацию. w = (float(count)/1928.00)/2.00;
Где count - это количество импульсов с энкодера,
1928 - это число импульсов на один оборот энкодера,
2 - это число оборотов на метр.
И как считать сантиметры, если полностью отказаться от float?
Я пробовал использовать только цеые числа, считает только метры.
Я пробовал использовать только цеые числа, считает только метры.
Т.е. Вы считаете, что, используя целые числа, нельзя считать, скажем, в миллиметрах или в микронах?
PS. Я вот в логарифмической шкале работаю, используя лишь целочисленную арифметику, - и ничего, точность вполне устраивает.
у мня даже таблица синусов в int храница. И преобразовываеца уже только в самый последний момент, когда нужен float. :)
Я пробовал использовать только цеые числа, считает только метры.
Т.е. Вы считаете, что, используя целые числа, нельзя считать, скажем, в миллиметрах или в микронах?
PS. Я вот в логарифмической шкале работаю, используя лишь целочисленную арифметику, - и ничего, точность вполне устраивает.
Можно, но нужно заморачиваться а я не хочу, для того колхоза, что я сделал этого достаточно.
А больше или что-то сложней делать лень, потому что нет мотивации)))
Ромик, в любой непонятной ситуации - бухай. Не заморачивайса, если мотивации нет.
Ромик, в любой непонятной ситуации - бухай. Не заморачивайса, если мотивации нет.
Чтобы бухать нужна тоже мотивация)))
Кому как. Мне уже лет 10 как не нужна. У меня просто без вотки обмен веществ уже не идет. Какта она незаметно встроилась в биахимию организма.
Есть на всех типах Ардуино float.
не порите чушь, ей - больно. А если хотите настоять, то покажите мне команду Ассемблера с float. Хоть одну.
Давайте поясню ситуацию. w = (float(count)/1928.00)/2.00;
Где count - это количество импульсов с энкодера,
1928 - это число импульсов на один оборот энкодера,
2 - это число оборотов на метр.
И как считать сантиметры, если полностью отказаться от float?
Я пробовал использовать только цеые числа, считает только метры.
Плохо пробовали.
Можно, но нужно заморачиваться а я не хочу, для того колхоза, что я сделал этого достаточно.
А больше или что-то сложней делать лень, потому что нет мотивации)))
Ну вот это - как раз "аргумент". Тогда Вам - заморачиваться с float. И не только Вам, но ещё и контроллеру заморачиваться по самые уши. :)
Есть на всех типах Ардуино float.
не порите чушь, ей - больно. А если хотите настоять, то покажите мне команду Ассемблера с float. Хоть одну.
В огороде бузина, а в Киеве - дядька.
Какое вообще отношение имеет язык Ассемблера к Ардуино?
Более того, в семействе Ардуино используются различные контроллеры, язык Ассемблера которых совершенно различен и даже не является совместимым.
Т.е. для какдого конкретного контроллера можно говорить о языке Ассемблера, а для Ардуино - нет.
Соответственно, нет и инструкций. Ни одной. Ни для float, ни для integer, ни для byte.
Что же касается float, то для него есть стандарт IEEE 754, и Ардуино этот стандарт поддерживает. Чего Вам еще нужно?
Мало ли что и как поддерживает. Это ни разу не означает "следует использовать где надо и не надо". Вы прекрасно меня поняли, но интенсивно завиляли хвостом. Не поддерживает ни одна Ардуино плата на мегах (перечислены в первом сообщении, на которые вы "бурно отреагировали") float от слова НИКАК. Нет никакой нативной поддержки для float. И весь ваш "опус" - ровно ни о чем, кроме виляния хвостом. Хотя Вы сами признаетесь что пользуете целочисленную арифметику (и ранее тоже) .. забавно, правда? :)
Да чо сраца то. Дело то просто в понятиях.
Процессоры AVR - не поддерживают нативный float.
Платформа Arduino - поддерживает по стандарту IEEE.