feststellen ob ein double eine natürliche Zahl ist
-
Hallo,
ich versuche gerade rauszufinden ob es möglich ist ffestzustellen das
double d = 1.0;eigentlich das selbe wie ein int 1 ist,
gibt es dafür eine Standard Bibliothek Funktion, oder muss man da mit <> epsilon oder ähnlichen selbst etwas schreiben?
vielleicht noch als Zusatz Erklärung:
sqlite> create table t1 (a NUM);
sqlite> insert into t1 values (1.0);
sqlite> select * from t1;
a
1es scheint irgendwo, entweder schon beim einfügen, oder beim anzeigen der Query, scheint sqlite3 sich ziemlich sicher zu sein das 1.0 eigentlich eine 1 ist.
da sqlite3 ein C program ist, jedoch viel zu gross für mich um da irgendetwas zu finden, frage ich mich ob das eine Standard Funktion ist oder nicht.
-
Ganze Zahlen lassen sich auch in einem double (zumindest wenn es sich um ieee754 handelt) exakt und verlustfrei darstellen, du kannst einen double also mit == auf 1.0 vergleichen und brauchst kein epsilon.
Das geht natürlich nur bis zu einer bestimmten Grenze, ab der dann nicht mehr alle Zahlen darstellbar sind. Die Grenze liegt so bei 2^53.
9007199254740992 ist noch darstellbar, aber wenn man dann 1 addiert, bleibt die Zahl gleich, d.h. 9007199254740993 gibt es in double dann nicht mehr. Ab dann musst du dir Sorgen machen, wenn du auf Gleichheit mit ganzen Zahlen testen willst.
-
SQL != C. SQLite wird diese Zahlen intern anders darstellen als als C float.
-
erst mal danke, aber ich denke ich muss meine Frage noch mal nach formulieren.
eventuell so:
Ist feststellbar ob ein double verlustfrei in einen Integer (int64_t) konvertiert werden kannist dieser, noch pseudo- Code zu naiv?,
int64_t convertOrThrow(double d) { int64_t i = static_cast<int64_t>(d); if ( d - i != 0.0) throw "verlust" return i ; }geht das besser?
-
Du kannst alternativ testen, ob
double d; ... if (trunc(d) == d) //ich bin ganzzahlig //oder: double dummy; if (modf(d, &dummy) == 0.0) // ich bin ganzzahligDiese Tests auf Ganzzahligkeit bleiben beide innerhalb von double, konvertieren also nicht in int. Bei sehr großen Zahlen müsstest du eben noch zusätzlich testen, ob die überhaupt in den int passen.
Dein Code geht natürlich auch - wobei ich die exception doch etwas hart finde.
-
zahl == (double)(int)zahl?
-
Ich hätte jetzt mal das.
wobei ich nicht weiss wie man die requirements auf template paramters legt, daher habe ich diese nur als Kommentar dazu geschrieben.template<typename InT, typename OutT> // requires std::is_integral<OutT>::value // requires is_floating_point<InT>::value inline OutT losslessConvert1 (InT in) { InT converted = std::trunc (in); if(in - converted != 0.0) throw std::out_of_range("nein!") ; using limit = std::numeric_limits<OutT> ; if (converted < limit::min() || converted > limit::max()) throw std::out_of_range("nein, aber fast!") ; return static_cast<OutT>(converted); } template<typename InT, typename OutT> // requires std::is_integral<OutT>::value // requires is_floating_point<InT>::value inline OutT losslessConvert2 (InT in) { InT converted{0.0}; InT fraction = std::modf (in, &converted) ; if(fraction != 0.0) throw std::out_of_range("nein!") ; using limit = std::numeric_limits<OutT> ; if (converted < limit::min() || converted > limit::max()) throw std::out_of_range("nein, aber fast!") ; return static_cast<OutT>(converted); }die Exception wenn es nicht geht ist gewollt, wird aber wohl einen besseren Text bekommen.
wenn das so stimmt müsste ich nur noch rausfinden welche Version die schnellere ist.
das "Test" Programm
int main() { try { std::cout << losslessConvert1<double, int>(1.0) << std::endl ; } catch (const std::exception& e) { std::cout << "Error: " << e.what () << std::endl ; } try { std::cout << losslessConvert1<double, int>(1.00001) << std::endl ; } catch (const std::exception& e) { std::cout << "Error: " << e.what () << std::endl ; } try { std::cout << losslessConvert1<double, int16_t>(300.00) << std::endl ; } catch (const std::exception& e) { std::cout << "Error: " << e.what () << std::endl ; } try { std::cout << losslessConvert1<double, int8_t>(300.00) << std::endl ; } catch (const std::exception& e) { std::cout << "Error: " << e.what () << std::endl ; } try { std::cout << losslessConvert2<double, int>(1.0) << std::endl ; } catch (const std::exception& e) { std::cout << "Error: " << e.what () << std::endl ; } try { std::cout << losslessConvert2<double, int>(1.00001) << std::endl ; } catch (const std::exception& e) { std::cout << "Error: " << e.what () << std::endl ; } try { std::cout << losslessConvert2<double, int16_t>(300.00) << std::endl ; } catch (const std::exception& e) { std::cout << "Error: " << e.what () << std::endl ; } try { std::cout << losslessConvert2<double, int8_t>(300.00) << std::endl ; } catch (const std::exception& e) { std::cout << "Error: " << e.what () << std::endl ; } }produziert
1 Error: nein! 300 Error: nein, aber fast! 1 Error: nein! 300 Error: nein, aber fast!