nvteighen

April 6th, 2008, 05:08 PM

Hi there!

Some of you already know I'm playing around with C. Well, I was wondering if someone could criticize this code, which is maybe my first serious program that actually does something "useful". I'm sure there's a lot to comment and improve on this.

It's a D'Hondt apportionment (http://en.wikipedia.org/wiki/D%27Hondt_method) calculator that uses an input file listing how many votes each party has got and prints how many seats do each receive using this algorithm.

(I GPL'ed because... well, you never know if some code of yours can be useful for someone else!)

This is the code:

/*A D'Hondt/Hagenbach-Bischoff Method implementation in C

*

* Copyright (c) 2008 Eugenio M. Vigo

*

* This program is free software: you can redistribute it and/or modify

* it under the terms of the GNU General Public License as published by

* the Free Software Foundation, either version 3 of the License, or

* (at your option) any later version.

*

* This program is distributed in the hope that it will be useful,

* but WITHOUT ANY WARRANTY; without even the implied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

* GNU General Public License for more details.

*

* You should have received a copy of the GNU General Public License

* along with this program. If not, see <http://www.gnu.org/licenses/>

*

*/

#include <stdio.h>

#include <stdlib.h>

float hb2(int v, int d)

{

float output;

output = v / (d + 1); //Droop quota applied

return output;

}

int exam_max(float *q, int n)

{

int output, i;

float o;

//Primitive way to choose the largest value from a given list.

o = 0;

for(i = 0; i <= n; i++)

{

if(q[i] > o)

{

o = q[i];

output = i;

}

}

return output;

}

int main(int argc, char **argv)

{

FILE *data;

int c, i, n, tot, tot_real, vtot, a, *seats, *vot;

float *q, wz;

if(argc != 2)

{

//Exiting if no file specified or if too much arguments used.

puts("Usage: dhondt FILENAME");

exit(1);

}

if((data = fopen(argv[1], "r")) == NULL)

{

//Opening and testing file. If failed, exiting.

perror("dhondt");

exit(2);

}

/*RAII, so initializing variables.

n = -2 so the last '\n' and 'EOF' characters are not inserted into the vot and seats

arrays*/

n = -2;

tot_real = 0;

vtot = 0;

/*Check in how many parties will the seats be apportioned by counting the amount of integers there are.*/

while(fscanf(data, "%d", &c) != EOF)

{

n++;

}

rewind(data); //Rewinding file.

/*Surely heap can be avoided, but I'm not aware how. So, I'm forced to dynamic allocation

vot = array of votes by each party

seats = array of number of seats

q = quota for each party.*/

vot = malloc(n * sizeof(int));

if(vot == NULL)

exit(3);

seats = malloc(n * sizeof(int));

if(seats == NULL)

exit(4);

q = malloc(n * sizeof(float));

if(q == NULL)

exit(5);

//The first number in the file will be treated as the total amount of seats.

fscanf(data, "%d", &tot);

for(i = 0; i <= n; i++)

{

fscanf(data, "%d", &vot[i]); //Reading

vtot += vot[i]; //Calculating total amount of votes

}

fclose(data); //Closing the file. We don't need it any longer.

wz = vtot / (tot + 1); //D'Hondt uses the Droop quota Q = V / S + 1

for(i = 0; i <= n; i++)

{

seats[i] = (int)(vot[i] / wz); //Seats are integers... you can't have 14.788 seats!

tot_real += seats[i]; //Calculating amount of seats that have been apportioned.

}

/*But as D'Hondt uses down-rounding, tot_real will very probably be some seats smaller than the total amount of seats we wanted to apportion. Here we use the Hagenbach-Bischoff method, a so-called "static" apportionment method: we divide each party's votes by the seats it already has plus 1 (Droop quota again!). One seat is given to the party having the largest quotient. This is repeated until no more seats are needed to apportion.*/

if(tot_real < tot)

{

for(i = 0; i <= n; i++)

q[i] = hb2(vot[i], seats[i]);

a = exam_max(q, n);

seats[a]++;

tot_real++;

}

free(q); //Free malloc'd memory.

for(i = 0; i <= n; i++)

printf("%d\n", seats[i]);

//Free malloc'd memory.

free(vot);

free(seats);

return 0;

}

Input files must only include integers and be written like this:

TOTAL NUMBER OF SEATS

PARTY A's VOTES

PARTY B's VOTES

PARTY C's VOTES

...

Thanks in advance!

Some of you already know I'm playing around with C. Well, I was wondering if someone could criticize this code, which is maybe my first serious program that actually does something "useful". I'm sure there's a lot to comment and improve on this.

It's a D'Hondt apportionment (http://en.wikipedia.org/wiki/D%27Hondt_method) calculator that uses an input file listing how many votes each party has got and prints how many seats do each receive using this algorithm.

(I GPL'ed because... well, you never know if some code of yours can be useful for someone else!)

This is the code:

/*A D'Hondt/Hagenbach-Bischoff Method implementation in C

*

* Copyright (c) 2008 Eugenio M. Vigo

*

* This program is free software: you can redistribute it and/or modify

* it under the terms of the GNU General Public License as published by

* the Free Software Foundation, either version 3 of the License, or

* (at your option) any later version.

*

* This program is distributed in the hope that it will be useful,

* but WITHOUT ANY WARRANTY; without even the implied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

* GNU General Public License for more details.

*

* You should have received a copy of the GNU General Public License

* along with this program. If not, see <http://www.gnu.org/licenses/>

*

*/

#include <stdio.h>

#include <stdlib.h>

float hb2(int v, int d)

{

float output;

output = v / (d + 1); //Droop quota applied

return output;

}

int exam_max(float *q, int n)

{

int output, i;

float o;

//Primitive way to choose the largest value from a given list.

o = 0;

for(i = 0; i <= n; i++)

{

if(q[i] > o)

{

o = q[i];

output = i;

}

}

return output;

}

int main(int argc, char **argv)

{

FILE *data;

int c, i, n, tot, tot_real, vtot, a, *seats, *vot;

float *q, wz;

if(argc != 2)

{

//Exiting if no file specified or if too much arguments used.

puts("Usage: dhondt FILENAME");

exit(1);

}

if((data = fopen(argv[1], "r")) == NULL)

{

//Opening and testing file. If failed, exiting.

perror("dhondt");

exit(2);

}

/*RAII, so initializing variables.

n = -2 so the last '\n' and 'EOF' characters are not inserted into the vot and seats

arrays*/

n = -2;

tot_real = 0;

vtot = 0;

/*Check in how many parties will the seats be apportioned by counting the amount of integers there are.*/

while(fscanf(data, "%d", &c) != EOF)

{

n++;

}

rewind(data); //Rewinding file.

/*Surely heap can be avoided, but I'm not aware how. So, I'm forced to dynamic allocation

vot = array of votes by each party

seats = array of number of seats

q = quota for each party.*/

vot = malloc(n * sizeof(int));

if(vot == NULL)

exit(3);

seats = malloc(n * sizeof(int));

if(seats == NULL)

exit(4);

q = malloc(n * sizeof(float));

if(q == NULL)

exit(5);

//The first number in the file will be treated as the total amount of seats.

fscanf(data, "%d", &tot);

for(i = 0; i <= n; i++)

{

fscanf(data, "%d", &vot[i]); //Reading

vtot += vot[i]; //Calculating total amount of votes

}

fclose(data); //Closing the file. We don't need it any longer.

wz = vtot / (tot + 1); //D'Hondt uses the Droop quota Q = V / S + 1

for(i = 0; i <= n; i++)

{

seats[i] = (int)(vot[i] / wz); //Seats are integers... you can't have 14.788 seats!

tot_real += seats[i]; //Calculating amount of seats that have been apportioned.

}

/*But as D'Hondt uses down-rounding, tot_real will very probably be some seats smaller than the total amount of seats we wanted to apportion. Here we use the Hagenbach-Bischoff method, a so-called "static" apportionment method: we divide each party's votes by the seats it already has plus 1 (Droop quota again!). One seat is given to the party having the largest quotient. This is repeated until no more seats are needed to apportion.*/

if(tot_real < tot)

{

for(i = 0; i <= n; i++)

q[i] = hb2(vot[i], seats[i]);

a = exam_max(q, n);

seats[a]++;

tot_real++;

}

free(q); //Free malloc'd memory.

for(i = 0; i <= n; i++)

printf("%d\n", seats[i]);

//Free malloc'd memory.

free(vot);

free(seats);

return 0;

}

Input files must only include integers and be written like this:

TOTAL NUMBER OF SEATS

PARTY A's VOTES

PARTY B's VOTES

PARTY C's VOTES

...

Thanks in advance!