Vai ir laba ideja izmantot float tipu kā atslēgu konteineram?
sobes.tech AI
Atbilde no AI
Nepieciešams izmantot float kā atslēgu asociatīvos konteineros (piemēram, std::map, std::unordered_map) vai tieši kārtošanai, tas nav ieteicams šādu iemeslu dēļ:
-
Salīdzināšanas problēmas: Divi
floatskaitļi (vaidouble) reti ir vienādi, jo pludiņa punktu pārstāvības kļūdas dēļ.a == bsalīdzinājums var dot nepareizu rezultātu, pat ja matemātiski tie ir vienādi. Tas pārkāpj konteineru invarianus, kas pieprasa stingru vājo kārtību (std::mapunstd::set) vai pareizu haša un vienlīdzības aprēķinu (std::unordered_mapunstd::unordered_set). -
Nepareiza kārtošana:
floatsalīdzināšanas operatori ne vienmēr nodrošina stingru vājo kārtību visām iespējamām vērtībām (piemēram, NaN). -
Nestabils hašs:
floathaša funkciju realizācija var būt nestabila, jo tā pati pārstāvība var radīt neparedzamu uzvedību vai zemu veiktspēju haša tabulās:
Ieteicamās pieejas:
-
Izmantot veselos skaitļus: Ja precizitāte nav būtiska vai skaitļiem ir ierobežots diapazons un rezolūcija, var mēģināt mērogošanu un pārveidot
floatuz veselo skaitli (piemēram,intvailong long) un izmantot to kā atslēgu:float f = 1.23f; int atslēga = static_cast<int>(f * 100); // Mērogošanas piemērs std::map<int, Value> mana_karte; mana_karte[atslēga] = kāda_vērtība; -
Izmantot fiksētu punktu: Ja nepieciešama precīza daļskaitļu pārstāvība, var izmantot fiksēta punkta skaitļu bibliotēku.
-
Salīdzināt ar pieļaujamu novirzi (epsilon): Lai gan tas tieši neļauj izmantot
floatkā atslēgu, meklēšanas laikā var salīdzināt vērtības ar mazu pieļaujamu novirzi:bool irVienādi(float a, float b, float epsilon = 1e-6) { return std::abs(a - b) < epsilon; } // Nav ieteicams tieši izmantot kā atslēgu mapē -
Izmantot lietotāja definētu salīdzinātāju (
std::map/std::set): Var definēt lietotāja salīdzinātāju, kas ņem vērā pieļaujamo novirzi, bet tas joprojām var pārkāpt stingru vājo kārtību:struct FloatComparer { bool operator()(float a, float b) const { // Vienkāršs piemērs, kas var pārkāpt stingru kārtību return a < b - 1e-6; } }; // Nav ieteicams lietošanai reālos projektos // std::map<float, Value, FloatComparer> mana_karte; -
Bitu pārstāvuma konvertēšana uz veselo skaitli:
std::unordered_map/std::unordered_setgadījumā var pārveidotfloatbitu pārstāvumu uz veselo skaitli un izmantot to kā atslēgu, nodrošinot unikālu atslēgu katramfloatunikālajam bitu pārstāvumam, bet tas neizskaužfloatskaitļu salīdzināšanas problēmas, kuri ir matemātiski vienādi, bet atšķiras ar bitu pārstāvumu (piemēram, 0.0 un -0.0):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 { // Bitu pārstāvumu salīdzināšana 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> mana_karte; // Piezīme: tas salīdzina bitu pārstāvjus, ne matemātisko vienādību
Kopsavilkumā, ja atslēgas ir pludiņa skaitļi un to pārstāvība vai precizitāte rada problēmas, ieteicams pārskatīt datu struktūru vai izmantot veselos skaitļus vai fiksēta punkta metodes.