LINUX.ORG.RU

Поиск в map<double>, может ли быть не нахождение того же значения, что добавили?

 


2

1

Возможна ли ситуация, что такая функция вернет истину?

bool to_do_test(double v) {
   map<double,double> m;
   m.insert({v,v});
   return m.find(v) == m.end();
}
Т.е. возможны ли ситуации изменения double при множественных операциях копирования и сохранения в контейнерах через десятки классов, без математических операций?

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

Makhno
()

Знатоки, как вам такой способ сравнения double :?

#include <cmath>
#include <limits>

bool AreSame(double a, double b) {
    return std::fabs(a - b) < std::numeric_limits<double>::epsilon();
}

rumgot ★★★★★
()

В общем виде не используй отношение == с float, double и т.п. Никогда и ни при каких обстоятельствах.
Вот и весь сказ.

Deleted
()
Ответ на: комментарий от rumgot

Не очень, но для очень приблизительных задач сойдет. Что если числа a и b таких порядков, что для их абсолютной разницы этот эпсилон всегда будет больше? Но при этом a и b достаточно разные, чтобы не считаться равными.

Makhno
()

Возможна ли ситуация, что такая функция вернет истину?

Нет.

d_a ★★★★★
()

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

Нет? Но это не точно.

PS: --fast-math у GCC может испортить это, вроде как.

RazrFalcon ★★★★★
()
Последнее исправление: RazrFalcon (всего исправлений: 1)

Тще, гнилая идея. Если так нужен мап - вставляй в качестве ключа уже подготовленное значение обрезав нецелую часть перед вставкой до нужных разрядов, умноженную например на мильен и приведенную к целому. Т. Е. Мап<уинт,дабл> Каконить

deep-purple ★★★★★
()
Ответ на: комментарий от rumgot

как вам такой способ сравнения double

Этот способ ошибочен. Epsilon это разница между 1.0 и следующим представимым числом, поэтому для чисел прилично больше единицы эта функция будет эквивалентна точному равенству, а для чисел меньше единицы будет слишком «прощающей».

i-rinat ★★★★★
()
Ответ на: комментарий от rumgot

Знатоки, как вам такой способ сравнения double :?

Там все сложно.

https://en.cppreference.com/w/cpp/types/numeric_limits/epsilon

template<class T>
typename std::enable_if<!std::numeric_limits<T>::is_integer, bool>::type
    almost_equal(T x, T y, int ulp)
{
    // the machine epsilon has to be scaled to the magnitude of the values used
    // and multiplied by the desired precision in ULPs (units in the last place)
    return std::abs(x-y) <= std::numeric_limits<T>::epsilon() * std::abs(x+y) * ulp
        // unless the result is subnormal
        || std::abs(x-y) < std::numeric_limits<T>::min();
}
KennyMinigun ★★★★★
()
Ответ на: комментарий от Deleted

В общем виде не используй отношение == с float, double и т.п. Никогда и ни при каких обстоятельствах.

Годный совет для школьного урока информатики, где учат программировать на gwBASIC.

Для людей, занимающихся коммерческой разработкой, будет полезно лучше (глубже) разбираться в числах с плавающей запятой, а также флагах компилятора и оптимизациях, которые на них влияют. Числа с плавающей запятой, по сути, вполне себе дискретные величины, дополненные NotaNumber, +/-Inf, +/-0. И хотя у них есть заморочки с округлением и порядком вычисления значения, но float и double - дискретные величины. Потому, если взять конкретное число, вставить его в std::map, а затем его же там искать - то оно будет найдено (с учетом NotaNumber, +/-Inf, +/-0).

anonymous
()
Ответ на: комментарий от anonymous

если взять конкретное число, вставить его в std::map, а затем его же там искать

Вот только эта конкретная задача не имеет смысла.
Да, если мы можем гарантировать что число не будет преобразовано, то оно совершенно ожидаемо, останется таким же и в таком же виде.
Но это вырожденный и совершенно теоретический случай.
Возможно интересный в масштабе «школьного урока информатики, где учат программировать на gwBASIC», но бессмысленный на практике.

Deleted
()
Ответ на: комментарий от Deleted

Вот только эта конкретная задача не имеет смысла.

Есть смысл, просто ты всех смыслов знать не можешь. Впрочем я осознал всю ответственность за использование find и переделал на такой код:

    void erase(double v, int i_pos) {
// multimap<double,int> mmap;
        auto itr = mmap.lower_bound(v-std::numeric_limits<double>::epsilon());
        for (;;) {
            assert( itr != mmap.end() );
            if (itr->second == i_pos) break;
            ++itr;
        }
        mmap.erase(itr);
    }
Вопрос остался чисто теоретический, может ли возникать ошибки с использованием find. Пока не возникали.

victor79
() автор топика
Ответ на: комментарий от KennyMinigun

Там все сложно.
https://en.cppreference.com/w/cpp/types/numeric_limits/epsilon
// and multiplied by the desired precision in ULPs (units in the last place)

Кстати, может мне кто объяснить, каков смысл в этом примере ULP - желаемая точность? В примере по ссылке используется 2, почему не 1?. Для каких случаев нужно ставить 2 или более?

victor79
() автор топика
Ответ на: комментарий от KennyMinigun

almost_equal(T x, T y, int ulp)
return std::abs(x-y) <= std::numeric_limits<T>::epsilon() * std::abs(x+y) * ulp || std::abs(x-y) < std::numeric_limits<T>::min()

Жуть: almost_equal(x, 0, 1) всегда будет ложью, пока порядок цифр аргумента x не станет меньше std::numeric_limits<T>::min(), что в свою очередь около 1e-300 для double.

Потому что при x <= epsilon, (x+0) <= esilon, а произведение двух epsilon будет всегда меньше чем epsilon.

victor79
() автор топика
Ответ на: комментарий от rumgot

0.5 - да, а сравнение на ноль, нет. Нулем она посчитает только значения меньше 1e-300 с модулем. Вся загвоздка, что epsilon это разница между единицей и следующей значащей цифрой от единицы.

victor79
() автор топика
Ответ на: комментарий от i-rinat

Ты написал выше, что если разница меньше 1 то слишком прощающая... Но получается, что не всегда.

rumgot ★★★★★
()
Ответ на: комментарий от i-rinat

Ну если они меньше чем epsilion то нормально.

rumgot ★★★★★
()

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

oldstable
()
11 мая 2019 г.

https://stackoverflow.com/a/8097097/9585016

Something I've always considered a little odd is that the standard expresses the requirements in terms of the key type, not in terms of the actual key values added to the container. I believe you could choose to read this as not guaranteeing that map<double, int> has defined behaviour at all if the implementation supports NaNs, regardless of whether you actually add a NaN to an instance or not.

Если считать, что map<double,double> приводит к неопределённому поведению, то возможно не только то, что элемент не найдётся в map, но и что твой хард будет отформатирован.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.