Проблема с большими числами FLOAT

Romhik
Offline
Зарегистрирован: 11.10.2017

Здравствуйте дорогие друзья!

В общем в интернете долго искал это явление, но так и не нашел или может быть плохо искал, поэтому решил написать сюда, может быть гуру ответят на мой вопрос или может быть кто-то уже также наступил на те-же грабли...

Я в общем для себя уже решил эту проблему, но просто интересно стало...

Суть проблемы такова:

Есть число, которое хранится в переменной 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);
}

Но мне всеравно интересно что скажут люди.
Спасибо за внимание!
 

sva_khv
Offline
Зарегистрирован: 19.12.2016

Причина:

Romhik пишет:

С типами данных до этого я не заморачивался, в конечном итоге мне нужен FLOAT, ну я как-бы сделал все переменные одинаковые, чтобы не думать)))

Следствие:

Romhik пишет:

И тут неожиданно меня удивило!

О сколько нам открытий чудных

Готовят просвещенья дух

И опыт, сын ошибок трудных,

И гений, парадоксов друг,

И случай, бог изобретатель.

 

sva_khv
Offline
Зарегистрирован: 19.12.2016

Сдесь на сайте черным по белому написано  "Тип float имеет точность 6-7 знаков, имеются ввиду все знаки, а не только мантисса."

http://arduino.ru/Reference/Float

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Romhik, собственно, это проблема на Ваша, а всего нашего школьного образования, которое делает вид, что целые и дробные числа - это почти одно и то же. А это далеко не так. И, соответственно, ни о какой взаимозаменяемости между ними не может быть и речи. Вы вдруг с этим столкнулись. 

Просто пока примите к сведению, что целые и дробные числа - совершенно разные объекты с сильно отличающимися свойствами. В частности: целые числа всегда точные, а дробные числа в их компьютеном представлении - всегда приближенные

Ну и на будущее запомните, для значения счетчика следует использовать исключительно целые числа. Просто потому, что они именно для этого и предназначены. А дробные на эту роль не подходят. С чем, собственно, Вы и столкнулись.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

используй long long int, Люк.  для большинства применений - хватит.  Еще он обзывается int64_t.

Romhik
Offline
Зарегистрирован: 11.10.2017

sva_khv пишет:

Причина:

Romhik пишет:

С типами данных до этого я не заморачивался, в конечном итоге мне нужен FLOAT, ну я как-бы сделал все переменные одинаковые, чтобы не думать)))

Следствие:

Romhik пишет:

И тут неожиданно меня удивило!

О сколько нам открытий чудных

Готовят просвещенья дух

И опыт, сын ошибок трудных,

И гений, парадоксов друг,

И случай, бог изобретатель.

 

Хм странно)))
А я всегда думал, что причина - это лень

А следствие - это жадность))))

Romhik
Offline
Зарегистрирован: 11.10.2017

sva_khv пишет:

Сдесь на сайте черным по белому написано  "Тип float имеет точность 6-7 знаков, имеются ввиду все знаки, а не только мантисса."

http://arduino.ru/Reference/Float

Ну если честно, то  я читал эту инструкцию, но видимо плохо посчитал сколько у меня чисел получилось, спасибо за подсказку.

Но вообще конечно точность даже самого описания внушает "Тип float имеет точность 6-7 знаков...", как можно вообще говорить о точности при этом само выражение как бабка на двое сказала: точность 6-7 знаков...)))
Вот это и сбивает с толку точность шесть, семь))) Или семь на восемь)) Хотели написать о точности а вы шло 6-7...)))

b707
Offline
Зарегистрирован: 26.05.2017

Romhik пишет:

Ну если честно, то  я читал эту инструкцию, но видимо плохо посчитал сколько у меня чисел получилось, спасибо за подсказку.

вы не на то обратили внимание. Главное, что стоит усвоить из этого случая - для счетчиков использовать ТОЛЬКО ЦЕЛЫЕ числа.

Тип float вообще стоит использовать как можно реже.

Romhik
Offline
Зарегистрирован: 11.10.2017

andriano пишет:

Romhik, собственно, это проблема на Ваша, а всего нашего школьного образования, которое делает вид, что целые и дробные числа - это почти одно и то же. А это далеко не так. И, соответственно, ни о какой взаимозаменяемости между ними не может быть и речи. Вы вдруг с этим столкнулись. 

