2015-09-12 22 views
5

How to round floats to integers while preserving their sum?, değişmeyen öğelerin toplamı ve dönüş hatası hatası en aza indirilecek şekilde bir vektörü tamsayı değerlerine yuvarlayan pseudocode ile yazılmış answer kodunun altındadır. I R. (yani mümkünse vektörlü) verimli bir şekilde uygulamak için istiyorumSayısal değerlerin tamsayılarını tamsayı olarak koruyarak toplamları

Örneğin, bu sayıları yuvarlama farklı toplam verir: referans answer den

set.seed(1) 
(v <- 10 * runif(4)) 
# [1] 2.655087 3.721239 5.728534 9.082078 
(v <- c(v, 25 - sum(v))) 
# [1] 2.655087 3.721239 5.728534 9.082078 3.813063 
sum(v) 
# [1] 25 
sum(round(v)) 
# [1] 26 

kopyalama yalancı kod

// Temp array with same length as fn. 
tempArr = Array(fn.length) 

// Calculate the expected sum. 
arraySum = sum(fn) 

lowerSum = 0 
-- Populate temp array. 
for i = 1 to fn.lengthf 
    tempArr[i] = { result: floor(fn[i]),    // Lower bound 
        difference: fn[i] - floor(fn[i]), // Roundoff error 
        index: i }       // Original index 

    // Calculate the lower sum 
    lowerSum = lowerSum + tempArr[i] + lowerBound 
end for 

// Sort the temp array on the roundoff error 
sort(tempArr, "difference") 

// Now arraySum - lowerSum gives us the difference between sums of these 
// arrays. tempArr is ordered in such a way that the numbers closest to the 
// next one are at the top. 
difference = arraySum - lowerSum 

// Add 1 to those most likely to round up to the next number so that 
// the difference is nullified. 
for i = (tempArr.length - difference + 1) to tempArr.length 
    tempArr.result = tempArr.result + 1 
end for 

// Optionally sort the array based on the original index. 
array(sort, "index") 
daha basit formda

cevap

11

diyebilirim bu algoritmadır:

  1. Yuvarlanan her şeyle başlayın
  2. İstenen toplama ulaşılana kadar en yüksek kesirli parçalara sahip sayıları toplayın. (order kullanarak) fraksiyonel parça endekslerini kapmak için tail
  3. Kullanımı ile floor
  4. Sipariş numaraları ile aşağı

    1. Round:

    Bu tarafından Ar bir vektörleşen şekilde uygulanabilir k en büyük fraksiyonel parçalara sahip elemanların k değeri, hedef değere ulaşmak için toplamı arttırmamız gereken miktardır.

  5. Çıkış değerini artırın kodunda

1 bu endekslerinin her: bu yararlı fonksiyon için

smart.round <- function(x) { 
    y <- floor(x) 
    indices <- tail(order(x-y), round(sum(x)) - sum(y)) 
    y[indices] <- y[indices] + 1 
    y 
} 
v 
# [1] 2.655087 3.721239 5.728534 9.082078 3.813063 
sum(v) 
# [1] 25 
smart.round(v) 
# [1] 2 4 6 9 4 
sum(smart.round(v)) 
# [1] 25 
5

teşekkür! ondalık basamak belirtilen sayıya yuvarlayarak, fonksiyon değiştirilebilir eğer Sadece cevaba eklemek için: toplam ve fark tabanlı yaklaşım Running

smart.round <- function(x, digits = 0) { 
    up <- 10^digits 
    x <- x * up 
    y <- floor(x) 
    indices <- tail(order(x-y), round(sum(x)) - sum(y)) 
    y[indices] <- y[indices] + 1 
    y/up 
} 
2

çok daha hızlı smartRound karşılaştırılır @josliber tarafından:

diffRound <- function(x) { 
    diff(c(0, round(cumsum(x)))) 
} 
sonuçlar 1m kayıtlarına kıyasla ne İşte

(dETAYLAR burada: Running Rounding):

res <- microbenchmark(
    "diff(dww)" = x$diff.rounded <- diffRound(x$numbers) , 
    "smart(josliber)"= x$smart.rounded <- smartRound(x$numbers), 
    times = 100 
) 

benchmark of column rounding methods

Unit: milliseconds 
expr   min  lq  mean  median  uq  max  neval 
diff(dww)  38.79636 59.70858 100.6581 95.4304 128.226 240.3088 100 
smart(josliber) 466.06067 719.22723 966.6007 1106.2781 1177.523 1439.9360 100 
+2

Bu çözüm benimkilerden daha hızlıyken ve istenen toplamı korurken, maalesef bu soruda talep edildiği gibi dönüş hatalarını en aza indirmez. Örneğin, "v <- c (2.655087, 3.721239, 5.728534, 9.082078, 3.813063)" ile, "smart.round", "sum (abs (smart.round (v) - v))' dönüş hatası hatası döndürür. 'DiffRound',' toplamı (abs (diffRound (v) -v)) 'nin dönüş hatası, 1.474329 iken, 1.606633 değerini döndürür. – josliber

+0

doğrudur, genel dönüş hatası, diff yöntemi ile en aza indirilmez. Yine de sorunun güçlü bir gerekliliği olup olmadığından emin değilim. – Bulat

+0

Orijinal soru şu fıkraları vardı: "Bu dört koşulun yerine getirildiği göz önüne alındığında, yuvarlama varyansını en aza indiren bir algoritma (toplam (([i] - fn [i])^2)) tercih edilir, ancak bu büyük bir anlaşma değildir. ." – Bulat

İlgili konular