2005-10-20 17:45:00 +02:00
|
|
|
/*
|
2005-11-26 17:52:51 +01:00
|
|
|
maths.c
|
|
|
|
|
2005-10-20 17:45:00 +02:00
|
|
|
Bygfoot Football Manager -- a small and simple GTK2-based
|
|
|
|
football management game.
|
|
|
|
|
|
|
|
http://bygfoot.sourceforge.net
|
|
|
|
|
|
|
|
Copyright (C) 2005 Gyözö Both (gyboth@bygfoot.com)
|
|
|
|
|
|
|
|
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 2
|
|
|
|
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, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
2004-12-23 13:58:39 +01:00
|
|
|
#include "maths.h"
|
2004-12-30 17:48:19 +01:00
|
|
|
#include "misc.h"
|
2005-04-04 12:36:04 +02:00
|
|
|
#include "variables.h"
|
2004-12-23 13:58:39 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
Generate a Gauss-distributed (pseudo)random number.
|
|
|
|
"By Box and Muller, and recommended by Knuth".
|
|
|
|
@return A Gauss-distributed random number.
|
|
|
|
*/
|
2005-04-04 12:36:04 +02:00
|
|
|
gdouble
|
2004-12-30 17:48:19 +01:00
|
|
|
math_gaussrand(void)
|
2004-12-23 13:58:39 +01:00
|
|
|
{
|
2008-11-25 14:50:07 +01:00
|
|
|
#ifdef DEBUG
|
|
|
|
printf("math_gaussrand\n");
|
|
|
|
#endif
|
|
|
|
|
2005-04-04 12:36:04 +02:00
|
|
|
static gdouble V1, V2, S;
|
2004-12-23 13:58:39 +01:00
|
|
|
static gint phase = 0;
|
2005-04-04 12:36:04 +02:00
|
|
|
gdouble X;
|
2004-12-23 13:58:39 +01:00
|
|
|
|
|
|
|
if(phase == 0) {
|
|
|
|
do {
|
2005-04-04 12:36:04 +02:00
|
|
|
gdouble U1 = g_rand_double(rand_generator);
|
|
|
|
gdouble U2 = g_rand_double(rand_generator);
|
2004-12-23 13:58:39 +01:00
|
|
|
|
|
|
|
V1 = 2 * U1 - 1;
|
|
|
|
V2 = 2 * U2 - 1;
|
|
|
|
S = V1 * V1 + V2 * V2;
|
|
|
|
} while(S >= 1 || S == 0);
|
|
|
|
|
|
|
|
X = V1 * sqrt(-2 * log(S) / S);
|
|
|
|
} else
|
|
|
|
X = V2 * sqrt(-2 * log(S) / S);
|
|
|
|
|
|
|
|
phase = 1 - phase;
|
|
|
|
|
|
|
|
return X;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Generate a Gauss-distributed random number within given boundaries
|
2004-12-30 17:48:19 +01:00
|
|
|
using math_gaussrand().
|
2004-12-23 13:58:39 +01:00
|
|
|
Expectation value of the distribution is (upper + lower) / 2,
|
|
|
|
the variance is so that the number is between the boundaries with probability
|
|
|
|
99,7 %. If the number isn't between the boundaries, we cut off.
|
|
|
|
@param lower Lower cutoff boundary.
|
|
|
|
@param upper Upper cutoff boundary.
|
|
|
|
@return A Gauss-distributed number
|
|
|
|
*/
|
2005-04-04 12:36:04 +02:00
|
|
|
gdouble
|
|
|
|
math_gauss_dist(gdouble lower, gdouble upper)
|
2008-11-25 14:50:07 +01:00
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
printf("math_gauss_dist\n");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2005-04-04 12:36:04 +02:00
|
|
|
gdouble result;
|
2004-12-23 13:58:39 +01:00
|
|
|
|
2005-04-04 12:36:04 +02:00
|
|
|
result = (upper - lower) / 6 * math_gaussrand()
|
|
|
|
+ (upper + lower) / 2;
|
2004-12-23 13:58:39 +01:00
|
|
|
|
|
|
|
if(result < lower)
|
|
|
|
result = lower;
|
|
|
|
|
|
|
|
if(result > upper)
|
|
|
|
result = upper;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Get a certain part of an integer number.
|
|
|
|
|
|
|
|
If 'place' is between 1 and 9, the 'place'th digit beginning
|
|
|
|
from the right is returned, e.g. if the number = 1234 and
|
|
|
|
place = 2, the function returns 3.
|
|
|
|
|
|
|
|
If 'place' is between 10 and 19, say 10 + x, the first
|
|
|
|
'x' digits are returned, e.g. number = 8765 and place = 12 leads to
|
|
|
|
return value 87.
|
|
|
|
|
|
|
|
If 'place' is between 20 and 29, say 20 + x, the last
|
|
|
|
'x' digits are returned, e.g. number = 4869 and place = 22
|
|
|
|
leads to return value 69.
|
|
|
|
|
|
|
|
@param value The number which gets scrutinized.
|
|
|
|
@param place The number telling the function which part of 'value' to return.
|
|
|
|
@return A part of the integer 'value'.
|
|
|
|
*/
|
|
|
|
gint
|
2004-12-30 17:48:19 +01:00
|
|
|
math_get_place(gint value, gint place)
|
2004-12-23 13:58:39 +01:00
|
|
|
{
|
2008-11-25 14:50:07 +01:00
|
|
|
#ifdef DEBUG
|
|
|
|
printf("math_get_place\n");
|
|
|
|
#endif
|
|
|
|
|
2004-12-23 13:58:39 +01:00
|
|
|
if(place < 10)
|
|
|
|
return (value % (gint)powf(10, place) -
|
|
|
|
value % (gint)powf(10, place - 1)) /
|
|
|
|
(gint)powf(10, place - 1);
|
|
|
|
|
|
|
|
else if(place < 20)
|
|
|
|
{
|
|
|
|
while(value >= (gint)powf(10, place % 10))
|
|
|
|
value = (value - value % 10) / 10;
|
|
|
|
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
return value % (gint)powf(10, place % 10);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Round an integer with given precision.
|
|
|
|
|
|
|
|
If places > 0, round with precision 'places', e.g.
|
|
|
|
number = 124566 and places = 2 leads to return value
|
|
|
|
124600.
|
|
|
|
|
|
|
|
If places < 0, precision is length of 'number' minus
|
|
|
|
'places', e.g. number = 654987 and places = -2 leads to return
|
|
|
|
value 65000.
|
|
|
|
|
|
|
|
@param number The number to be rounded.
|
|
|
|
@param places The precision.
|
|
|
|
@return The rounded integer.
|
|
|
|
*/
|
|
|
|
gint
|
2004-12-30 17:48:19 +01:00
|
|
|
math_round_integer(gint number, gint places)
|
2004-12-23 13:58:39 +01:00
|
|
|
{
|
2008-11-25 14:50:07 +01:00
|
|
|
#ifdef DEBUG
|
|
|
|
printf("math_round_integer\n");
|
|
|
|
#endif
|
|
|
|
|
2004-12-23 13:58:39 +01:00
|
|
|
gint length = 0;
|
|
|
|
gfloat copy = (gfloat)number;
|
|
|
|
|
|
|
|
if(places > 0)
|
|
|
|
return (gint)rint( (gfloat)number / powf(10, places) ) *
|
|
|
|
powf(10, places);
|
|
|
|
|
|
|
|
while(copy >= 1)
|
|
|
|
{
|
|
|
|
copy /= 10;
|
|
|
|
length++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (gint)rint( (gfloat)number / powf(10, length + places) ) *
|
|
|
|
powf(10, length + places);
|
|
|
|
}
|
2004-12-30 17:48:19 +01:00
|
|
|
|
|
|
|
/** Generate a permutation of integers and write it to 'array'.
|
|
|
|
@param array The integer array we store the permutation in.
|
|
|
|
It must have size at least end - start - 1.
|
|
|
|
@param start The integer to start with.
|
|
|
|
@param end The integer to end with. */
|
|
|
|
void
|
|
|
|
math_generate_permutation(gint *array, gint start, gint end)
|
|
|
|
{
|
2008-11-25 14:50:07 +01:00
|
|
|
#ifdef DEBUG
|
|
|
|
printf("math_generate_permutation\n");
|
|
|
|
#endif
|
|
|
|
|
2004-12-30 17:48:19 +01:00
|
|
|
gint i;
|
|
|
|
|
|
|
|
for(i = start; i < end + 1; i++)
|
|
|
|
array[i - start] = i;
|
|
|
|
|
|
|
|
for(i=0;i<end - start;i++)
|
|
|
|
misc_swap_int(&array[i], &array[math_rndi(i, end - start)]);
|
|
|
|
}
|
2005-01-09 21:21:22 +01:00
|
|
|
|
|
|
|
/** This function tells us how many teams from 'number' teams
|
|
|
|
have to be left away to obtain a power of 2. */
|
|
|
|
gint
|
|
|
|
math_get_bye_len(gint number)
|
|
|
|
{
|
2008-11-25 14:50:07 +01:00
|
|
|
#ifdef DEBUG
|
|
|
|
printf("math_get_bye_len\n");
|
|
|
|
#endif
|
|
|
|
|
2005-01-09 21:21:22 +01:00
|
|
|
gint i;
|
|
|
|
|
2005-03-03 13:46:48 +01:00
|
|
|
for(i=0;i<20;i++)
|
|
|
|
if((gint)powf(2, i) >= number)
|
2005-01-09 21:21:22 +01:00
|
|
|
break;
|
|
|
|
|
2005-03-03 13:46:48 +01:00
|
|
|
return (gint)powf(2, i) - number;
|
2005-01-09 21:21:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Return the sum of the integers in the array.
|
|
|
|
@param array The integer array.
|
|
|
|
@param max The size of the array.
|
|
|
|
@return The sum of all the integers in the array. */
|
|
|
|
gint
|
2005-03-03 13:46:48 +01:00
|
|
|
math_sum_int_array(const gint *array, gint max)
|
2005-01-09 21:21:22 +01:00
|
|
|
{
|
2008-11-25 14:50:07 +01:00
|
|
|
#ifdef DEBUG
|
|
|
|
printf("math_sum_int_array\n");
|
|
|
|
#endif
|
|
|
|
|
2005-01-09 21:21:22 +01:00
|
|
|
gint i, sum = 0;
|
|
|
|
|
|
|
|
for(i=0;i<max;i++)
|
|
|
|
sum += array[i];
|
|
|
|
|
|
|
|
return sum;
|
|
|
|
}
|