Freeciv-3.3
Loading...
Searching...
No Matches
distribute.c
Go to the documentation of this file.
1/***********************************************************************
2 Freeciv - Copyright (C) 2004 - The Freeciv Project
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12***********************************************************************/
13
14#ifdef HAVE_CONFIG_H
15#include <fc_config.h>
16#endif
17
18/* utility */
19#include "log.h" /* fc_assert */
20
21#include "distribute.h"
22
23/************************************************************************/
34void distribute(int number, unsigned groups, const unsigned *ratios,
35 int *result)
36{
37 int i, sum = 0, rest[groups], max_groups[groups], max_count, max;
38#ifdef FREECIV_DEBUG
39 const int original_number = number;
40#endif
41
42 /*
43 * Distribution of a number of items into a number of groups with a given
44 * ratio. This follows a modified Hare/Niemeyer algorithm (also known
45 * as "Hamilton's Method"):
46 *
47 * 1) distribute the whole-numbered part of the targets
48 * 2) sort the remaining fractions (called rest[])
49 * 3) divide the remaining source among the targets starting with the
50 * biggest fraction. (If two targets have the same fraction the
51 * target with the smaller whole-numbered value is chosen. If two
52 * values are still equal it is the _first_ group which will be given
53 * the item.)
54 */
55
56 for (i = 0; i < groups; i++) {
57 sum += ratios[i];
58 }
59
60 /* 1. Distribute the whole-numbered part of the targets. */
61 for (i = 0; i < groups; i++) {
62 result[i] = number * ratios[i] / sum;
63 }
64
65 /* 2a. Determine the remaining fractions. */
66 for (i = 0; i < groups; i++) {
67 rest[i] = number * ratios[i] - result[i] * sum;
68 }
69
70 /* 2b. Find how much source is left to be distributed. */
71 for (i = 0; i < groups; i++) {
72 number -= result[i];
73 }
74
75 while (number > 0) {
76 max = max_count = 0;
77
78 /* Find the largest remaining fraction(s). */
79 for (i = 0; i < groups; i++) {
80 if (rest[i] > max) {
81 max_count = 1;
82 max_groups[0] = i;
83 max = rest[i];
84 } else if (rest[i] == max) {
86 max_count++;
87 }
88 }
89
90 if (max_count == 1) {
91 /* Give an extra source to the target with largest remainder. */
92 result[max_groups[0]]++;
93 rest[max_groups[0]] = 0;
94 number--;
95 } else {
96 int min = result[max_groups[0]], which_min = max_groups[0];
97
98 /* Give an extra source to the target with largest remainder and
99 * smallest whole number. */
100 fc_assert(max_count > 1);
101 for (i = 1; i < max_count; i++) {
102 if (result[max_groups[i]] < min) {
103 min = result[max_groups[i]];
105 }
106 }
107 result[which_min]++;
108 rest[which_min] = 0;
109 number--;
110 }
111 }
112
113#ifdef FREECIV_DEBUG
114 number = original_number;
115 for (i = 0; i < groups; i++) {
116 fc_assert(result[i] >= 0);
117 number -= result[i];
118 }
119 fc_assert(number == 0);
120#endif /* FREECIV_DEBUG */
121}
char * incite_cost
Definition comments.c:76
void distribute(int number, unsigned groups, const unsigned *ratios, int *result)
Definition distribute.c:34
#define fc_assert(condition)
Definition log.h:177