I have an angle say 60deg and want to generate random angle within interval say [-120,120] where the interval centred around the 60deg which be now [-60,180]
I have this code below:
http://www.cs.princeton.edu/introcs/22library/StdRandom.java.html
I'm confused because it's say that the gaussian distribution is within [0,1].
How could I pass the range [-120,120]?
The 60 angle is the relative rotation of an object the generated random angle is a predication of it's next postion
When testing the code I have angles ,say 65 ,55 if i use this angle directly it performs stranges so I take the difference 65-60 ,55-60.
Is this idea correct?
If you have a random number with a range 0 to 1, you can convert it to -120 to 120 by using:
rand_num*240 - 120
More generally, transforming any number within range [A,B] to range [C,D] involves:
num * (D-C)/(B-A) + C
I'm not sure what you mean by keeping your mean, however.
If you want a range that extends 120 in each direction, from 60, you could either do the above and add 60, or use a range [60-120,60+120] = [-60,180]
In that sense, you'd have
rand_num * 240 - 60
following from the formula given above
static void Main(string[] args)
{
Random rand = new Random();
double a = 0;
for (int i = 0; i < 1000; i++)
{
double r = rand.NextDouble() * 240 - 60;
a += r;
Console.WriteLine(string.Format("ang:{0,6:0.0} avg:{1,5:0.0}", r, a / (i + 1)));
}
Console.ReadKey();
}
If you have something that generates random numbers in a range such as [0, 1] it's easy to transform that to another range, such as [-120, 120]: you just have to multiply by the size of the target range (240 in this case) and add the start of the target range (-120 in this case).
So, for example:
java.util.Random random = new java.util.Random();
// Generate a random number in the range [-120, 120]
double value = random.nextDouble() * 240.0 - 120.0;
Is there a special reason why you are using that StdRandom class? Does the distribution of the random numbers have to be Gaussian? (That doesn't matter, the above will still work).
If it has to be centered around 60, then just add 60.
Try this:
import java.lang.Math;
public static void main(String[] args)
{
System.out.println((int)(Math.random()*(-240))+120);
}
You have C# and Java marked as tags. Kind of confusing to figure out which one you want.
I prefer this over the Random class in java.utils because you don't have to instantiate a class. Everything you need is in the static methods of the Math class.
Breakdown:
return Math.random(); // returns a double value [0, 1]
return Math.random()*-240; // returns a double value from [-240, 0]
return (int)(Math.random()*-240); // returns an integer value from [-240, 0]
return (int)(Math.random()*-240) + 120; // returns an integer value from [-120, 120]
Related
I'm trying to create a random float generator (range of 0.0-1.0), where I can supply a single target value, and a strength value that increases or decreases the chance that this target will be hit. For example, if my target is 0.7, and I have a high strength value, I would expect the function to return mostly values around 0.7.
Put another way, I want a function that, when run a lot of times, would produce a distribution graph something like this:
Histogram
Something like a bell curve, yes, but with a strict range limit (instead of the -inf/+inf range limit of a normal distribution). Clamping a normal distribution is not ideal, I want the distribution to naturally end at the range limits.
The approach I've been attempting is to come up with a formula to transform a value from uniform distribution to the mythical distribution I'm envisioning. Something like an inverse sine:
Inverse Sine
with the ability to widen out that middle point, via the strength value:
Widened Midpoint
and also the ability to move that midpoint up and down, via the target value:
Target changed to 0.7 (courtesy of MS Paint because I couldn't figure this part out mathematically)
The range of this theoretical "strength value" is up for debate. I could imagine either a limited value, say between 0 and 1, where 0 means it's uniform distribution and 1 means it's a 100% chance of hitting the target; or, I could imagine a value that approaches a 100% chance the higher it gets, without ever reaching it. Something along either line would work.
I'm working in C# but this can be language-agnostic. Any help pointing me in the right direction is appreciated. Also happy to clarify further.
I'm not a mathematician but I took a look and I feel like I got something that might work for you.
All i did was take the normal distribution formula:
and use 0.7 as mu to shift the distribution towards 0.7. I added a leading coefficient of 0.623 to shift the values to be between 0 and 1 and migrated it from formula to C#, this can be found below.
Usage:
DistributedRandom random = new DistributedRandom();
// roll for the chance to hit
double roll = random.NextDouble();
// add a strength modifier to lower or strengthen the roll based on level or something
double actualRoll = 0.7d * roll;
Definition
public class DistributedRandom : Random
{
public double Mean { get; set; } = 0.7d;
private const double limit = 0.623d;
private const double alpha = 0.25d;
private readonly double sqrtOf2Pi;
private readonly double leadingCoefficient;
public DistributedRandom()
{
sqrtOf2Pi = Math.Sqrt(2 * Math.PI);
leadingCoefficient = 1d / (alpha * sqrtOf2Pi);
leadingCoefficient *= limit;
}
public override double NextDouble()
{
double x = base.NextDouble();
double exponent = -0.5d * Math.Pow((x - Mean) / alpha, 2d);
double result = leadingCoefficient * Math.Pow(Math.E,exponent);
return result;
}
}
Edit:
In case you're not looking for output similar to the distribution histogram that you provided and instead want something more similar to the sigmoid function you drew I have created an alternate version.
Thanks to Ruzihm for pointing this out.
I went ahead and used the CDF for the normal distribution: where erf is defined as the error function: . I added a coefficient of 1.77 to scale the output to keep it within 0d - 1d.
It should produce numbers similar to this:
Here you can find the alternate class:
public class DistributedRandom : Random
{
public double Mean { get; set; } = 0.7d;
private const double xOffset = 1d;
private const double yOffset = 0.88d;
private const double alpha = 0.25d;
private readonly double sqrtOf2Pi = Math.Sqrt(2 * Math.PI);
private readonly double leadingCoefficient;
private const double cdfLimit = 1.77d;
private readonly double sqrt2 = Math.Sqrt(2);
private readonly double sqrtPi = Math.Sqrt(Math.PI);
private readonly double errorFunctionCoefficient;
private readonly double cdfDivisor;
public DistributedRandom()
{
leadingCoefficient = 1d / (alpha * sqrtOf2Pi);
errorFunctionCoefficient = 2d / sqrtPi;
cdfDivisor = alpha * sqrt2;
}
public override double NextDouble()
{
double x = base.NextDouble();
return CDF(x) - yOffset;
}
private double DistributionFunction(double x)
{
double exponent = -0.5d * Math.Pow((x - Mean) / alpha, 2d);
double result = leadingCoefficient * Math.Pow(Math.E, exponent);
return result;
}
private double ErrorFunction(double x)
{
return errorFunctionCoefficient * Math.Pow(Math.E,-Math.Pow(x,2));
}
private double CDF(double x)
{
x = DistributionFunction(x + xOffset)/cdfDivisor;
double result = 0.5d * (1 + ErrorFunction(x));
return cdfLimit * result;
}
}
I came up with a workable solution. This isn't quite as elegant as I was aiming for because it requires 2 random numbers per result, but it definitely fulfills the requirement. Basically it takes one random number, uses another random number that's exponentially curved towards 1, and lerps towards the target.
I wrote it out in python because it was easier for me to visualize the histogram of it:
import math
import random
# Linearly interpolate between a and b by t.
def lerp(a, b, t):
return ((1.0 - t) * a) + (t * b)
# What we want the median value to be.
target = 0.7
# How often we will hit that median value. (0 = uniform distribution, higher = greater chance of hitting median)
strength = 1.0
values = []
for i in range(0, 1000):
# Start with a base float between 0 and 1.
base = random.random()
# Get another float between 0 and 1, that trends towards 1 with a higher strength value.
adjust = random.random()
adjust = 1.0 - math.pow(1.0 - adjust, strength)
# Lerp the base float towards the target by the adjust amount.
value = lerp(base, target, adjust)
values.append(value)
# Graph histogram
import matplotlib.pyplot as plt
import scipy.special as sps
count, bins, ignored = plt.hist(values, 50, density=True)
plt.show()
Target = 0.7, Strength = 1
Target = 0.2, Strength = 1
Target = 0.7, Strength = 3
Target = 0.7, Strength = 0
(This is meant to be uniform distribution - it might look kinda jagged, but I tested and that's just python's random number generator.)
I'd like to take a range of four random integers between 1-64, and generate a random value somewhere within the range but leaning towards a more weighted average.
The practical application is that you take a pixel, grab the 4 surrounding pixels and use those plus the current pixel to generate a value that can then be used as the base weight for a Gaussian random number generator. So you have a pixel of 10 brightness, surrounded by 8,8,9,9. Add them all up, average out to 8.8. 8.8 is then the weight for the Gaussian random number generator. So you have a random result within a range, but close to the average brightness which is 8.8, and still with some element of randomness.
The issue comes when you have wide variations because of random noise.
To give a pseudo example of how I would like it to work..
Input = [1,16,19,21]
The average of this is 14.25, but that has too much movement because of the "1" bringing the average way down. The average of this should be more around the 18 mark, because more of the numbers are clustered around that area.
I would like to see a random result coming out that is between 1 and 64, but heavily weighted between 15 and 22, with a lower possibility of it being towards the 1(Because it is still within the range as a whole) and a much lower possibility of it being over 22(Because that is completely outside of the range).
Additional The purpose of this is to generate a galactic map. I have got to the point where I have a good set of galaxy shaped data, giving me the rough density of each sector on the map. Now I need to generate specific sets of data and generate exact numbers of stars in each sector. Taking the average of the 4 surrounding sectors and using that to work out how "dense" this sector should be is the main purpose. The main thing I want to avoid is that sectors bordering an empty region of space do not also end up mostly empty, as this does not fit with general observations of galaxies.
You could imagine that the four numbers are points in a line, the x axis. Around that points there is a sphere of probability with a radius of 64, with the probability more concentrated in the proximity of the points rather than on the edges. Pick randomly one of the four points, calculate a random point inside the sphere of that number and take its x coordinate. Repeat if it is out of the range 1..64.
using System;
using System.Collections.Generic;
namespace ProbabilityDistribution1
{
class Program
{
// This derived class converts the uniformly distributed random
// numbers generated by base.Sample( ) to another distribution.
class RandomProportional : Random
{
// The Sample method generates a distribution more concentrated around the 0, in the range [0.0, 1.0].
protected override double Sample()
{
double BSample = base.Sample();
const double concentrationAroundInputs = 5;//more concentrated when greater
double result = Math.Pow(BSample, concentrationAroundInputs);
return result;
}
}
static double XCoordinateOfRandomUnitInsideSphere(Random aRandom)
{
//Even with uniform distribution the probability of exiting is greater than 0.5 on each iteration
while (true)
{
double x = aRandom.NextDouble();
double y = aRandom.NextDouble();
double z = aRandom.NextDouble();
if ((x * x + y * y + z * z) < 1) //inside the sphere
{
return x;
}
}
}
static void TestDistribution()
{
double[] Input = { 1, 16, 19, 21 };
List<int> sampleValues = new List<int>();
Random aRandom = new Random();
RandomProportional aRandomProportinal = new RandomProportional();
for (int i = 0; i < 100; i++)
{
int value = 0;
do
{
int indexChosen = aRandom.Next(4);
double xCoordinate = XCoordinateOfRandomUnitInsideSphere(aRandomProportinal);
if (aRandom.Next(2)==0)
{
xCoordinate = -xCoordinate;
}
double xRandomResult = xCoordinate * 64;
value = (int)(Input[indexChosen] + xRandomResult);
} while (value < 1 || value > 64);
sampleValues.Add((int)value);
}
sampleValues.Sort();
Console.WriteLine();
foreach (int i in sampleValues)
{
Console.Write(" {0:00} ", i);
}
Console.WriteLine();
}
static void Main(string[] args)
{
TestDistribution();
Console.WriteLine("end");
Console.ReadLine();
}
}
}
I'm stuck on one final piece of a calculation puzzle below. I know how to generate a percentage score of correct parts from total correct possible parts ((correctNumPartsOnBoard / totalPossibleCorrectParts)*100) but I want to the final percentage score to factor in the number the incorrect parts on the board as well. (even if all the right parts are on the board you still won't get 100% if there are also incorrect parts). Right now my current formula percentCorrectParts = ((correctNumPartsOnBoard / totalPossibleCorrectParts) / totalNumPartsOnBoard) * 100); is wrong and I'm having trouble pinpointing the correct calculation.
So, the way the calc would need to work is: a user needs to match one of the six possible animals, each animal has around 15 correct parts, but users can also drag incorrect parts onto the board (parts from the other animals are still visible so they could drag a different set of legs or horns on a lizard head, they could make frankenstein type creatures as well this way). So the total number of parts available would be 6*15. But seeing as how they're not all correct they would influence the score as well by bringing the overall score average of pieces on the board down.
What's the correct formula for this?
// Scoring System
using UnityEngine;
using System.Linq;
using System.Collections.Generic;
public class ScoreManager : MonoBehaviour
{
public List<string> totalBuildBoardParts; // Running list of all parts on board (by Tag)
public int numCorrectPartsOnBoard;
public int numIncorrectPartsOnBoard;
public int totalPossibleCorrectParts;
public float percentCorrectParts;
void Start()
{
GameObject gameController = GameObject.FindGameObjectWithTag("gc");
GameSetup gameSetup = gameController.GetComponent<GameSetup>();
totalPossibleCorrectParts = gameSetup.totalPossibleCorrectParts;
Debug.Log("TOTAL POSSIBLE CORRECT PARTS ARE: " + totalPossibleCorrectParts);
}
public void AddAnimalPartByTag(string tag)
{
// Add object tag to List
totalBuildBoardParts.Add(tag);
Debug.Log ("Added an object tagged as: " + tag);
GameObject gameController = GameObject.FindGameObjectWithTag("gc");
GameSetup gameSetup = gameController.GetComponent<GameSetup>();
if (tag == gameSetup.activeTag)
{
numCorrectPartsOnBoard ++;
Debug.Log ("There are " + numCorrectPartsOnBoard + " correct parts on the board");
} else {
numIncorrectPartsOnBoard ++;
}
CalculateScore();
}
public void RemoveAnimalPartByTag(string tag)
{
// Add object tag to List
totalBuildBoardParts.Remove(tag);
Debug.Log ("Removed an object tagged as: " + tag);
GameObject gameController = GameObject.FindGameObjectWithTag("gc");
GameSetup gameSetup = gameController.GetComponent<GameSetup>();
if (tag == gameSetup.activeTag)
{
numCorrectPartsOnBoard --;
Debug.Log ("There are " + numCorrectPartsOnBoard + " correct parts on the board");
} else {
numIncorrectPartsOnBoard --;
}
CalculateScore();
}
public void CalculateScore()
{
float totalNumPartsOnBoard = totalBuildBoardParts.Count();
float correctNumPartsOnBoard = numCorrectPartsOnBoard;
percentCorrectParts = ((correctNumPartsOnBoard / totalPossibleCorrectParts) / totalNumPartsOnBoard) * 100);
Debug.Log ("Your current score is: " + percentCorrectParts);
}
}
Your formula is probably correct. However, your datatypes are not.
You are currently doing an integer division, which results in an int too. So let's say that correctNumPartsOnBoard is 3 and totalPossibleCorrectParts is 5, 3/5 gives 0 because an int does not have any decimals.
You need to cast one of the two operands in the division as a datatype with decimals ( float, double or decimal for example):
percentCorrectParts = ((correctNumPartsOnBoard / (float)totalPossibleCorrectParts) / totalNumPartsOnBoard) * 100);
By setting denominator totalPossibleCorrectParts as a float, the first division will return a float. That float is then used in the second division, also returning correctly a float.
I think your formula should look like this:
int correctParts;
int possibleCorrect;
int incorrectParts;
int parts;
float percentFinished =
Mathf.Max((((float)correctParts/possibleCorrect) // Correct percent
- ((float)incorrectParts/parts)) // Minus incorrect percent
* 100f, // Normalized to 100
0f); // Always a minimum of 0
Also with this formula unlike other answers, you don't have to use all of the parts to get 100%, just get the total possible correct parts which doesn't necessarily have to use up all of your parts ;)
Scenario
Lets say you have 100 parts, with 3 right and 3 wrong. Total right we are aiming for here is 20.
int correctParts = 3;
int possibleCorrect = 20;
int incorrectParts = 3;
int parts = 100;
float percentFinished =
Mathf.Max((((float)correctParts/possibleCorrect) // Correct percent is 0.15 or 15%
- ((float)incorrectParts/parts)) // Minus incorrect percent which is .03 or 3%
* 100f, // Normalized to 100 which gives us 15% - 3% = 12%
0f); // Always a minimum of 0
I think your final (%age) score should be:
correctNumPartsOnBoard / totalNumPartsOnBoard * 100
If you have 80 correctparts and 20 incorrect then the total parts is 100 and you've got 80 of them correct so you should score 80% like this:
80 / (80+20) * 100
I get the bezier value from a path like this (note: If there is another/better way to do that let me know, please):
public static Vector3 PathCubic (float t, Vector3[] path)
{
if (t >= 1f)
return path[path.Length - 1];
// projects t in the path
var projT = path.Length / 3 * t;
// what interval t is (between P1 and P2 or between P2 and P3, etc)
var range = (int)projT;
// get the interval index
var i = range * 3;
var p0 = path[i + 0]; // first point
var c0 = path[i + 1]; // control 1
var c1 = path[i + 2]; // control 2
var p1 = path[i + 3]; // second point
// calculate bezier in the current interval
return Cubic(projT - range, p0, c0, c1, p1);
}
So, supposing points P1, P2, P3, P4, t = 0.0 is the first point P1 and t = 1.0 is the last point P4.
But, that doesn't give me a constant moviment over the bezier. Image bellow depicts what I mean. A t = 0.5 give me different positions depending on points location.
I found I have to calculate the length of the path in order to achieve that. And here comes the problem. Once calculated this length, how can I calculate the interval index, as I did before? Or I will need to walk through each interval (for instruction) in order to find that?
// get the ***interval index***
var i = range * 3;
var p0 = path[i + 0]; // first point
var c0 = path[i + 1]; // control 1
var c1 = path[i + 2]; // control 2
var p1 = path[i + 3]; // second point
There is no true solution but here is a usefull approximation:
First get the length of each segment. Let's say it's:
// |a b| is the operator of length between two points a and b
A=|P1 P2|=3.0
B=|P2 P3|=1.2
C=|P3 P4|=0.8
L=A+B+C=5.0 // length of the whole spline
Your t=0.5 and is between points P1 and P2 - we know that because t*L = 2.5 and length A=3 (and A is first, so the immaginary length before was 0).
We also know that the value of t that we want should be on 2.5/3.0 =~ 0.833 of the length between points P1 and P2.
Note that P1was calculated with t = 0 and P2 with t =~ 0.333.
We can now find the fixed value of t: Tfix=Mathf.Lerp(0, 0.333, 0.833) =~ 0.277, where:
0 - t of point P1
0.333 - t of point P2
0.833 - the approximated position of searched t relative to closest approximation points.
Finally to find the point you were searching for substitute Tfix for t: PathCubic(Tfix)
Also, think about using more approximation points. For more demanding uses I needed dividing the segment in 16 pieces.
Mathematical answer: in general you can't. There is no symbolic way to determine the length of your cubic curve (it'd require solving a 6th order polynomial, which cannot be with regular formula manipulations), so there's no way to straight-up compute which t value you need for distance d along your curve.
The fastest solution is typically to index your curve: at fixed t intervals, build a lookup table with the length of the curve up to that point. Then use that LUT to do estimation. If your curve is length 42, and your LUT is distance = [0,5,12,25,37,42] for corresponding t = [0,1/5,2/5,3/5,4/5,1] then now you can use that data at moment to quickly estimate which t values you need to highlight which fixed distances, using simple linear interpolation.
Given the start and the end of an integer range, how do I calculate a normally distributed random integer between this range?
I realize that the normal distribution goes into -+ infinity. I guess the tails can be cutoff, so when a random gets computed outside the range, recompute. This elevates the probability of integers in the range, but as long as the this effect is tolerable (<5%), it's fine.
public class Gaussian
{
private static bool uselast = true;
private static double next_gaussian = 0.0;
private static Random random = new Random();
public static double BoxMuller()
{
if (uselast)
{
uselast = false;
return next_gaussian;
}
else
{
double v1, v2, s;
do
{
v1 = 2.0 * random.NextDouble() - 1.0;
v2 = 2.0 * random.NextDouble() - 1.0;
s = v1 * v1 + v2 * v2;
} while (s >= 1.0 || s == 0);
s = System.Math.Sqrt((-2.0 * System.Math.Log(s)) / s);
next_gaussian = v2 * s;
uselast = true;
return v1 * s;
}
}
public static double BoxMuller(double mean, double standard_deviation)
{
return mean + BoxMuller() * standard_deviation;
}
public static int Next(int min, int max)
{
return (int)BoxMuller(min + (max - min) / 2.0, 1.0);
}
}
I probably need to scale the standard deviation some how relative to the range, but don't understand how.
Answer:
// Will approximitely give a random gaussian integer between min and max so that min and max are at
// 3.5 deviations from the mean (half-way of min and max).
public static int Next(int min, int max)
{
double deviations = 3.5;
int r;
while ((r = (int)BoxMuller(min + (max - min) / 2.0, (max - min) / 2.0 / deviations)) > max || r < min)
{
}
return r;
}
If the Box-Muller method returns a "standard" normal distribution, it will have mean 0 and standard deviation 1. To transform a standard normal distribution, you multiply your random number by X to get standard deviation X, and you add Y to obtain mean Y, if memory serves me correctly.
See the Wikipedia article's section on normalizing standard normal variables (property 1) for a more formal proof.
In response to your comment, the rule of thumb is that 99.7% of a normal distribution will be within +/- 3 times the standard deviation. If you need a normal distribution from 0 to 100 for instance, than your mean will be halfway, and your SD will be (100/2)/3 = 16.667. So whatever values you get out of your Box-Muller algorithm, multiply by 16.667 to "stretch" the distribution out, then add 50 to "center" it.
John, in response to your newest comment, I'm really not sure what is the point of the Next function. It always uses a standard deviation of 1 and a mean of halfway between your min and max.
If you want a mean of Y, with ~99.7% of the numbers in the range -X to +X, then you just call BoxMuller(Y, X/3).
Well, the -2*sigma..+2*sigma will give you 95% of the bell curve.
(check the "Standard deviation and confidence intervals" section in the already mentioned wiki article).
So modify this piece:
return (int)BoxMuller(min + (max - min) / 2.0, 1.0);
and change 1.0 (standard deviation) to 2.0 (or even more if you want more than 95% coverage)
return (int)BoxMuller(min + (max - min) / 2.0, 2.0);