2015-04-16 13 views
13

Çok sayıda standart kitaplık konteynerine sahibim, bu yüzden onları bir araya getirdiğimde taşmaya neden olabilirler.Bir ortalama hesaplamak için std :: accumulate ve bir lambda'yı nasıl kullanabilirim?

std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 

Ben birikir :: std, bu kabın ortalamasını hesaplamak istiyorum ama ben birlikte tüm numaraları ekleyemezsiniz: en bu konteyner var sayalım. Ben sadece v[0]/v.size() + v[1]/v.size() + ... ile hesaplayacağım. Bu yüzden ayarlayın: -> çıkışını gösterir nerede

İşte
auto lambda = ...; 
std::cout << std::accumulate(v.begin(), v.end(), 0, lambda) << std::endl; 

, şimdiye kadar denedim budur:

lambda = [&](int a, int b){return (a + b)/v.size();}; -> 1 
lambda = [&](int a, int b){return a/v.size() + b/v.size();}; -> 1 
lambda = [&](int a, int b){return a/v.size() + b;}; -> 10 

nasıl doğru ortalama böyle çıktı olacağını 5 üretebilir?

+2

'5' doğru cevap değildir:

(veya en azından önemli ölçüde azaltmak) hatası yuvarlama birikimini önlemek için, bir gibi bir şey yapabilirsiniz. –

+0

@BenVoigt Tamsayı bölümü kullanıyorsanız. – EMBLEM

+2

Tamsayılı bölüm, ortalama hesaplanmasında kullanılmaz. Std :: accumulate' ile birleştiğinde, daha da kötüsü - kısmi miktarlarınızı mahvedecek. Son sonucun tamsayı bölme kurallarına göre yuvarlanmasını istiyorsanız, sorunuzda açıkça belirtmeniz gerekir (ve sonra bir ortalamayı bulamıyorsunuz). Aksi takdirde, tam sayı bölme kullanımınız her okuyucu için bir hataya benziyor. –

cevap

14
Sen sonucunu depolamak için tamsayı kullanmamalısınız

:

işleve accumulate geçirilen döndürme türü:
T accumulate(InputIt first, InputIt last, T init, BinaryOperation op); Üçüncü parametre türüne bağlıdır: (T init) böylece var çift olarak sonuç almak için 0.0.

#include <vector> 
#include <algorithm> 
#include <iostream> 
#include <numeric> 
using namespace std; 
std::vector<int> v = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 

int main() 
{ 
    auto lambda = [&](double a, double b){return a + b/v.size(); }; 
    std::cout << std::accumulate(v.begin(), v.end(), 0.0, lambda) << std::endl; 
} 
+0

@rpattabi Uyarıyı dönüşsüz olarak nasıl yeniden üretebileceğinizi biraz daha açıklayabilir misiniz? Bunu yapamam. – AdamF

0

Çalışan "ortalamanız" lambda için ilk parametredir, bu nedenle aşağıdaki doğrudur.

lambda = [&](int a, int b){return a + b/v.size();}; 
+3

tamsayı yuvarlamada sorun olmayacak mı? – dwcanillas

6

Bu oldukça olarak güzel yuvarlak olmayabilir, ama kabın üzerinde hiçbir size() yöntemi bulunduğundan bile çalışır:

auto lambda = [count = 0](double a, int b) mutable { return a + (b-a)/++count; }; 

Bu yeni bir C++ 14 özellikler, başlatıldı yakalar yararlanır Durumu lambda içinde saklamak için. (Aynı şeyi, fazladan bir yerel değişkenin yakalanmasıyla yapabilirsiniz, ancak kapsamı, lambda'nın yaşam süresi yerine yerel kapsamdır.) Daha eski C++ sürümleri için, değerini struct üye değişkenine koyabilirsiniz ve lambda gövdesini operator()() uygulaması olarak yerleştirin.

auto lambda = [count = 0, error = 0.0](double a, int b) mutable { 
    const double desired_change = (b-a-error)/++count; 
    const double newa = a + (desired_change + error); 
    const double actual_change = newa - a; 
    error += desired_change - actual_change; 
    return newa; 
}; 
+0

Büyük veri kümesi için bu yaklaşım formülünü kullanmak iyidir, çünkü orijinal formülde çiftin kalitesi yeterli olmayabilir. – AdamF

+0

@AdamF: Yuvarlama hatalarının birikmesini önlemek için bir hata kelimesi de takip edilebilir. –

+0

@AdamF: Daha iyi mi? –

İlgili konular