Функция map небезопасна

SuperXL
Offline
Зарегистрирован: 30.12.2011

Приветствую всех!

Выловил баг, или даже не баг, а возможную конфликтную ситуацию при использовании функции map.

Стояла задача нарисовать на экранчике прогресс-бар чтения файла с SD карты.

вот пример кода:

uint8_t progress_width = map(music_file.position(), 0, music_file.size(), 0, 100);

[пояснение для новичков: эта функция вычисляет ширину прогресса от 0 до 100 попугаев в зависимости от размера файла ( music_file.size() ) и той позиции, где сейчас читается файл (music_file.position() ). ]

В случае, если размер файла = 0 (битый, пустой, карточка барахлит итд) получается деление на ноль.

Внутри эта функция устроена так (файл WMath.cpp):

long map(long x, long in_min, long in_max, long out_min, long out_max) {
const long dividend = out_max - out_min;
const long divisor = in_max - in_min;
const long delta = x - in_min;

return (delta * dividend + (divisor / 2)) / divisor + out_min;
}
и получается, что uint8_t progress_width = map(music_file.position(), 0, 0, 0, 100); пытается значение
(delta * dividend + (divisor / 2)) разделить на divisor + out_min , а divisor и out_min = 0

Будьте осторожны.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ну так переписать чтобы не было деления на ноль, то-есть размер файла брать большим из 1 или длины файла

SuperXL
Offline
Зарегистрирован: 30.12.2011

Код уже исправлен, добавлена проверка на размер файла.

uint8_t progress_width = 0;
if (music_file.size() > 0) {
   progress_width = map(music_file.position(), 0, music_file.size(), 0, 100);
}

Просто такая ситуация может возникнуть у новичков.

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

SuperXL, а какова, по Вашему мнению, должна быть "ширина прогресс-бара" при длине файла равной нулю?

Назовите число.

Вывод: функция map в данном случае совершенно ни при чем. А вот автор кода забыл сделать необходимую проверку. Такая проблема может возникнуть с любой другой функцией при использовании подобного стиля программирования.

Т.е. небезопасна совсем не функция map, а стиль программирования, пренебрегающий проверками. 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

SuperXL пишет:

Код уже исправлен, добавлена проверка на размер файла.

uint8_t progress_width = 0;
if (music_file.size() > 0) {
   progress_width = map(music_file.position(), 0, music_file.size(), 0, 100);
}

Просто такая ситуация может возникнуть у новичков.

 и дальше что? по нормальному нужна функция обработчик ошибок, если при открытии файла длина равна нулю, возвращаем в обработчик соответствующий код ошибки и далее ветвить программу в соответствии с кодом ошибки, в вашем случае видимо перейти к открытию другого файла...но ситуации могут быть разные...типичная олимиадская задача... wdrakula сможет откомментировать авторитетно, он сильно в теме )))

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

SuperXL пишет:
пытается значение (delta * dividend + (divisor / 2)) разделить на divisor + out_min , а divisor и out_min = 0

Ну, разделить-то она пытается только на divisor, out_min  потом уже из результата вычитается. 

А что получается-то? Вы пробовали?

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

Собственно и оператор / небезопасен. У любого новичка с ним могут возникнуть проблемы ))

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

v258 пишет:
Собственно и оператор / небезопасен. У любого новичка с ним могут возникнуть проблемы ))

Народ, придумываем новый, безопасный ?

lilik
Offline
Зарегистрирован: 19.10.2017

brokly пишет:

Народ, придумываем новый, безопасный ?

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

SuperXL
Offline
Зарегистрирован: 30.12.2011

andriano пишет:

SuperXL, а какова, по Вашему мнению, должна быть "ширина прогресс-бара" при длине файла равной нулю?

Назовите число.

По моей логике, если файл имеет нулевой размер то и ширина бара тоже должна быть равна нулю. Что и реализовано в куске кода выше.

andriano пишет:

Вывод: функция map в данном случае совершенно ни при чем. А вот автор кода забыл сделать необходимую проверку. Такая проблема может возникнуть с любой другой функцией при использовании подобного стиля программирования.

Т.е. небезопасна совсем не функция map, а стиль программирования, пренебрегающий проверками. 

