1. Mala korekcija sa velikim posledicama
Na početku želim da zahvalim studentu Jovanu Todorovu, koji mi je skrenuo pažnju na važnu tehničku specifičnost srpskog izbornog zakonodavstva: kada se proverava cenzus od 3% na lokalnim izborima, imenilac se ne mora svesti samo na zbir važećih glasova za izborne liste, već se polazi od šire kategorije glasova birača koji su glasali, što u izbornoj administraciji praktično znači da u osnovici mogu biti i važeći i nevažeći listići pronađeni u glasačkim kutijama. Ta napomena je važna zato što sam u prethodnoj blog objavi ispravno objasnio osnovnu logiku ponovljenog glasanja, stari rezultat sa biračkog mesta koje se ponavlja zamenjuje se novim rezultatom, a zatim se mandate ponovo računa po istoj izbornoj formuli. Međutim, ova pravna pojedinost menja jedan specifičan korak u tom postupku: proveru cenzusa.
Ovo nije puka pravnička fusnota. U tesnoj lokalnoj izbornoj utakmici lista koja je blizu cenzusa može ući u raspodelu mandata ako se imenilac računa samo iz važećih glasova za liste, ali može ostati ispod cenzusa ako se u istu osnovicu uključe i nevažeći listići. Kada se to dogodi, menja se cela raspodela mandata. Drugim rečima, sama D’Hondtova procedura može ostati potpuno ista, ali se menja skup lista koje uopšte smeju da uđu u raspodelu. To je drugačija vrsta korekcije od one iz prethodnog teksta: tamo je fokus bio na zameni starog rezultata sa ponovljenog biračkog mesta novim rezultatom, a ovde je fokus na zakonski relevantnoj osnovici za proveru da li lista uopšte učestvuje u raspodeli mandata.
To je praktično važno i zato što je ponovljeno glasanje bilo realna tema u lokalnim izborima u Srbiji 2026. godine. U Knjaževcu je, na primer, glasanje ponovljeno na biračkom mestu broj 8 nakon što je prethodno glasanje tamo poništeno; lokalni i nacionalni mediji izvestili su o terminu ponovljenog glasanja i toku samog dana glasanja. Upravo takvi slučajevi čine pitanje sasvim konkretnim: kada se novi rezultat sa ponovljenog biračkog mesta unese u zbir izborne jedinice, koji je pravno ispravan način da se proveri cenzus od 3%, a zatim izračuna raspodela mandata?
2. Šta se menja, a šta ne
Osnovna logika ostaje ista kao i ranije. Ponovljeno glasanje ne stvara novu teoriju izbora. Ono samo menja pravno važeće ukupne rezultate. Ako je prvobitni ukupni broj glasova neke liste u izbornoj jedinici bio \(V_p\) a stari rezultat sa ponovljenih biračkih mesta bude zamenjen novim, tada je korigovani ukupan broj glasova:
$$ V_p^*=V_p-\sum_{r \in R} v_{pr}^{(stari)} + \sum_{r \in R} v_{pr}^{(novi)}.$$
Taj deo se ne menja. Ne menja se ni sama D’Hondtova formula. Ako lista ispunjava uslove da učestvuje u raspodeli mandata, njeni mandati se i dalje određuju rangiranjem količnika dobijenih deljenjem korigovanog broja glasova sa 1, 2, 3, … zajedno sa količnicima ostalih podobnih lista. Ono što se menja jeste provera cenzusa. U srpskom okviru lokalnih izbora član 61 kaže da u raspodeli mandata učestvuju samo liste koje su osvojile najmanje 3% od glasova birača koji su glasali, dok član 62 mandate zatim raspodeljuje na osnovu glasova koje su liste osvojile primenom sistema najvećeg količnika. Zakon pritom posebno vodi evidenciju o važećim i nevažećim listićima, upravo zato je ova korekcija bitna.
Dakle, ispravljena pravna logika izgleda ovako. Neka je \(I^{(0)}\) prvobitni broj nevažećih listića u izbornoj jedinici, a neka su \(I^{(stari)}\) i \(I^{(novi)}\) brojevi nevažećih listića na ponovljenim biračkim mestima pre i posle ponovljenog glasanja. Tada je korigovani broj nevažećih listića:
$$ I^*=I^{(0)}-I^{(stari)}+I^{(novi)}.$$
Korigovana osnovica za cenzus je:
$$ T^*=\sum_{p=1}^{P} V_p^* +I^*.$$
I test cenzusa od 3% postaje:
$$ \frac{V_p^*}{T^*} ≥0.03.$$
U tome je cela korekcija. Imenilac za cenzus širi je od imenilaca koji ulaze u samu D’Hondtovu formulu. D’Hondt i dalje koristi samo korigovane važeće glasove za liste. Nevažeći listići su važni za utvrđivanje podobnosti za raspodelu, a ne za računanje količnika.
3. Zašto je to analitički važno
Ta razlika može izgledati sitno, ali ima stvarne analitičke posledice. U slučaju ponovljenog glasanja sada postoje dve odvojene korekcije. Prva je poznata korekcija glasova: stari rezultat sa ponovljenog biračkog mesta zamenjuje se novim. Druga je pravna korekcija imenilaca za cenzus: ako se na ponovljenom biračkom mestu promeni i broj nevažećih listića, onda se 3% mora proveravati na osnovu korigovanog zbira važećih plus nevažećih listića u kutijama. Ako se ta druga korekcija ignoriše i koristi samo zbir važećih glasova za liste, analitičar može pogrešno pustiti neku listu u raspodelu mandata.
Upravo je to vrsta pitanja koju izborna forenzika ne sme da previdi. Izborna forenzika nije samo otkrivanje sumnjivih obrazaca u agregatnim podacima. Ona je i rekonstrukcija pravno ispravnog numeričkog mehanizma kojim se glasovi pretvaraju u mandate. Ako zakon nalaže da se cenzus proverava na osnovu svih glasova birača koji su glasali, onda analitičar koji kao imenilac koristi samo važeće glasove po listama, čak i uz potpuno ispravno kodiran D’Hondt, ne reprodukuje tačno srpsko izborno pravilo. U tom smislu, mala pravna nijansa može proizvesti veliki metodološki promašaj.
4. Političke implikacije uključivanja nevažećih listića u osnovicu za cenzus
Iz političko-strateške perspektive, uključivanje nevažećih listića u imenilac za cenzus obično ide u korist većih i već uspostavljenih lista, dok njihovo isključivanje obično ide u korist manjih lista koje su blizu cenzusa. Razlog je mehanički: kada se nevažeći listići uključe, imenilac postaje veći, pa isti broj važećih glasova daje manji procenat. Time listama koje su na granici postaje teže da pređu 3%. U mnogim stvarnim lokalnim izborima takve granične liste češće su opozicione liste, lokalne građanske grupe ili manji novi akteri nego glavna vladajuća lista ili najjača opoziciona lista. Zato uključivanje nevažećih listića često ide u prilog dominantnijim velikim akterima, a na štetu manjih izazivača. Ipak, to nije pravilo o „vlasti i opoziciji“ u apstraktnom smislu. Prava linija podele nije politička etiketa, već položaj u odnosu na cenzus: najviše je pogođena ona lista koja se kreće oko 3%, bez obzira da li pripada vlasti ili opoziciji.
5. Kompletan R kod sa numeričkim primerom
R kod ispod implementira ispravljenu srpsku logiku. On radi četiri stvari: menja stare važeće glasove na ponovljenim biračkim mestima novim, koriguje broj nevažećih listića, proverava cenzus koristeći važeće plus nevažeće listiće, i zatim raspodeljuje mandate među podobnim listama po D’Hondtu uz srpsko pravilo razrešenja izjednačenja većim ukupnim brojem glasova.
#===============================================
# Repeated voting – Mandates allocation
#===============================================
serbia_repeat_dhondt <- function(original_votes,
repeat_old,
repeat_new,
seats,
original_invalid = 0,
repeat_old_invalid = 0,
repeat_new_invalid = 0,
threshold = 0.03) {
# original_votes = original valid votes by list / originalni važeći glasovi po listama
# repeat_old = old valid votes at repeated stations / stari važeći glasovi na ponovljenim mestima
# repeat_new = new valid votes at repeated stations / novi važeći glasovi na ponovljenim mestima
# original_invalid = original invalid ballots / originalni nevažeći listići
# repeat_old_invalid = old invalid ballots at repeated stations / stari nevažeći listići
# repeat_new_invalid = new invalid ballots at repeated stations / novi nevažeći listići
# seats = total seats / ukupan broj mandata
# Align party names / Uskladi nazive lista
parties <- names(original_votes)
repeat_old <- repeat_old[parties]
repeat_new <- repeat_new[parties]
# Correct valid totals / Koriguj važeće glasove
corrected_votes <- original_votes - repeat_old + repeat_new
# Correct invalid totals / Koriguj nevažeće listiće
corrected_invalid <- original_invalid - repeat_old_invalid + repeat_new_invalid
# Total ballots cast = valid + invalid / Ukupan broj ubačenih listića = važeći + nevažeći
total_cast <- sum(corrected_votes) + corrected_invalid
# Wrong threshold base for comparison / Pogrešna osnova za poređenje
total_valid_only <- sum(corrected_votes)
# Eligibility under wrong and correct rules / Učešće po pogrešnom i ispravnom pravilu
eligible_valid_only <- corrected_votes / total_valid_only >= threshold
eligible_cast <- corrected_votes / total_cast >= threshold
# D'Hondt allocator / D’Hondt raspodela
allocate_dhondt <- function(votes, seats) {
qtab <- do.call(rbind, lapply(names(votes), function(p) {
divs <- seq_len(seats)
data.frame(
party = rep(p, seats),
total_votes = rep(unname(votes[p]), seats),
divisor = divs,
quotient = unname(votes[p]) / divs,
stringsAsFactors = FALSE
)
}))
# Serbian tie-break: higher total votes wins / Srpsko pravilo: prednost većem ukupnom broju glasova
qtab <- qtab[order(-qtab$quotient, -qtab$total_votes, qtab$divisor, qtab$party), ]
winners <- qtab[seq_len(seats), ]
seat_counts <- table(factor(winners$party, levels = names(votes)))
list(seat_counts = seat_counts, ranking = winners)
}
# Seats under wrong threshold base / Mandati po pogrešnoj osnovi cenzusa
seats_valid_only <- allocate_dhondt(corrected_votes[eligible_valid_only], seats)
# Seats under correct Serbian rule / Mandati po ispravnom srpskom pravilu
seats_cast <- allocate_dhondt(corrected_votes[eligible_cast], seats)
list(
corrected_votes = corrected_votes,
corrected_invalid = corrected_invalid,
total_valid_only = total_valid_only,
total_cast = total_cast,
eligible_valid_only = eligible_valid_only,
eligible_cast = eligible_cast,
seats_valid_only = seats_valid_only$seat_counts,
seats_cast = seats_cast$seat_counts,
ranking_valid_only = seats_valid_only$ranking,
ranking_cast = seats_cast$ranking
)
}
# Example / Primer
original_votes <- c(A = 12000, B = 8000, C = 5000, D = 690)
repeat_old <- c(A = 300, B = 200, C = 100, D = 20)
repeat_new <- c(A = 250, B = 180, C = 90, D = 130)
original_invalid <- 1150
repeat_old_invalid <- 30
repeat_new_invalid <- 80
S <- 33
res <- serbia_repeat_dhondt(
original_votes = original_votes,
repeat_old = repeat_old,
repeat_new = repeat_new,
seats = S,
original_invalid = original_invalid,
repeat_old_invalid = repeat_old_invalid,
repeat_new_invalid = repeat_new_invalid,
threshold = 0.03
)
print("Corrected valid votes / Korigovani važeći glasovi:")
print(res$corrected_votes)
print("Corrected invalid ballots / Korigovani nevažeći listići:")
print(res$corrected_invalid)
print("Eligibility if threshold uses only valid votes / Cenzus ako koristi samo važeće glasove:")
print(res$eligible_valid_only)
print("Eligibility if threshold uses valid + invalid ballots / Cenzus ako koristi važeće + nevažeće:")
print(res$eligible_cast)
print("Seats under wrong threshold base / Mandati po pogrešnoj osnovi:")
print(res$seats_valid_only)
print("Seats under correct Serbian rule / Mandati po ispravnom srpskom pravilu:")
print(res$seats_cast)
Na ovom primeru dobijamo sledeće korigovane ukupne rezultate: A = 11.950, B = 7.980, C = 4.990, D = 800, nevažeći listići = 1.200
Dakle, korigovani zbir važećih glasova je 25.720, dok je korigovani zbir svih ubačenih listića 26.920. To znači da lista D ima 3,11% ako se, pogrešno, koristi samo zbir važećih glasova, ali samo 2,97% ako se, ispravno, koristi zbir važećih i nevažećih listića. Pod pogrešnim imeniteljem D ulazi u raspodelu mandata; pod ispravnim srpskim imeniteljem D ne ulazi. Rezultujuće raspodele mandata su:
- Pogrešna osnova (samo važeći): A = 16, B = 10, C = 6, D = 1
- Ispravno srpsko pravilo (važeći + nevažeći): A = 16, B = 11, C = 6
Dakle, pravna korekcija menja raspodelu za jedan mandat: D gubi mandat koji bi pogrešno dobio, a B zadržava jedanaesti mandat.
6. Ručna verifikacija
Ručna provera je jednostavna i presudna. Pođimo od korigovanih ukupnih rezultata: A = 11.950, B = 7.980, C = 4.990, D = 800, nevažeći listići = 1.200
Prvo proverimo cenzus. Ako se, pogrešno, koristi samo zbir važećih glasova za liste, imenilac je:
$$ 11.950+7.980+4.990+800=25.720$$
Tada lista D ima:
$$ 800/25.720=0,03110=3,11%$$
Dakle, po pogrešnom pravilu, D prelazi cenzus.
Ako se koristi ispravno srpsko pravilo, imenilac je:
$$ 25.720+1.200=26.920.$$
Tada lista D ima:
$$ 800/26.920=0,02972=2,97%. $$
Dakle, po ispravnom pravilu, D ne prelazi cenzus.
Sada proverimo odlučujuće D’Hondtove količnike pod pogrešnom osnovom, gde D ulazi u raspodelu:
- C / 6 = 4.990 / 6 = 831,67
- D / 1 = 800 / 1 = 800,00
- B / 10 = 7.980 / 10 = 798,00
- A / 15 = 11.950 / 15 = 796,67
- A / 16 = 11.950 / 16 = 746,88
- B / 11 = 7.980 / 11 = 725,45
Pošto je prvi količnik liste D jednak 800, on ulazi među 33 najveća količnika. To D daje jedan mandat i istiskuje B-ov jedanaesti količnik (725,45) ispod granice. Zato pod pogrešnom osnovom dobijamo: A = 16, B = 10, C = 6, D = 1.
Pod ispravnim srpskim pravilom, D se isključuje pre nego što se D’Hondt uopšte primeni. Tada 33. mandat ide B-ovom jedanaestom količniku umesto prvom količniku liste D, pa raspodela postaje: A = 16, B = 11, C = 6
To je cela logika. Sama D’Hondtova formula se nije promenila. Ključna promena dogodila se jedan korak ranije: u zakonski relevantnom imenitelju za cenzus.
7. Komentar i zaključak
Ova korekcija je uska po obimu, ali važna po posledicama. Ona ne menja standardnu teoriju preračunavanja mandata nakon ponovljenog glasanja. Ona je samo precizira. Šira logika ostaje ista: stari rezultati sa ponovljenih biračkih mesta zamenjuju se novim, računaju se korigovani ukupni glasovi, a zatim se ponovo primenjuje zakonsko pravilo raspodele mandata. Ono što se u srpskom okviru lokalnih izbora menja jeste osnovica za proveru cenzusa. Ako su nevažeći listići pravno deo kategorije „glasova birača koji su glasali“, onda oni moraju biti uključeni u taj imenilac. Njihovo ignorisanje može proizvesti formalno uredan, ali pravno netačan rezultat.
Zato i ova tema pripada izbornoj forenzici. Izborna forenzika je najjača kada kombinuje statističko rasuđivanje sa tačnim čitanjem institucija i pravila. Matematički elegantna formula nije dovoljna ako je povezana sa pogrešnim pravnim imeniteljem. Obrnuto, kada se pravno pravilo pravilno razume, i numerička implementacija postaje sasvim jasna. Ovaj tekst zato treba čitati kao korekciju i dopunu prethodne objave: opšta logika ponovljenog glasanja ostaje ista, ali u srpskim lokalnim izborima korak sa cenzusom mora se izvesti sa posebnom pažnjom.
8. Python kod
Ispod je ekvivalentna Python implementacija iste logike.
from typing import Dict, Any
def serbia_repeat_dhondt(original_votes: Dict[str, float],
repeat_old: Dict[str, float],
repeat_new: Dict[str, float],
seats: int,
original_invalid: float = 0,
repeat_old_invalid: float = 0,
repeat_new_invalid: float = 0,
threshold: float = 0.03) -> Dict[str, Any]:
# original_votes = original valid votes by list / originalni važeći glasovi po listama
# repeat_old = old valid votes at repeated stations / stari važeći glasovi na ponovljenim mestima
# repeat_new = new valid votes at repeated stations / novi važeći glasovi na ponovljenim mestima
# original_invalid = original invalid ballots / originalni nevažeći listići
# repeat_old_invalid = old invalid ballots at repeated stations / stari nevažeći listići
# repeat_new_invalid = new invalid ballots at repeated stations / novi nevažeći listići
# seats = total seats / ukupan broj mandata
# Align party names / Uskladi nazive lista
parties = list(original_votes.keys())
old_aligned = {p: repeat_old.get(p, 0) for p in parties}
new_aligned = {p: repeat_new.get(p, 0) for p in parties}
# Correct valid totals / Koriguj važeće glasove
corrected_votes = {
p: original_votes[p] - old_aligned[p] + new_aligned[p]
for p in parties
}
# Correct invalid totals / Koriguj nevažeće listiće
corrected_invalid = original_invalid - repeat_old_invalid + repeat_new_invalid
# Total ballots cast / Ukupan broj ubačenih listića
total_valid_only = sum(corrected_votes.values())
total_cast = total_valid_only + corrected_invalid
# Threshold tests / Provera cenzusa
eligible_valid_only = {
p: (corrected_votes[p] / total_valid_only) >= threshold
for p in parties
}
eligible_cast = {
p: (corrected_votes[p] / total_cast) >= threshold
for p in parties
}
# D'Hondt allocator / D’Hondt raspodela
def allocate_dhondt(votes: Dict[str, float], seats: int):
qtab = []
for p, v in votes.items():
for d in range(1, seats + 1):
qtab.append({
"party": p,
"total_votes": v,
"divisor": d,
"quotient": v / d
})
# Serbian tie-break: higher total votes wins / Srpsko pravilo: prednost većem ukupnom broju glasova
qtab_sorted = sorted(
qtab,
key=lambda row: (-row["quotient"], -row["total_votes"], row["divisor"], row["party"])
)
winners = qtab_sorted[:seats]
seat_counts = {p: 0 for p in votes.keys()}
for row in winners:
seat_counts[row["party"]] += 1
return {"seat_counts": seat_counts, "ranking": winners}
# Seats under wrong threshold base / Mandati po pogrešnoj osnovi cenzusa
votes_valid_only = {p: corrected_votes[p] for p in parties if eligible_valid_only[p]}
seats_valid_only = allocate_dhondt(votes_valid_only, seats)
# Seats under correct Serbian rule / Mandati po ispravnom srpskom pravilu
votes_cast = {p: corrected_votes[p] for p in parties if eligible_cast[p]}
seats_cast = allocate_dhondt(votes_cast, seats)
return {
"corrected_votes": corrected_votes,
"corrected_invalid": corrected_invalid,
"total_valid_only": total_valid_only,
"total_cast": total_cast,
"eligible_valid_only": eligible_valid_only,
"eligible_cast": eligible_cast,
"seats_valid_only": seats_valid_only["seat_counts"],
"seats_cast": seats_cast["seat_counts"],
"ranking_valid_only": seats_valid_only["ranking"],
"ranking_cast": seats_cast["ranking"]
}
# Example / Primer
original_votes = {"A": 12000, "B": 8000, "C": 5000, "D": 690}
repeat_old = {"A": 300, "B": 200, "C": 100, "D": 20}
repeat_new = {"A": 250, "B": 180, "C": 90, "D": 130}
original_invalid = 1150
repeat_old_invalid = 30
repeat_new_invalid = 80
S = 33
res = serbia_repeat_dhondt(
original_votes=original_votes,
repeat_old=repeat_old,
repeat_new=repeat_new,
seats=S,
original_invalid=original_invalid,
repeat_old_invalid=repeat_old_invalid,
repeat_new_invalid=repeat_new_invalid,
threshold=0.03
)
print("Corrected valid votes / Korigovani važeći glasovi:")
print(res["corrected_votes"])
print("\nCorrected invalid ballots / Korigovani nevažeći listići:")
print(res["corrected_invalid"])
print("\nEligibility if threshold uses only valid votes / Cenzus ako koristi samo važeće glasove:")
print(res["eligible_valid_only"])
print("\nEligibility if threshold uses valid + invalid ballots / Cenzus ako koristi važeće + nevažeće:")
print(res["eligible_cast"])
print("\nSeats under wrong threshold base / Mandati po pogrešnoj osnovi:")
print(res["seats_valid_only"])
print("\nSeats under correct Serbian rule / Mandati po ispravnom srpskom pravilu:")
print(res["seats_cast"])
Literatura
Kohler, U., & Zeh, J. (2012). Apportionment methods. The Stata Journal, 12(3), 375–392. https://doi.org/10.1177/1536867X1201200303
Medzihorsky, J. (2019). Rethinking the D’Hondt method. Political Research Exchange, 1(1), Article 1625712. https://doi.org/10.1080/2474736X.2019.1625712
Gallagher, M., & Mitchell, P. (Eds.). (2005). The politics of electoral systems. Oxford University Press. https://doi.org/10.1093/0199257566.001.0001
Pravni i medijski izvori
Republic of Serbia. Law on Local Elections (English version; Articles 58–62). Venice Commission document repository.
Paragraf Lex. Zakon o lokalnim izborima.
Za Media. Ponovljeno glasanje na biračkom mestu br. 8 u Knjaževcu 29. aprila. 25 April 2026.
Euronews Srbija. Ponovljeno glasanje u Knjaževcu: Izlaznost 39,41 odsto. 29 April 2026.