2016-07-13 13 views
1

Was ist der richtige Weg, um ein int mit einer Dezimalzahl zu einem Doppel zu konvertieren?Was ist der richtige Weg, um ein int mit einer Dezimalzahl zu einem Doppel zu konvertieren

Ich habe eine int zum Beispiel 12123456 als 12123456. Dies kommt von einem Netzwerkgerät, das ich nicht ändern kann.

Ich möchte es mit minimalem Fehler zu verdoppeln.

Die naive Lösung wäre: double res = boost::numeric_cast<double>(myint)/1000000.0;

Ich denke, dass zu einem Doppel als eine andere Methode mehr verlustbehaftete myint (eine große Zahl) Umwandlung ist, weil der resultierende Wert nahe 1 ist, wo dobule mehr Präzision hat.

Ich bin auf der Suche nach der am wenigsten verlustreiche Methode, diese Konvertierung zu machen.


EDIT:

Ich habe nicht log0 Antwort glauben war richtig. TL; DR Er ist.

Der Test I verwendet:

#include <iostream> 
#include <limits> 

#include <boost/random.hpp> 


inline double DecimalToDouble(int64_t value, int64_t divisor) 
{ 
    int64_t first = value/divisor; 
    int64_t second = value % divisor; 

    return (double)first + (double)second/(double)divisor; 
} 

int main() 
{ 
    boost::mt19937 rng; 
    boost::uniform_int<int> distr(std::numeric_limits<int>::min(), 
     std::numeric_limits<int>::max()); 
    boost::variate_generator< boost::mt19937, boost::uniform_int<> > dice(rng, distr); 

    int erra = 0; 
    int errb = 0; 
    std::cout.precision(std::numeric_limits<double>::max_digits10); 

    int iterations = 1000000; 
    for(int i = 0; i < iterations; ++i) 
    { 
     int x = dice(); 

     double divi = 10000000.0; 

     double a = x/divi; 
     double b = DecimalToDouble(x, 10000000); 

     if((int)(a * divi) != x) 
     { 

      //std::cout << "ERROR AT A:" << x << '\t' << a << '\t' << b << std::endl; 
      erra++; 
     } 

     if((int)(b * divi) != x) 
     { 
      //std::cout << "ERROR AT B:" << x << '\t' << a << '\t' << b << std::endl; 
      errb++; 
     } 
    } 

    std::cout.precision(10); 
    std::cout << "A:" << (erra/(double)iterations) * 100.0 << "% B:" 
      << (errb/(double)iterations) * 100.0 << "%" << std::endl; 


    char stop; 
    std::cin >> stop; 
} 

Ergebnis auf Win7x64 VS2010: A: 6,4997% B: 6,5188%

+0

@ FrédéricHamidi Sorry für unklare Frage, siehe bearbeiten. – akaltar

+1

Was meinst du mit "ohne Verluste"? – Slava

+0

Um @ Slavas Kommentar zu erläutern, kommen Doppel mit Verlust - das ist von Entwurf, wenn Sie das nicht wollen, verwenden Sie alternative Festkommatypen. –

Antwort

3

Doppel res = myint/1000000,0;

Das ist die Aufgabe des Compilers, res auf den nächsten darstellbaren Wert des Ergebnisses zu setzen.

+0

Ich habe Ihre Antwort bestätigt mit einem Test. Es ist die beste Methode, denke ich. – akaltar

1

Beachten Sie, dass es immer einen Unterschied gibt zwischen dem, was ein numerischer Wert für Sie bedeutet und der Darstellung, die in der Sprache verfügbar ist, die Sie in Ihrem Code verwenden. Meistens ist es nicht so offensichtlich wie in diesem Fall. Was ich sagen möchte ist: Wenn Sie einen int haben, dessen Wert 12123456 ist, dann ist dies bereits eine Darstellung des tatsächlichen Wertes 12.123456. Der einzige Grund, warum ich mir vorstellen könnte, es in eine double zu konvertieren, ist Gleitkommaarithmetik (insbesondere Division) zu verwenden, sonst würde ich einfach bei der int bleiben.

TL; DR: Wenn möglich würde ich versuchen, die Konvertierung zu vermeiden. Wenn Sie es wirklich wollen, ist die Antwort von imho log0 perfekt.

Verwandte Themen