Согласен с Вами, что подобный подход к написанию кода является нежелательным. Автор кода, который написал функцию map мог, действительно, написать проверку на предмет ситуации деления на ноль. Только вот каков результат должна вернуть эта функция - спорный момент. Опять по моей же логике, хотя случаи разные бывают, функция должна вернуть long out_min, если мы говорим о том, что out_min < out_max.

В моем случае, ESP32 просто уходила в "кернел_1 паник" с указанием на то, что где-то есть деление целого числа на ноль. Возможно, дебагер показал бы где затык, но не имея онного пришлось, отслеживать Serial.print-ами.

 

ua6em пишет:

 и дальше что? по нормальному нужна функция обработчик ошибок, если при открытии файла длина равна нулю, возвращаем в обработчик соответствующий код ошибки и далее ветвить программу в соответствии с кодом ошибки, в вашем случае видимо перейти к открытию другого файла...но ситуации могут быть разные...типичная олимиадская задача... wdrakula сможет откомментировать авторитетно, он сильно в теме )))

я привел совсем меленький кусочек кода, который вычисляет ширину бара, естественно есть еще и до и после. Отрисовка бара идет через функцию из задачи повторяющейся с интервалом 200 мс. И эта функция отвечает только за вычисление/отрисовку, все проверки, флаги разрешения и прочее ранее.

По поводу олимПиадских задач, мимо. Это не про меня. Я делаю свой девайс. Ну нравится мне кулибничать да паялить чё-нить.

ЕвгенийП пишет:

SuperXL пишет:
пытается значение (delta * dividend + (divisor / 2)) разделить на divisor + out_min , а divisor и out_min = 0

Ну, разделить-то она пытается только на divisor, out_min  потом уже из результата вычитается. 

А что получается-то? Вы пробовали?

Получается то, что ESP32 вываливается в "кернел_1 паник", я выше написал, как это выглядит. Если честно, не совсем Вас понял про то, что пробовал ли я что-то. Если Вы про то, что посчитать конечный результат функции, то да.

v258 пишет:
Собственно и оператор / небезопасен. У любого новичка с ним могут возникнуть проблемы ))

Новичек на то и новичек, чтобы творить, ошибаться и учиться, по большей степени, на чужих ошибках.

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

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

Очень рекомендую смотреть, что конкретно пишет esp, а она вам прям конкретно пишет ошибку. Просто нужно уметь это читать. Более того, скажите спасибо, что есп так делает. Другие процы молча пичкают возвращаемую переменную дерьмом, не побоюсь этого слова.

SuperXL
Offline
Зарегистрирован: 30.12.2011

brokly пишет:

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

Очень рекомендую смотреть, что конкретно пишет esp, а она вам прям конкретно пишет ошибку. Просто нужно уметь это читать. Более того, скажите спасибо, что есп так делает. Другие процы молча пичкают возвращаемую переменную дерьмом, не побоюсь этого слова.

:-) Согласен с Вами, что деление на ноль дает бесконечность, но, как Вы сказали при нулевом размере файла градусник должен показывать бесконечно нулевой размер. ))

ESP-шка мне и написала, что идет где-то  деление на ноль целого числа. Полез разбираться, где идет именно деление, вышел на map. Залез под капот функции map и обнаружил, то что описал в первом посте. 

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

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

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

Стремящийся к нулю - это бесконечно малый.

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Насколько далеко от нуля бесконечно малое значение ? 

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

Вопрос некорректный.

Главное другое - бесконечно малое никогда не равно нулю.

rkit
Offline
Зарегистрирован: 23.11.2016

Всю математику перекроили, рамануджаны млять.

Деление на ноль не сходится.

Числа "бесконечность" нет.

Бесконечно малое (в контексте близкое к нулю) это ноль.

А если в контексте операции "меньше", то не сходится.

Logik
Offline
Зарегистрирован: 05.08.2014

brokly пишет:

Насколько далеко от нуля бесконечно малое значение ? 

Отличается менее чем на эпсилон.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

rkit пишет:

Деление на ноль не сходится.

Числа "бесконечность" нет.

? ?? ???? ????????

...ушел сдавать в макулатуру диплом МехМата.

