Kas on hea mõte kasutada float tüüpi konteineri võtmena?
sobes.tech AI
Vastus AI-lt
Ei soovitata kasutada float-i võtmena assotsiatiivsetes konteinerites (näiteks std::map, std::unordered_map) või otse sorteerimiseks järgmistel põhjustel:
-
Võrdluse probleemid: Kaks
floatarvu (võidouble) on harva võrdsed, kuna ujukoma arvutamise vead.a == bvõrdlus võib anda vale tulemuse, isegi kui matemaatiliselt on nad võrdsed. See rikub konteinerite invarianse, mis nõuavad ranget nõrka järjekorda (std::mapjastd::set) või korrektset hash- ja võrdluse arvutust (std::unordered_mapjastd::unordered_set). -
Vale järjestus:
floatvõrdlusoperaatorid ei pruugi alati tagada ranget nõrka järjekorda kõigi võimalike väärtuste puhul (näiteks NaN). -
Ebakindel hash:
floathash-funktsioonide rakendamine võib olla ebastabiilne, kuna sama esitus võib põhjustada ettearvamatut käitumist või madalat jõudlust hash-tabelites:
Soovitatavad lähenemised:
-
Kasutada täisarvulist esitamist: Kui täpsus ei ole oluline või arvud on piiratud vahemikus ja resolutsioonis, saab skaleerida ja teisendada
floattäisarvuks (näiteksintvõilong long) ning kasutada seda võtmena:float f = 1.23f; int võti = static_cast<int>(f * 100); // Skaleerimise näide std::map<int, Value> minu_map; minu_map[võti] = mingi_väärtus; -
Kasutada fikseeritud punkti: Kui on vaja täpset murdarvu esitamist, saab kasutada fikseeritud punkti arvutuskirjandust.
-
Võrdluse tegemine lubatud vahega (epsilon): Kuigi see ei võimalda
float-i otseselt võtmena kasutada, saab otsingutel võrrelda väärtusi väikese lubatud vahega (epsilon):bool onVõrdne(float a, float b, float epsilon = 1e-6) { return std::abs(a - b) < epsilon; } // Ei sobi otseseks kasutamiseks map võtmena -
Kasutada kasutaja määratletud võrdlusfunktsiooni (
std::map/std::set): Võib määratleda kasutaja määratletud võrdlusfunktsiooni, mis arvestab lubatud vahega, kuid see võib ikkagi rikkuda ranget nõrka järjekorda:struct FloatComparer { bool operator()(float a, float b) const { // Lihtne näide, mis võib rikkuda ranget nõrka järjekorda return a < b - 1e-6; } }; // Ei soovitata kasutada reaalsetes rakendustes // std::map<float, Value, FloatComparer> minu_map; -
Bitiväljundi teisendamine täisarvuks:
std::unordered_map/std::unordered_setjaoks saab teisendadafloatbitiväljundi täisarvuks ja kasutada seda võtmena, mis tagab igafloatunikaalse bitiväljundi, kuid ei lahendafloatarvude võrdlusprobleemi, mis on matemaatiliselt võrdsed, kuid erineva bitiväljundiga (näiteks 0.0 ja -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 { // Bitiväljundi võrdlus 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> minu_map; // Märkus: see võrdleb bitiväljundeid, mitte matemaatilist võrdsust
Kokkuvõttes, kui võtmed on ujukoma arvud ja nende esitus või täpsus tekitab probleeme, on soovitatav üle vaadata andmestruktuur või kasutada täisarvulist või fikseeritud punkti lähenemist.