Просто пока примите к сведению, что целые и дробные числа - совершенно разные объекты с сильно отличающимися свойствами. В частности: целые числа всегда точные, а дробные числа в их компьютеном представлении - всегда приближенные

Ну и на будущее запомните, для значения счетчика следует использовать исключительно целые числа. Просто потому, что они именно для этого и предназначены. А дробные на эту роль не подходят. С чем, собственно, Вы и столкнулись.

Ну в общем-то согласен с вами, если-бы нормально объясняли в школе а не тупо читали программу, причем устаревшую и без особого интереса и энтузиазма.
То конечно ожидать многого не стоит. Просто некоторые люди по разному воспринимают информацию и я скажу, что практики нужно больше и тренировки мозга, решения задач, соревнования и т.д...

Ну в общем-то интересно конечно получается, что я это число могу хранить в переменной FLOAT, но ничего с ним не могу сделать никаких математических операций, если я правильно понял конечно.
Но меня самого сбивает вот это выражение, тогда почему это работает: float w = (float(count)/1928)/2; Если long count=19087200 - тут не 6-7 знаков а все 8

Romhik
Offline
Зарегистрирован: 11.10.2017

DetSimen пишет:

используй long long int, Люк.  для большинства применений - хватит.  Еще он обзывается int64_t.

Премного вам благодарен, спасибо, теперь буду знать!

Romhik
Offline
Зарегистрирован: 11.10.2017

b707 пишет:

Romhik пишет:

Ну если честно, то  я читал эту инструкцию, но видимо плохо посчитал сколько у меня чисел получилось, спасибо за подсказку.

вы не на то обратили внимание. Главное, что стоит усвоить из этого случая - для счетчиков использовать ТОЛЬКО ЦЕЛЫЕ числа.

Тип float вообще стоит использовать как можно реже.

Спасибо, ну теперь буду знать, но пока не наступила жажда большего, он хорошо работал и люди были готовы с этим смириться)))) Но только не я))) А вообще конечно выступил хорошим сдерживающим фактором этот случай, считал считал и остановился, ну типа на сегодня хватит, а завтра все сначала начинай))))

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Romhik пишет:

как можно вообще говорить о точности при этом само выражение как бабка на двое сказала: точность 6-7 знаков...)))

Вот это и сбивает с толку точность шесть, семь))) Или семь на восемь)) Хотели написать о точности а вы шло 6-7...)))

Вообще-то 24 разряда точно. Естественно - двоичных. А уж как двоичные разряды пересчитаются в десятичные - зависит от числа. Вот, например, 4 двоичных разряда: числа от 0 до 15 - это один десятичный знак или два?

Romhik пишет:

Ну в общем-то интересно конечно получается, что я это число могу хранить в переменной FLOAT, но ничего с ним не могу сделать никаких математических операций, если я правильно понял конечно.

Но меня самого сбивает вот это выражение, тогда почему это работает:float w = (float(count)/1928)/2; Если long count=19087200 - тут не 6-7 знаков а все 8

1. То, что не можете сделать - этому не объективная, а субъективные причина: ене можете потому, что не умеете. Если у Вас не подлучается извлечь из скрипки ни одного звука, от которого соседи не сходили бы с ума, то совершенно необязательно, что проблема в скрипке.

2. А кто Вам сказал, что в числе 19087200 восемь десятичных знаков? В продолжаете путсть между собой целые числа и числда с плавающей точкой - у низ по разному считаются знаки.

sva_khv
Offline
Зарегистрирован: 19.12.2016

Romhik пишет:

Ну в общем-то интересно конечно получается, что я это число могу хранить в переменной FLOAT, но ничего с ним не могу сделать никаких математических операций, если я правильно понял конечно.

Если не сталкивался  - разберись что такое число с плавающей точкой и нормализованная запись числа. Не обязательно углубляться в дебри  типа перемножения двоичных чисел в таком формате - главное понять как и для чего такая запись используется. И сразу станут понятны органичения при работе с такими формами записи числа.

sadman41
Offline
Зарегистрирован: 19.10.2016

Romhik пишет:

