Sobes.tech
Middle

Konteyner üçün açar kimi float növünü istifadə etmək yaxşı fikir mi?

sobes.tech Süni İntellekt

AI-dan cavab

İstifadə float kimi açar üçün əlaqəli konteynerlərdə (məsələn, std::map, std::unordered_map) və ya birbaşa sıralama üçün aşağıdakı səbəblərə görə tövsiyə edilmir:

  • Müqayisə problemləri: float (və ya double) tipində iki ədədin bərabərliyi nadir hallarda əldə edilir, çünki onlayn təmsil səhvləri mövcuddur. a == b müqayisəsi yalnış nəticə verə bilər, hətta ədədlər riyazi olaraq bərabər olsa da. Bu, std::mapstd::set kimi konteynerlərin sərt zəif sıralama prinsiplərini pozur və ya std::unordered_mapstd::unordered_set üçün düzgün hash və bərabərlik müqayisəsini pozur.

  • Yanlış sıralama: float üçün standart müqayisə operatorları hər zaman bütün mümkün dəyərlər üçün sərt zəif sıralama təmin etmir (məsələn, NaN).

  • Etibarsız hash: float üçün hash funksiyalarının tətbiqi eyni təmsil problemləri səbəbindən etibarsız ola bilər və bu, proqnozlaşdırılmayan davranışlara və ya aşağı performansa səbəb ola bilər.

Tövsiyə olunan yanaşmalar:

  1. Tam ədəd təmsilindən istifadə: Əgər dəqiqlik vacib deyilsə və ya ədədlər məhdud diapazon və həllə malikdirsə, float-i ölçüləndirərək tam ədədə (məsələn, int və ya long long) çevirmək və onu açar kimi istifadə etmək olar.

    float f = 1.23f;
    int key = static_cast<int>(f * 100); // Ölçüləndirmə nümunəsi
    std::map<int, Value> my_map;
    my_map[key] = some_value;
    
  2. Sabit nöqtə istifadə etmək: Əgər onluq ədədlərin dəqiq təmsili tələb olunursa, sabit nöqtə ilə işləyən kitabxanadan istifadə etmək olar.

  3. Toleransla müqayisə (epsilon): Bu, float-i birbaşa açar kimi istifadə etməyə imkan verməsə də, axtarış zamanı kiçik bir epsilon ilə müqayisə edilə bilər.

    bool are_equal(float a, float b, float epsilon = 1e-6) {
        return std::abs(a - b) < epsilon;
    }
    // Birbaşa açar kimi istifadə üçün uyğun deyil
    
  4. İstifadəçi tərəfindən təyin olunan müqayisəçi istifadə etmək (məsələn, std::map/std::set üçün): Toleransı nəzərə alan xüsusi müqayisəçi təyin etmək mümkündür, lakin bu, sərt zəif sıralama prinsiplərini pozma riskini daşıyır.

    struct FloatComparer {
        bool operator()(float a, float b) const {
            // Sadə nümunə, sərt zəif sıralama pozula bilər
            return a < b - 1e-6;
        }
    };
    // Əsl tətbiqlərdə istifadə etmək tövsiyə edilmir
    // std::map<float, Value, FloatComparer> my_map;
    
  5. Bit təmsilindən tam ədədə çevirmək (məsələn, std::unordered_map/std::unordered_set üçün): Hash cədvəlləri üçün float-in bit təmsilini tam ədədə çevirmək və onu açar kimi istifadə etmək olar. Bu, hər unikal float bit təmsilatı üçün unikal açar təmin edir, lakin float-in riyazi bərabər olduğu, lakin fərqli bit təmsilatı olan ədədlər (məsələn, 0.0 və -0.0) problemini həll etmir.

    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 təmsilatı ilə müqayisə
            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;
    // Diqqət: Bu, bit təmsilatı ilə müqayisə edir, riyazi bərabərlik deyil
    

Əksər hallarda, əgər açarlar onluq ədədlərdirsə, məlumat quruluşunu yenidən nəzərdən keçirmək və ya tam ədəd və ya sabit nöqtə yanaşmasından istifadə etmək daha məqsədəuyğundur.