/*
* Compiled by Andruid Kerne, Texas A&M University and Creating Media LLC.
* Copyright 1996-2002 by Andruid Kerne.
* Use freely without profit, so long as this notice is included intact.
*/
package ecologylab.generic;
import java.util.Vector;
/**
* Mathematical tools for shaping ranges of values;
* wrappers beyond @link java.lang.Math.
* Includes various falvors of random.
*/
public class MathTools
{
MathTools() {}
/**
* @return a random float (instead of a double)
*/
public static float random() { return (float) Math.random(); }
/**
* @return a random integer <= max
*/
public static int rand(int max)
{
return (int) (Math.random() * (max + 1));
}
// an int: [0, max - 1]
/**
* @return a random integer < max
*/
public static int random(int max)
{
return (int) (Math.random() * max);
}
/**
* @return a random float < max
*/
public static float random(float max)
{
return (float) Math.random() * max;
}
/**
* heads i win. tails you lose.
*/
public static boolean tossCoin() { return rand(1) == 1; }
/**
* @param choices := array of pairs;
* each pair := [value, probability]
*/
public static float pick(float[][] choices)
{
float sum = 0, indicator, bracket = 0;
for (int i=0; i != choices.length; i++)
sum += choices[i][1];
indicator = (float) Math.random() * sum;
for (int i=0; i != choices.length; i++)
{
bracket += choices[i][1];
if (indicator <= bracket)
return choices[i][0];
}
throw new Error("MoreMath.pick() didnt pick any");
}
public static Vector randomize(Vector v)
{
// swap the random pick with the ith pick (starts w the last one)
// then do it again, without the last one (its been randomized)
for (int i=v.size(); i != 0; i--)
{
int pick = (int) (Math.random() * i);
// swap em
Object o = v.elementAt(i - 1);
v.setElementAt(v.elementAt(pick), i - 1);
v.setElementAt(o, pick);
}
return v;
}
/**
* push <code>a</code> to 1 extreme or the other, based on b
*/
public static float bias(float a, float b)
{
if (a < .001)
return 0;
else if (a > .999)
return 1;
else if (b < .001)
return 0;
else if (b > .999)
return 1;
else
return (float)(Math.pow(a, Math.log(b) / Math.log(0.5)));
}
/**
* push a towards middle (b < .5), or extrema (b > .5).
*
* could also be called "contrast".
*/
public static float gain(float a, float b)
{
float p;
if (a < .001f)
return 0;
else if (a > .999)
return 1;
b = (b < .001f) ? .001f : (b > .999f) ? .999f : b;
p = (float) (Math.log(1 - b) / Math.log(0.5f));
if (a < 0.5f)
return (float) (Math.pow(2 * a, p) / 2);
else
return (float) (1 - Math.pow(2 * (1 - a), p) / 2);
}
public static float randGain(float factor)
{ return MathTools.gain(random(), factor); }
public static float randBias(float factor)
{ return MathTools.bias(random(), factor); }
/**
* plus or minus
* @param op is 0 to 1
*/
public static float pM(float op, float factor)
{ return (op - .5f) * factor;}
/**
* random plus or minus
* @param factor the magnitude of the desired result.
*
* @return a random number in the interval [-factor, factor].
*/
public static float randPM(float factor)
{ return pM(random(), factor);}
public static float toExtremes(float x)
{
float factor = bias(random(), .8f);
return gain(x, factor);
}
}