Но вообще конечно точность даже самого описания внушает "Тип float имеет точность 6-7 знаков...", как можно вообще говорить о точности при этом само выражение как бабка на двое сказала: точность 6-7 знаков...)))

Вот это и сбивает с толку точность шесть, семь))) Или семь на восемь)) Хотели написать о точности а вы шло 6-7...)))

Да просто барыги писали язык программирования: "...ну там, пят-шэст... как хорошему другу дам сэм!".

Тут вон был один ELITE - так тоже страдал. Ему то '\0' в строку не докладывали, то функция размер массива считала не по закону Архимеда.

sva_khv
Offline
Зарегистрирован: 19.12.2016

Я в  Romhik-а верю. Он пытается разобраться, а не стонет. Конечно базовых знаний не зватает - значит много граблей соберет. :-) 

Romhik
Offline
Зарегистрирован: 11.10.2017

Огромное Вам спасибо друзья за поддержку.
В самом начале статьи я написал, что в общем-то все решил, пока написал статью, жаль было просто потраченного времени, вот и решил оставить её, возможно для новичков таких как я.
У меня давно все работает и считает прекрасно!
Если честно, да, понимаю, что как бы знаний и опыта мало, что нужно больше учить и читать, экспериментировать, но где на это время найти, когда приходится работать, если бы еще за такие знания и саморазвитие доплачивали деньги)) А так приходится на скорую руку что-то лепить и по быстрому, да еще с гарантией и поддержкой, чтобы потом не остаться без работы...
В общем большое спасибо вашему форуму, вашему вниманию и вообще какие-бы коментарии не были, всеравно прияно находится в обществе умных людей и хоть как-то я вместе с вами развиваюсь.

Ну и последнее, так для интереса, я уже задавал этот вопрос, кому не лень, то может прокоментирует, почему все-таки на ардуино это работает:

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 можно а вот прибавлять и отнимать от него или делать инкремент или декремент нельзя.
Или я чего-то не понимаю?

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Ромик, давай вместе подумаем твоей башкой.  Тебя в школе или этих ваших институтах учили, что действительное число может записываться по-разному, или 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  

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Ну и ещё: в МК типа НАНО, УНО, МЕГА нет типа float как природного явления. Эмулируется библиотеками и достаточно непродуктивно. Отсюда: везде где можно НАДО отказываться от float и решать задачу по возможности в целых числах.

Количество(!) тиков энкодера - в природе .. целое число.

В общем, заморочьтесь с типами и прочитайте учебники.

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

DetSimen пишет:
Если числа отстоят друг от друга на N порядков, где N - точность представления float, то делать арифметические операцыи с ними - бессмысленно.

По поводу сложения-вычитания полностью согласен,
а вот по поводу умножения-деления там всё нормально.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Да, я имел ввиду, естесственно, сложение/вычитание. 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Arhat109-2 пишет:

Ну и ещё: в МК типа НАНО, УНО, МЕГА нет типа float как природного явления. Эмулируется библиотеками и достаточно непродуктивно.

Ох, Архат, писали бы Вы лучше о том, в чем хоть чуть-чуть разбираетесь...

Есть на всех типах Ардуино float. Причем, разумеется, по стандарту. И ни о какой эмуляции вообще речи быть не может. (Вопрос на засыпку: что именно нужно эмулировать?)

Ну а по поводу продуктивно/непродуктивно - вполне продуктивно, хотя и не слишком быстро. Аппаратной поддержки операций с плавающей точкой в Ардуино, разумеется, нет.

Поэтому к дальнейшему вполне разумно прислушаться (особенно к последней фразе):

Цитата:

Отсюда: везде где можно НАДО отказываться от float и решать задачу по возможности в целых числах.

Количество(!) тиков энкодера - в природе .. целое число.

В общем, заморочьтесь с типами и прочитайте учебники.

Romhik
Offline
Зарегистрирован: 11.10.2017

Arhat109-2 пишет:

Ну и ещё: в МК типа НАНО, УНО, МЕГА нет типа float как природного явления. Эмулируется библиотеками и достаточно непродуктивно. Отсюда: везде где можно НАДО отказываться от float и решать задачу по возможности в целых числах.

