Publi

Reparto de escaños a partir de los resultados electorales según el sistema d’Hondt

b3546d64_r

El sistema d’Hondt. Es el método por el cual se realiza el reparto de escaños tras un proceso electoral en países como España, Chile, Perú, Uruguay, Argentina, Colombia, Portugal, Finlandia y muchos más.

Y como curiosidad, y dado que vivimos en épocas de elecciones en varios países, vamos a implementar unas hipotéticas elecciones en España. Para ello, vamos a introducir varios nombres de partidos políticos en un saco, vamos a definir un número de votantes y vamos a generar los resultados de unas votaciones, también podemos pedirlas al usuario, pero me ha parecido también curioso generar los votos para hacer pruebas más rápidamente).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/* fichero dhondt.c */
/* Calculo de escaños por partido con la ley d'Hondt.
   En lugar de escaño he puesto silla, para que los compiladores
   no se vuelvan locos con la ñ.
*/

#include <stdio.h>
#include <stdlib.h>

struct TPartido
{
  char nombre[100];     /* Nombre del partido */
  long votos;
  int sillas;
};

typedef struct TPartido TPartido;

/* Los votos nulos no cuentan, pero los blancos sí */
long cuenta_votos (const TPartido partidos[], int npartidos, long votos_blancos)
{
  long votos = votos_blancos;
  int i;

  for (i=0; i<npartidos; ++i)
    votos+=partidos[i].votos;

  return votos;
}

void limpia_sillas(TPartido partidos[], int npartidos)
{
  int i;

  for (i=0; i<npartidos; ++i)
    partidos[i].sillas = 0;
}

int calcula_dhont(TPartido partidos[], int npartidos, long votos_blancos, long votos_nulos, int nsillas, double liston)
{
  long total_votos = cuenta_votos (partidos, npartidos, votos_blancos);
  long min_votos = (long) (total_votos * liston); /* Porcentaje de votos necesario para que el partido opte a escaño */
  int sillas;
  long max, imax;
  int i;
  /* Se supone que los pusimos a cero, pero si nos da por repetir los cálculos
     agradeceremos que se inicialicen aquí los escaños. */

  printf("Min votos: %ld (%lf de %ld)\n", min_votos, liston, total_votos);
  limpia_sillas(partidos, npartidos);
  for (sillas=0; sillas<nsillas; ++sillas)
    {
      max=0;
      imax=0;

      for (i=0; i<npartidos; ++i)
    {
      if (partidos[i].votos<min_votos)
        continue;       /* ignoramos el partido si no llega al mínimo */
      if (partidos[i].votos / (partidos[i].sillas+1) > max )
        {
          max = partidos[i].votos / (partidos[i].sillas+1);
          imax = i;
        }
    }
      partidos[imax].sillas++;
    }
}

void print_partido(const TPartido *p)
{
  printf ("Partido: %s\n", p->nombre);
  printf ("Votos: %ld\n", p->votos);
  printf ("Escaños: %d\n", p->sillas);
  printf ("\n");
}

void print_resultados (const TPartido partidos[], int n_partidos, long votos_nulos, long votos_blanco)
{
  unsigned i;
  for (i=0; i<n_partidos; ++i)
    print_partido(&partidos[i]);

  printf ("Votos nulos: %ld\n", votos_nulos);
  printf ("Votos en blanco: %ld\n", votos_blanco);
}

int sin_repetir (int valores[], int total, int max)
{
  int encontrado;
  int i;
  int gen;

  do
    {
      gen = rand()%(max+1);
      encontrado = 0;
      for (i=0; i<total; ++i)
    {
      if (valores[i] == gen)
        encontrado = 1;
    }
    } while (encontrado);

  return gen;
}

void genera_resultados(TPartido partidos[], int n_partidos, long *votos_nulos, long *votos_blancos, long total_votos)
{
  srand(time(NULL));

  double correc = 0.90;     /* Como mucho, un partido podrá conseguir el voto del 90% de la gente */
  int *votados = malloc(sizeof(int)*n_partidos); /* Creamos un array para almacenar los partidos que ya hayamos votado */
  int generados = 0;                 /* Número de partidos rellenos con votos */
  int partido;
  int i;

  while (generados<n_partidos)
    {
      partido = sin_repetir(votados, generados, n_partidos-1);
      votados[generados++] = partido;

      partidos[partido].votos=rand()%(long)(total_votos*correc);
      total_votos -= partidos[partido].votos;
    }

  *votos_blancos = rand()%total_votos;
  *votos_nulos = total_votos - *votos_blancos;

  free(votados);                 /* Liberamos el array */
}

#define N_ESC 2 /* número de escaños en liza. */
#define N_PAR 3 /* número de partidos que concurren */
int main(int argc, char* argv[])
{
  TPartido partidos[] = {
    {"Ciudadanos", 0, 0},
    {"Ciudadanos Libres Unidos", 0, 0},
    {"Equo", 0, 0},
    {"Izquierda Unida", 0, 0},
    {"Partido Animalista Contra el Maltrato Animal", 0, 0},
    {"Partido Popular", 0, 0},
    {"Partido Socialista", 0, 0},
    {"Podemos", 0, 0},
    {"Unión Progreso y Democracia", 0, 0}
  };

  /* Podemos dar el número contado directamente, pero bueno,
     es un ejemplo, y podemos generarlo. */

  int n_partidos = sizeof(partidos)/sizeof(TPartido);
  long votos_nulos=0, votos_blancos=0;
  long total_votos = 10000000;  /* Un millón de votos a repartir */
  int total_sillas = 263;
  double liston = 0.03;

  genera_resultados (partidos, n_partidos, &votos_nulos, &votos_blancos, total_votos);

  calcula_dhont (partidos, n_partidos, votos_nulos, votos_blancos, total_sillas, liston);

  print_resultados(partidos, n_partidos, votos_nulos, votos_blancos);
}

Este método intenta ser lo más justo posible, sin desmembrar candidatos. Con esto me refiero a que si hiciéramos un reparto 100% proporcional, en el número de escaños saldrían decimales… y a una persona está feo partirla en trozos para una cosa así.

Por otro lado, en muchos sitios se utiliza un umbral de voto, es decir, un porcentaje de votos mínimos para ser tenido en cuenta en la representación parlamentaria. Yo comprendo que en el pasado, cuando no había ordenadores, se hiciera esto, porque hacer los cálculos a mano tiene que ser horrible.

Aún más, si, como en España, utilizamos este método de manera provincial junto con el anterior, podremos ver que hay partidos que tienen de sobra votos suficientes para tener representación de manera global, pero al no alcanzar el mínimo en las diferentes provincias, no la obtienen.

Este pequeño programa nos puede ayudar a ver también cómo variarían los resultados cambiando algunas cosas, por ejemplo, ¿qué pasaría si el número de votos en blanco es el doble? ¿y si quitamos el porcentaje de umbral? ¿y si nadie hubiera votado a xxxx ?

En el código anterior, confieso que el código pare generar los votos es más grande que el método para asignar los escaños. Intenté que sólo se generaran el número de votos que se indican, y que además, sea lo más aleatorio posible (si ponemos que los votos se generen en el mismo orden en el que están introducidos los partidos, es muy grande la probabilidad de que el primer partido sea el más votado, y no quería que eso sucediese).

Para terminar, os dejo un ejemplo de una generación de resultados, no ha sido totalmente al azar, ha sido la primera que he generado en la que el PP obtuvo 0 escaños.
Screenshot 17-12-2015-171211
Foto: Kate Tandy (Unsplash)

También podría interesarte....

Leave a Reply