Bir konteyner için anahtar olarak float türünü kullanmak iyi bir fikir mi?
sobes.tech yapay zeka
AI'dan gelen yanıt
İşlevsel konteynerler (örneğin, std::map, std::unordered_map) anahtarı olarak float kullanmak veya doğrudan sıralama yapmak aşağıdaki nedenlerden dolayı önerilmez:
-
Karşılaştırma sorunları:
float(veyadouble) türündeki iki sayının eşitliği, kayan nokta temsil hataları nedeniyle nadiren sağlanır.a == bkarşılaştırması yanlış sonuç verebilir, hatta matematiksel olarak eşit olsalar bile. Bu,std::mapvestd::setgibi katı zayıf sıralama gerektiren veya doğru hash ve eşitlik karşılaştırması yapan konteynerlerin ilkelerini ihlal eder. -
Yanlış sıralama:
floatiçin standart karşılaştırma operatörleri, tüm olası değerler (örneğin NaN) için her zaman katı zayıf sıralama sağlamaz. -
Dengesiz hash:
floatiçin hash fonksiyonlarının uygulanması, aynı temsil hataları nedeniyle dengesiz olabilir, bu da öngörülemeyen davranışlara veya düşük performansa yol açar.
Tavsiye edilen yaklaşımlar:
-
Tam sayı temsili kullanmak: Hassasiyet önemli değilse veya sayılar sınırlı bir aralık ve çözünürlüğe sahipse,
float'ı ölçeklendirip tam sayıya (örneğin,intveyalong long) dönüştürüp anahtar olarak kullanabilirsiniz.float f = 1.23f; int key = static_cast<int>(f * 100); // Ölçeklendirme örneği std::map<int, Value> my_map; my_map[key] = some_value; -
Sabit nokta kullanmak: Ondalık sayıların tam temsil edilmesi gerekiyorsa, sabit nokta sayılarını kullanmak için kütüphane kullanılabilir.
-
Tolerans (epsilon) ile karşılaştırmak: Bu, doğrudan
float'ı anahtar olarak kullanmaya izin vermez, ancak arama sırasında küçük bir tolerans (epsilon) kullanılarak karşılaştırma yapılabilir.bool are_equal(float a, float b, float epsilon = 1e-6) { return std::abs(a - b) < epsilon; } // Bu, doğrudan map anahtarı karşılaştırması için uygun değildir -
Özelleştirilmiş karşılaştırıcı kullanmak (
std::map/std::setiçin): Toleransı dikkate alan bir karşılaştırıcı tanımlanabilir, ancak bu yine de katı zayıf sıralama ilkelerini ihlal edebilir.struct FloatComparer { bool operator()(float a, float b) const { // Basit örnek, katı zayıf sıralamayı ihlal edebilir return a < b - 1e-6; } }; // Gerçek uygulamalarda doğrudan kullanılması önerilmez // std::map<float, Value, FloatComparer> my_map; -
Bit temelli tam sayı temsili kullanmak (
std::unordered_map/std::unordered_setiçin): Hash tabloları için,float'ın bit temsili tam sayıya dönüştürülüp anahtar olarak kullanılabilir. Bu, her benzersizfloatbit temsili için anahtarın benzersizliğini sağlar, ancak matematiksel olarak eşit olan sayılar farklı bit temsillerine sahip olabileceği için (örneğin, 0.0 ve -0.0) sorunu çözmez.union FloatIntConverter { float f; int i; }; struct FloatHash { size_t operator()(float f) const { FloatIntConverter converter; converter.f = f; return std::hash<int>()(converter.i); } }; struct FloatEqual { bool operator()(float a, float b) const { // Bit temelli karşılaştırma FloatIntConverter converter_a, converter_b; converter_a.f = a; converter_b.f = b; return converter_a.i == converter_b.i; } }; // std::unordered_map<float, Value, FloatHash, FloatEqual> my_map; // Not: Bu, bit temelli karşılaştırma yapar, matematiksel eşitliği değil
Çoğu durumda, anahtarlar kayan nokta sayıları ise, veri yapısını yeniden gözden geçirmek veya tam sayı veya sabit nokta yaklaşımlarını kullanmak en iyisidir.