2017-05-24 4 views
3

I einen unsigned long int für einen size_t (zurückgegeben von einer Dimension eines Arrays mit size()), wie diese haben zuzuweisen teilen:Teilen und das Ergebnis an eine Doppel

vector<string> mapped_samples; 
vector<double> mean; 
vector<unsigned long> feature_sum; 
/* elaboration here */ 
mean.at(index) = feature_sum.at(index) /mapped_samples.size(); 

aber auf diese Weise eine integer-Division statt (ich verliere den Dezimalteil das ist nicht gut.)

Daher kann ich tun:

mean.at(index) = feature_sum.at(index)/double(mapped_samples.size()); 

aber auf diese Weise wird feature_sum.at(index) automatisch umgewandelt (Temporäre Kopie) zu double und ich könnte die Präzision verlieren. Wie kann ich die Frage angehen? Ich muss eine Bibliothek benutzen?

Es könnte Präzisionsverlust sein, wenn Sie das unsigned long in double konvertieren (weil der vorzeichenlose lange Wert größer als das maximale double sein könnte). Der unsigned long Wert ist die Summe der Features (positive Werte). Die Stichproben des Merkmals können 1000000 oder mehr betragen und die Summe der Werte der Merkmale kann enourmus sein. Der maximale Wert eines Merkmals ist 2000 so: 2000 * 1000000 oder mehr

(Ich verwende C++ 11)

+2

Sie könnten die Bibliothek [Boost.Multiprecision] (http://www.boost.org/doc/libs/1_64_0/libs/multiprecision/doc/html/index.html) verwenden; Es ist in der Lage, Arbiträr- und Gleitkommaarithmetik mit beliebiger Genauigkeit auszuführen. –

+1

@JasonR In C++ gibt es keine einfachere Lösung? Ich bin jetzt auf andere konzentriert und II würde nicht eine Bibliothek für eine einzelne Operation studieren Es sei denn, es ist der einzige Weg – Umbert

+1

Sie haben nicht angegeben, welche Präzision Sie benötigen – keith

Antwort

4

Sie könnten versuchen, std::div

Entlang der Linien zu verwenden

auto dv = std::div(feature_sum.at(index), mapped_samples.size()); 

double mean = dv.quot + dv.rem/double(mapped_samples.size()); 
3

könnten Sie verwenden:

// Grab the integral part of the division 
auto v1 = feature_sum.at(index)/mapped_samples.size(); 

// Grab the remainder of the division 
auto v2 = feature_sum.at(index)%mapped_samples.size(); 

// Dividing 1.0*v2 is unlikely to lose precision 
mean.at(index) = v1 + static_cast<double>(v2)/mapped_samples.size(); 
+0

wie std :: div Version –

+0

@SeverinPappadeux, stimmt. –

+1

Ist das genauer als das Original? –

2

kann man nicht besser machen, als die einfachen

std::uint64_t x=some_value, y=some_other_value; 
auto mean = double(x)/double(y); 

, da die relative Genauigkeit der verkürzten Form des korrekten Ergebnisses mit float128

auto improved = double(float128(x)/float128(x)) 

ist in der Regel das gleiche (wenn Sie das Ergebnis als double speichern mögen) (für typische Eingabe - es kann seltene Eingaben geben, wo Verbesserung möglich ist). Beide haben einen relativen Fehler, der durch die Länge der Mantisse für double (53 Bits) bestimmt ist. Also die einfache Antwort ist: Verwenden Sie entweder einen genaueren Typ als double für Ihren Mittelwert oder vergessen Sie dieses Problem.


Um die relative Genauigkeit zu sehen, lassen Sie uns, dass

x=a*(1+e); // a=double(x) 
y=b*(1+f); // b=double(y) 

wo e nehmen f der Bestellung sind 2^-53.

Dann ist die 'richtige' Quotient in erster Ordnung ist in e und f

(x/y) = (a/b) * (1 + e - f) 

Umwandeln dieser zu double verursacht eine weitere relative Fehler in der Größenordnung von 2^-53, d.h.in der gleichen Größenordnung wie der dem Fehler von (a/b), das Ergebnis der naiven

mean = double(x)/double(y). 

Natürlich e und f kann abbrechen verschwören, wenn ein höhere Genauigkeit kann durch die in anderen Antworten vorgeschlagenen Methoden gewonnen werden, aber in der Regel die Genauigkeit kann nicht verbessert werden.

Verwandte Themen