lilik
Offline
Зарегистрирован: 19.10.2017

brokly пишет:

Насколько далеко от нуля бесконечно малое значение ? 

Бесконечно близко :-)

Logik
Offline
Зарегистрирован: 05.08.2014

wdrakula пишет:

rkit пишет:

Деление на ноль не сходится.

Числа "бесконечность" нет.

? ?? ???? ????????

...ушел сдавать в макулатуру диплом МехМата.

Не примут. Жесткий сильно. Используй как подставку под сковородку.

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

lilik пишет:

Бесконечно близко :-)

Хорошо, плюсанул :)

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

rkit пишет:

Всю математику перекроили, рамануджаны млять.

Деление на ноль не сходится.

Числа "бесконечность" нет.

Бесконечно малое (в контексте близкое к нулю) это ноль.

А если в контексте операции "меньше", то не сходится.

Как всегда без аргументов и сплошной поток мысли... С чем не сходится, с представлением о мире ?

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

andriano пишет:

Вопрос некорректный.

Главное другое - бесконечно малое никогда не равно нулю.

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

lilik
Offline
Зарегистрирован: 19.10.2017

andriano пишет:

Главное другое - бесконечно малое никогда не равно нулю.

Тут мы всегда с "математичкой" ругались, потому что "физичка" была за нас :-)

Ведь с любой желаемой степенью точности это бм можно считать нулём.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

lilik пишет:

Ведь с любой желаемой степенью точности это бм можно считать нулём.

А как же Вы разрешали парадокс Зенона? Он ведь в конечных величинах неразрешим.

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

А они вместо этого в "Соки-воды" ходили и каждый просил тетеньку налить ему половину того, что было выдано предыдущему.

lilik
Offline
Зарегистрирован: 19.10.2017

ЕвгенийП пишет:

lilik пишет:

Ведь с любой желаемой степенью точности это бм можно считать нулём.

А как же Вы разрешали парадокс Зенона? Он ведь в конечных величинах неразрешим.

:-)

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

AndreyD
AndreyD аватар
Offline
Зарегистрирован: 07.10.2018

Физически есть абсолютный ноль, а математически?

lilik
Offline
Зарегистрирован: 19.10.2017

Вопросов больше чем ответов...

Что точнее 0 или 0.0 или 0.00 или ... ?

Если есть 0 есть ли -0?  Насколько они бесконечно близки друг другу?

Как правильно писать ноль, нуль или зеро?

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

lilik пишет:

Если есть 0 есть ли -0?  Насколько они бесконечно близки друг другу?

В программировании, конечно есть. Причём, 0 > -0 даёт истину.

А на Зенона попрошу не катить. Этот человек в 1-ом веке н.э. сделал первое (из известных) программируемое устройство и научил мальчика (своего подмастерье) его программировать. Так что он великий предок всех программистов. Кроме того, он же сделал первый в истории торговый автомат ("wendig machine" на языке потенциального противника наших уважаемых партнёров). Так что автоматизаторы торговли его тоже свои родоначальником считают. Ну и, наконец, он создал хиробаллисту, которая под названием "Скорпион" стояла на вооружении римской армии около 500 лет - никем до сих пор не побитый рекорд ВПК.

lilik
Offline
Зарегистрирован: 19.10.2017

Не знал, мне запомнился по апории про бегуна и черепаху.

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

AndreyD пишет:

Физически есть абсолютный ноль, а математически?

Наоборот: физически - нет, а математически - есть.

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

lilik пишет:

Вопросов больше чем ответов...

Что точнее 0 или 0.0 или 0.00 или ... ?

Если есть 0 есть ли -0?  Насколько они бесконечно близки друг другу?

Как правильно писать ноль, нуль или зеро?

 

0.(0)

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

А начиналось все с градусника.....

Green
Offline
Зарегистрирован: 01.10.2015

Нет, не так. "А как хорошо начиналось...")

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Green пишет:

Нет, не так. "А как хорошо начиналось...")

ты лучше озвучь где купаться небезопасно )

Green
Offline
Зарегистрирован: 01.10.2015

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

Green
Offline
Зарегистрирован: 01.10.2015

На самом деле, дурак - дураком! Эх, тогда бы теперешние мозги...(