Количество(!) тиков энкодера - в природе .. целое число.

В общем, заморочьтесь с типами и прочитайте учебники.

Давайте поясню ситуацию. w = (float(count)/1928.00)/2.00;
Где count - это количество импульсов с энкодера,
1928 - это число импульсов на один оборот энкодера,
2 - это число оборотов на метр.
И как считать сантиметры, если полностью отказаться от float?
Я пробовал использовать только цеые числа, считает только метры.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Romhik пишет:

Я пробовал использовать только цеые числа, считает только метры.

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

 

PS. Я вот в логарифмической шкале работаю, используя лишь целочисленную арифметику, - и ничего, точность вполне устраивает.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

у мня даже таблица синусов в int  храница.  И преобразовываеца уже только в самый последний момент, когда нужен float. :) 

Romhik
Offline
Зарегистрирован: 11.10.2017

andriano пишет:

Romhik пишет:

Я пробовал использовать только цеые числа, считает только метры.

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

 

PS. Я вот в логарифмической шкале работаю, используя лишь целочисленную арифметику, - и ничего, точность вполне устраивает.

Можно, но нужно заморачиваться а я не хочу, для того колхоза, что я сделал этого достаточно.
А больше или что-то сложней делать лень, потому что нет мотивации)))

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Ромик, в любой непонятной ситуации - бухай. Не заморачивайса, если мотивации нет.

Romhik
Offline
Зарегистрирован: 11.10.2017

DetSimen пишет:

Ромик, в любой непонятной ситуации - бухай. Не заморачивайса, если мотивации нет.

Чтобы бухать нужна тоже мотивация)))

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Кому как. Мне уже лет 10 как не нужна. У меня просто без вотки обмен веществ уже не идет. Какта она незаметно встроилась в биахимию организма.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

andriano пишет:

Есть на всех типах Ардуино float.

не порите чушь, ей - больно. А если хотите настоять, то покажите мне команду Ассемблера с float. Хоть одну.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Romhik пишет:

Давайте поясню ситуацию. w = (float(count)/1928.00)/2.00;
Где count - это количество импульсов с энкодера,
1928 - это число импульсов на один оборот энкодера,
2 - это число оборотов на метр.
И как считать сантиметры, если полностью отказаться от float?
Я пробовал использовать только цеые числа, считает только метры.

Плохо пробовали.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Romhik пишет:

Можно, но нужно заморачиваться а я не хочу, для того колхоза, что я сделал этого достаточно.
А больше или что-то сложней делать лень, потому что нет мотивации)))

Ну вот это - как раз "аргумент". Тогда Вам - заморачиваться с float. И не только Вам, но ещё и контроллеру заморачиваться по самые уши. :)

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Arhat109-2 пишет:

andriano пишет:

Есть на всех типах Ардуино float.

не порите чушь, ей - больно. А если хотите настоять, то покажите мне команду Ассемблера с float. Хоть одну.

В огороде бузина, а в Киеве - дядька.

Какое вообще отношение имеет язык Ассемблера к Ардуино?

Более того, в семействе Ардуино используются различные контроллеры, язык Ассемблера которых совершенно различен и даже не является совместимым. 

Т.е. для какдого конкретного контроллера можно говорить о языке Ассемблера, а для Ардуино - нет.

Соответственно, нет и инструкций. Ни одной. Ни для float, ни для integer, ни для byte.

 

Что же касается float, то для него есть стандарт IEEE 754, и Ардуино этот стандарт поддерживает. Чего Вам еще нужно?

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Мало ли что и как поддерживает. Это ни разу не означает "следует использовать где надо и не надо". Вы прекрасно меня поняли, но интенсивно завиляли хвостом. Не поддерживает ни одна Ардуино плата на мегах (перечислены в первом сообщении, на которые вы "бурно отреагировали") float от слова НИКАК. Нет никакой нативной поддержки для float. И весь ваш "опус" - ровно ни о чем, кроме виляния хвостом. Хотя Вы сами признаетесь что пользуете целочисленную арифметику (и ранее тоже) .. забавно, правда? :)

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Да чо сраца то. Дело то просто в понятиях.

Процессоры AVR - не поддерживают нативный float.

Платформа Arduino - поддерживает по стандарту IEEE.