//! Para hesapları (kuruş, `i64`). Float yok. /// `total` kuruşu ağırlıklara orantılı böler; **toplam her zaman `total`'a eşittir**. /// /// "En büyük kalan" yöntemi: herkes tam payını alır, artan kuruşlar /// küsuratı en büyük olana (eşitlikte öndekine) birer birer verilir. /// Ağırlıkların hepsi 0 ise hepsine 0 döner (ve `total` dağıtılamaz → çağıran kontrol eder). pub fn split_proportional(total: i64, weights: &[u64]) -> Vec { let sum: u128 = weights.iter().map(|&w| u128::from(w)).sum(); if sum == 0 || total <= 0 { return vec![0; weights.len()]; } let total_u = total as u128; let mut parts: Vec = Vec::with_capacity(weights.len()); let mut remainders: Vec<(u128, usize)> = Vec::with_capacity(weights.len()); for (i, &w) in weights.iter().enumerate() { let exact = total_u * u128::from(w); parts.push((exact / sum) as i64); remainders.push((exact % sum, i)); } let mut left = total - parts.iter().sum::(); // Büyük kalan önce; eşitlikte küçük indeks önce remainders.sort_by(|a, b| b.0.cmp(&a.0).then(a.1.cmp(&b.1))); for (_, i) in remainders { if left == 0 { break; } parts[i] += 1; left -= 1; } parts } #[cfg(test)] mod tests { use super::*; #[test] fn sums_exactly_and_is_proportional() { // 1.000,00 ₺ Aralık haftalarına (6,7,7,7,4 gün) let p = split_proportional(100_000, &[6, 7, 7, 7, 4]); assert_eq!(p.iter().sum::(), 100_000); assert_eq!(p, vec![19_355, 22_581, 22_581, 22_580, 12_903]); } #[test] fn default_percentages() { // Tam paylar 617.283,5 / 370.370,1 / 123.456,7 / 123.456,7 → artan 2 kuruş // küsuratı en büyük olan ikisine (0,7'ler) gider assert_eq!( split_proportional(1_234_567, &[50, 30, 10, 10]), vec![617_283, 370_370, 123_457, 123_457] ); assert_eq!(split_proportional(1, &[50, 30, 10, 10]), vec![1, 0, 0, 0]); } #[test] fn edge_cases() { assert_eq!(split_proportional(0, &[1, 2]), vec![0, 0]); assert_eq!(split_proportional(-500, &[1, 2]), vec![0, 0]); assert_eq!(split_proportional(100, &[0, 0]), vec![0, 0]); assert_eq!(split_proportional(100, &[]), Vec::::new()); assert_eq!(split_proportional(7, &[0, 3, 0]), vec![0, 7, 0]); // Çok büyük tutarlarda taşma yok let big = 10_000_000_000_000; assert_eq!(split_proportional(big, &[31, 31]).iter().sum::(), big); } }