Одним из следствий стандарта IEEE 754 является неинтуитивное поведение std::unordered_set<double>
, когда вставляются элементы не числа (NAN
s).
В связи с тем, что NAN!=NAN
, после следующей последовательности:
#include <iostream>
#include <cmath>
#include <unordered_set>
int main(){
std::unordered_set<double> set;
set.insert(NAN);
set.insert(NAN);
std::cout<<"Number of elements "<<set.size()<<"\n"; //there are 2 elements!
}
Есть два элемента в set
( посмотреть его вживую ): NAN
и NAN
!
Моя главная проблема в том, что, когда N
NAN
s вставляются в хэш-набор, все они попадают в один и тот же хэш-контейнер, а производительность N
вставок в хэш-набор вырождается в наихудшее время работы - O(N^2)
.
Например, см. Листинг в конце вопроса или здесь в прямом эфире - вставка NAN
занимает на порядок больше времени, чем «обычное» плавающее число.
Мой вопрос: возможно ли (и если да - как) настроить std::unordered_set<double>
таким образом, чтобы в наборе было не более одного NAN
-элемента, независимо от того, был ли добавлен NAN
с (NAN
, - NAN
и т. д.)?
Листинг:
#include <iostream>
#include <cmath>
#include <unordered_set>
#include <chrono>
constexpr int N=5000;
void test_insert(double value)
{
std::unordered_set<double> s;
auto begin = std::chrono::high_resolution_clock::now();
for (int i = 0; i < N; i++) {
s.insert(value);
}
auto end = std::chrono::high_resolution_clock::now();
std::cout << "Duration: " << (std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin).count() / 1e9) << "\n";
std::cout << "Number of elements: "<<s.size()<<"\n";
}
int main(){
std::cout << "Not NAN\n";
test_insert(1.0); //takes 0.0001 s
std::cout << "NAN\n";
test_insert(NAN); //takes 0.2 s
}