Formatting double to latitude/longitude human readable format - c#

If the formula for converting latitude or longitude to double is
((Degree) + (Minute) / 60 + (Second) / 3600) * ((South || West) ? -1 : 1)
then what's the formula for parsing degrees, minutes, seconds from a double?
It'd make sense to have two separate methods for parsing latitude and longitude, but I'm not sure how to parse the degrees, minutes, seconds from the double.
ParseLatitude(double value)
{
//value is South if negative, else is North.
}
ParseLongitude(double value)
{
//value is West if negative, else is East.
}
Example coordinates:
latitude: 43.81234123
longitude: -119.8374747
The final code to convert back and forth, thanks again to Peter and James for the answer. I had to convert value to Decimal because this is being used in Silverlight and Math.Truncate(double) is not available):
public class Coordinate
{
public double Degrees { get; set; }
public double Minutes { get; set; }
public double Seconds { get; set; }
public CoordinatesPosition Position { get; set; }
public Coordinate() { }
public Coordinate(double value, CoordinatesPosition position)
{
//sanity
if (value < 0 && position == CoordinatesPosition.N)
position = CoordinatesPosition.S;
//sanity
if (value < 0 && position == CoordinatesPosition.E)
position = CoordinatesPosition.W;
//sanity
if (value > 0 && position == CoordinatesPosition.S)
position = CoordinatesPosition.N;
//sanity
if (value > 0 && position == CoordinatesPosition.W)
position = CoordinatesPosition.E;
var decimalValue = Convert.ToDecimal(value);
decimalValue = Math.Abs(decimalValue);
var degrees = Decimal.Truncate(decimalValue);
decimalValue = (decimalValue - degrees) * 60;
var minutes = Decimal.Truncate(decimalValue);
var seconds = (decimalValue - minutes) * 60;
Degrees = Convert.ToDouble(degrees);
Minutes = Convert.ToDouble(minutes);
Seconds = Convert.ToDouble(seconds);
Position = position;
}
public Coordinate(double degrees, double minutes, double seconds, CoordinatesPosition position)
{
Degrees = degrees;
Minutes = minutes;
Seconds = seconds;
Position = position;
}
public double ToDouble()
{
var result = (Degrees) + (Minutes) / 60 + (Seconds) / 3600;
return Position == CoordinatesPosition.W || Position == CoordinatesPosition.S ? -result : result;
}
public override string ToString()
{
return Degrees + "º " + Minutes + "' " + Seconds + "'' " + Position;
}
}
public enum CoordinatesPosition
{
N, E, S, W
}
Unit Test (nUnit)
[TestFixture]
public class CoordinateTests
{
[Test]
public void ShouldConvertDoubleToCoordinateAndBackToDouble()
{
const double baseLatitude = 43.81234123;
const double baseLongitude = -119.8374747;
var latCoordN = new Coordinate(baseLatitude, CoordinatesPosition.N);
var latCoordS = new Coordinate(baseLatitude, CoordinatesPosition.S);
var lonCoordE = new Coordinate(baseLongitude, CoordinatesPosition.E);
var lonCoordW = new Coordinate(baseLongitude, CoordinatesPosition.W);
var convertedLatitudeS = latCoordS.ToDouble();
var convertedLatitudeN = latCoordN.ToDouble();
var convertedLongitudeW = lonCoordW.ToDouble();
var convertedLongitudeE = lonCoordE.ToDouble();
Assert.AreEqual(convertedLatitudeS, convertedLatitudeN);
Assert.AreEqual(baseLatitude, convertedLatitudeN);
Assert.AreEqual(convertedLongitudeE, convertedLongitudeW);
Assert.AreEqual(baseLongitude, convertedLongitudeE);
}
}

ParseLatitude(double Value)
{
var direction = Value < 0 ? Direction.South : Direction.North;
Value = Math.Abs(Value);
var degrees = Math.Truncate(Value);
Value = (Value - degrees) * 60; //not Value = (Value - degrees) / 60;
var minutes = Math.Truncate(Value);
var seconds = (Value - minutes) * 60; //not Value = (Value - degrees) / 60;
//...
}
ParseLongitude(double Value)
{
var direction = Value < 0 ? Direction.West : Direction.East;
Value = Math.Abs(Value);
var degrees = Math.Truncate(Value);
Value = (Value - degrees) * 60; //not Value = (Value - degrees) / 60;
var minutes = Math.Truncate(Value);
var seconds = (Value - minutes) * 60; //not Value = (Value - degrees) / 60;
//...
}
EDIT
I came back to this because of a recent upvote. Here's a DRY-er version, with the Value parameter renamed to reflect the most common coding convention, in which parameters start with lower-case letters:
ParseLatitude(double value)
{
var direction = value < 0 ? Direction.South : Direction.North;
return ParseLatituteOrLongitude(value, direction);
}
ParseLongitude(double value)
{
var direction = value < 0 ? Direction.West : Direction.East;
return ParseLatituteOrLongitude(value, direction);
}
//This must be a private method because it requires the caller to ensure
//that the direction parameter is correct.
ParseLatitudeOrLongitude(double value, Direction direction)
{
value = Math.Abs(value);
var degrees = Math.Truncate(value);
value = (value - degrees) * 60; //not Value = (Value - degrees) / 60;
var minutes = Math.Truncate(value);
var seconds = (value - minutes) * 60; //not Value = (Value - degrees) / 60;
//...
}

#include <math.h>
void ParseLatitude(double Value, bool &north, double &deg, double &min, double &sec)
{
if ( Value < 0 )
{
ParseLatitude( -Value, north, deg, min, sec );
north = false;
}
else
{
north = true;
deg = floor(Value);
Value = 60*(Value - deg);
min = floor(Value);
Value = 60*(Value - min);
sec = Value;
}
}
// ParseLongitude is similar

I've written a class in C# which does a lot of this. Perhaps it is useful, otherwise you can check out the implementation:
http://code.google.com/p/exif-utils/source/browse/trunk/ExifUtils/ExifUtils/GpsCoordinate.cs

In addition to parsing out the degree, minutes, seconds (which is just radix 60 arithmetic), you may also want to deal with sign of the doubles being converted to "North/South" for latitude and "East/West" for longitude.
It's pretty standard to identify positive degrees latitude with the Northern Hemisphere and negative degrees latitude with the Southern Hemisphere. It's also common here in the Western Hemisphere to take positive degrees longitude to mean degrees West of the Greenwich Meridian and conversely negative degrees longitude to mean degrees East of that Meridian. However the preferred convention for this is the opposite, to take degrees East of the Greenwich Meridian as negative. You may want to consult with your client/analyze the application design to determine which choice applies to this conversion.
Note also that the discontinuity of longitude at ±180 is a cause for care in converting coordinates that may result from calculations. If the conversion is not intended to handle wrap-around at the 180° meridian, then it's likely an exception should be thrown for such inputs. Of course the design decision should be documented either way.
Certainly latitudes outside the ±90° range are errors on input.
Added: Given the above differences in parsing latitude and longitude, issues that would best be handled in the distinct ParseLatitude & ParseLongitude routines, we could use a common utility to do the conversion from double to degrees/minutes/seconds.
I'm not sure what the target language should be here, so I wrote something in plain vanilla C:
#include <math.h>
void double2DegMinSec(double angle, int *Sign, int *Deg, int *Min, double *Sec)
{ /* extract radix 60 Degrees/Minutes/Seconds from "angle" */
Sign = 1;
if (angle < 0.0) /* reduce to case of nonnegative angle */
{
Sign = -Sign;
angle = -angle;
}
*Deg = floor(angle);
angle -= *Deg;
angle *= 60.0;
*Min = floor(angle);
angle -= *Min;
angle *= 60.0;
*Sec = angle;
return;
}
Likely ParseLatitude and ParseLongitude should manage the conversion of angle's sign to the appropriate geographic designation, but I've included an argument Sign that will allow that sign checking to be done after conversion (though it would be fine if the conversion were only ever called with nonnegative angles).
I made the function double2DegMinSec have a return type of void. Results are thus to be returned through its formal arguments of type pointer to int and pointer to double (in the case of seconds Sec, which might have fractional part).
Calling the conversion in C might be done like this:
double longitude = -119.8374747;
int Sign, Degrees, Minutes;
double Seconds;
double2DegMinSec(longitude, &Sign, &Degrees, &Minutes, &Seconds);
In C++ we would make the calling syntax a bit glibber by using call-by-reference instead of pointers.

With just multiplying you'll get conversion errors without noticing it, I noticed it when mapping the points on a map. You'll need to take into account the slope and other variables, like this:
public static void GeoToMercator(double xIn, double yIn, out double xOut, out double yOut)
{
double xArg = xIn / 100000, yArg = yIn / 100000;
xArg = 6371000.0 * Math.PI / 180 * xArg;
yArg = 6371000.0 * Math.Log(Math.Tan(Math.PI / 4 + Math.PI / 180 * yArg * 0.5));
xOut = xArg / 10000;
yOut = yArg / 10000;
}
I'm guessing you're using Mercator values as double representation. To convert the Mercator value back into the correct longitude/latitude values, just use the reverse:
public static void MercatorToGeo(double xIn, double yIn, out double xOut, out double yOut)
{
double xArg = xIn, yArg = yIn;
xArg = 180 / Math.PI * xArg / 6371000.0;
yArg = 180 / Math.PI * (Math.Atan(Math.Exp(yArg / 6371000.0)) - Math.PI / 4) / 0.5;
xOut = xArg * 10;
yOut = yArg * 10;
}
This did the trick for me.

Related

How to detect outliers in an array of doubles?

I'm trying to determine whether or not there is data outliers in a list of doubles. Basically if anything is below 10 percent of the limits or above 90 percent. I have the following code working, but it doesn't work properly with negative numbers and I'm not seeing what is wrong. Is there a better way to approach there, or is there something glaring in the code or math?
public bool DataHasOutliers(IEnumerable<double> results, Limits limits)
{
foreach (double result in results)
{
//detect if any result values are in the low or high regions of the acceptable limits
double deltaAbsolute = (limits.High - limits.Low) < 0 ? (limits.High - limits.Low) * -1 : limits.High - limits.Low;
double absoluteResult = result < 0 ? result * -1 : result;
double lowLimitAbsolute = limits.Low < 0 ? limits.Low * -1 : limits.Low;
double upperThreshold = 0.9 * deltaAbsolute + limits.Low;
double lowerThreshold = 0.1 * deltaAbsolute + limits.Low;
if (absoluteResult >= upperThreshold)
{
"".Dump("Upper threshold violated");
return true;
}
if (absoluteResult <= lowerThreshold)
{
"".Dump("Lower threshold violated");
return true;
}
}
return false;
}
public class Limits
{
public double High { get; set; }
public double Low { get; set; }
public string Error { get; set; }
}
If the limits are [-10, 0] and a result is -5, with the current code you'll effectively be checking if 5 is in [11, 19], which is not correct.
I suggest to keep the sign of the boundaries increasing/decreasing them by the 1/10-th of the range and then check the original result value against this reduced range:
double deltaAbsolute = Math.Abs(limits.High - limits.Low);
double lowerThreshold = limits.Low + 0.1 * deltaAbsolute;
double upperThreshold = limits.High - 0.1 * deltaAbsolute;
if (result >= upperThreshold)
{
"".Dump("Upper threshold violated");
return true;
}
if (result <= lowerThreshold)
{
"".Dump("Lower threshold violated");
return true;
}
Why are you recalculating limits IN the loop.
If High > Low then you don't need any of the absolute stuff.
public bool DataHasOutliers(IEnumerable<double> results, Limits limits)
{
if(limits.High < limits.Low)
{
throw new ArgumentOutOfRangeException();
}
double delta = limits.High - limits.Low;
double upperThreshold = 0.9 * delta + limits.Low;
double lowerThreshold = 0.1 * delta + limits.Low;
foreach (double result in results)
{
//detect if any result values are in the low or high regions of the acceptable limits
if (result >= upperThreshold)
{
"".Dump("Upper threshold violated");
return true;
}
if (result <= lowerThreshold)
{
"".Dump("Lower threshold violated");
return true;
}
}
return false;
}

Length calculator feet and inches

In my if statement (LengthCalculatorOption == 1), I want to convert, for example, 187.96cm to feet and inches, such as 6feet 2ins. How do I do that? In my current code, it shows 6.17feet and always 0ins. I have no idea why.
static void Main(string[] args) {
double Centimetres = 0.0, Feet = 0.0, Inches = 0.0;
string AnotherConversion = null;
string LengthCalculatorMenu;
int LengthCalculatorOption;
do {
LengthCalculatorMenu = ("Enter 1) Convert centimetres to feet and inches:"
+ "\nEnter 2) Convert feet and inches to centimetres:");
Console.Write(LengthCalculatorMenu);
LengthCalculatorOption = int.Parse(Console.ReadLine());
if (LengthCalculatorOption == 1) {
Console.WriteLine("Please Enter the Centimetres(cm) that you wish to convert to feet and inches");
Centimetres = double.Parse(Console.ReadLine());
Feet = (Centimetres / 2.54) / 12;
Inches = (Centimetres / 2.54) - (Feet * 12);
Centimetres = ((Feet * 12) + Inches) * 2.54;
Console.WriteLine("\nThe equivalent in feet and inches is {0:C} ft {1:G} ins", Feet, Inches);
Console.Write("\nWould you like to make an another conversion? \n\n(Enter Y to make an another conversion/Enter any other key to exit):");
AnotherConversion = Console.ReadLine();
} else if (LengthCalculatorOption == 2) {
Console.WriteLine("Please Enter the Feet");
Feet = double.Parse(Console.ReadLine());
Console.WriteLine("Please Enter the Inches");
Inches = double.Parse(Console.ReadLine());
Centimetres = ((Feet * 12) + Inches) * 2.54;
Console.WriteLine("\nThe equivalent in centimetres is {0:G}cm", Centimetres);
Console.Write("\nWould you like to make an another conversion? \n\n(Enter Y to make an another conversion/Enter any other key to exit):");
AnotherConversion = Console.ReadLine();
} else {
Console.WriteLine("\n\a\t Invalid Option!Option Must be 1 or 2");
}
} while (AnotherConversion == "y" || AnotherConversion == "Y");
Try this:
Feet = (Centimetres / 2.54) / 12;
int iFeet = (int)Feet;
inches = (Feet - (double)iFeet) * 12;
To elaborate a bit:
You are defining feet as a double, which means that it will be a decimal value. So since you're dividing by 12, it can become a decimal representation.
What my code does is it converts Feet to integer (which will round it to 6 in this situation). We then subtract the double version of Feet (6.17 in this situation) which equals .17 (The remainder). We multiply that by 12 to convert from .17 feet to inches
Edit
To expand based on Scott's comment, this would be a different way to go
int totalInches = (Centimetres / 2.54); // This will take a floor function of Centimetres/2.54
int Feet = (totalInches - totalInches % 12) / 12; // This will make it divisible by 12
int inches = totalInches % 12; // This will give you the remainder after you divide by 12
To calculate a value in centimeters into feet and inches, you'd likely want to do this:
double centimeters = 187.96;
double inches = centimeters/2.54;
double feet = Math.Floor(inches / 12);
inches -= (feet*12);
Generally-speaking, one should convert down to the most basic level, then calculate your way up. This way, you only do the work of converting one time, instead of having to repeat the conversion calculation. In this insntance, I do the simple conversion of centimeters to inches, and then after that, count the number of feet in inches, then subtract that much from the final inches value.
So, if I had, say, 38 inches, I would have Math.Floor(38 / 12) feet, or 3. Then inches would be set to 38 - (3*12), which is 2, giving a final result of 3 feet, 2 inches.
Keeping it as double, use:
double inp = 12.75; // e.g.
double feet = Math.Floor(inp);
double inches = (inp - feet) * 12.0;
Try this:
double F = Math.Floor(Centimetres * 0.0328084);
Feet = Centimetres * 0.0328084;
Inches = (Feet - F) * 12;
1 ft = 0.30480m
Some general-purpose methods:
public static class Converter
{
public static (int Feet, double Inches) CentimetresToFeetInches(double centimetres)
{
var feet = centimetres / 2.54 / 12;
var iFeet = (int)feet;
var inches = (feet - iFeet) * 12;
return (iFeet, inches);
}
public static string CentimetresToFeetInchesString(double centimetres, string footSymbol = " foot", string inchesSymbol = " inches")
{
(var feet, var inches) = CentimetresToFeetInches(centimetres);
return $"{feet:N0}{footSymbol}, {inches:N0}{inchesSymbol}";
}
}
Usage:
(var feet, var inches) = Converter.CentimetresToFeetInches(178);
//feet == 5
//inches == 10.078740157480315
var feetInchesString = Converter.CentimetresToFeetInchesString(178);
//5 foot, 10 inches

Confidence Intervals Using MathNET

I have a IEnumerable<double> data sample. I want to compute the 90% confidence interval for the signal/data. I have MathNET library at my disposal, but I am confused as to how to correctly work with the library. Given my data, the idea is to return two additional data arrays that contain the original signal's confidence intervals
using MathNet.Numerics.Statistics;
using MathNet.Numerics.Distributions;
public static List<double[]> ConfidenceIntervals(IEnumerable<double> sample, double interval)
{
Contract.Requires(interval > 0 && interval < 1.0);
int sampleSize = sample.Count();
double alpha = 1.0 - interval;
double mean = sample.Mean();
double sd = sample.StandardDeviation();
double t, mu;
double[] upper = new double[sampleSize];
double[] lower = new double[sampleSize];
StudentT studentT = new StudentT(mean, alpha, sampleSize - 1);
int index = 0;
foreach (double d in sample)
{
t = studentT.CumulativeDistribution(d);
double tmp = t * (sd / Math.Sqrt(sampleSize));
mu = mean - tmp;
upper[index] = d + mu;
lower[index] = d - mu;
}
return new List<double[]>() { upper, lower };
}
This really is not complex in terms of mathematics, I am just confused as to how to correctly use the functions/methods available to me in the MathNET library.
I'm not entirely sure I understand how the confidence interval of the signal is supposed to be applied to each sample of the signal, but we can compute the confidence interval of the sample set as follows:
public static Tuple<double, double> A(double[] samples, double interval)
{
double theta = (interval + 1.0)/2;
double mean = samples.Mean();
double sd = samples.StandardDeviation();
double T = StudentT.InvCDF(0,1,samples.Length-1,theta);
double t = T * (sd / Math.Sqrt(samples.Length));
return Tuple.Create(mean-t, mean+t);
}
Except that the line where we compute T does not compile because unfortunately there is no StudentT.InvCDF in current Math.NET Numerics yet. But we can still evaluate it numerically as a workaround in the meantime:
var student = new StudentT(0,1,samples.Length-1);
double T = FindRoots.OfFunction(x => student.CumulativeDistribution(x)-theta,-800,800);
For example, with 16 samples and alpha 0.05 we get 2.131 as expected. If there are more than ~60-100 samples, this can also be approximated with the normal distribution:
double T = Nomal.InvCDF(0,1,theta);
So all in all:
public static Tuple<double, double> B(double[] samples, double interval)
{
double theta = (interval + 1.0)/2;
double T = FindRoots.OfFunction(x => StudentT.CDF(0,1,samples.Length-1,x)-theta,-800,800);
double mean = samples.Mean();
double sd = samples.StandardDeviation();
double t = T * (sd / Math.Sqrt(samples.Length));
return Tuple.Create(mean-t, mean+t);
}
This is not the full answer yet as I understand you wanted to somehow apply the confidence interval to each sample, but hopefully it helps on the way to get there.
PS: Using Math.NET Numerics v3.0.0-alpha7
I noticed that you didn't increase the index value in foreach loop. This will make the value at index 0 is replaced by the next calculation (When you try to set upper[index] and lower[index] values).
So I guess this is a reason why you got the incorrect results.
If so, your code should be
using MathNet.Numerics.Statistics;
using MathNet.Numerics.Distributions;
public static List<double[]> ConfidenceIntervals(IEnumerable<double> sample, double interval)
{
Contract.Requires(interval > 0 && interval < 1.0);
int sampleSize = sample.Count();
double alpha = 1.0 - interval;
double mean = sample.Mean();
double sd = sample.StandardDeviation();
double t, mu;
double[] upper = new double[sampleSize];
double[] lower = new double[sampleSize];
StudentT studentT = new StudentT(mean, alpha, sampleSize - 1);
int index = 0;
foreach (double d in sample)
{
t = studentT.CumulativeDistribution(d);
double tmp = t * (sd / Math.Sqrt(sampleSize));
mu = mean - tmp;
upper[index] = d + mu;
lower[index] = d - mu;
index++;
}
return new List<double[]>() { upper, lower };
}

Oscillate or "ping pong" between two values?

I have a path that is evaluate at time 't' and returns an orientation and position based on the path type.
The value for time is affected by the path type:
switch (type)
{
case PathType.Closed:
time = ToolBox.Wrap(time, StartTime, EndTime);
break; // Wrap time around the path time to loop
case PathType.Open:
time = ToolBox.Min(time, EndTime);
break; // Clamp the time value to the max path time range
case PathType.Oscillating:
break;
}
The missing link is oscillating.
My question is what is a good, efficient way for oscillating between two values?
For example (2, 7). If time reaches 7 it reverses and decrements towards to 2 and once it reaches 2 it reverses and increases towards 7.
The algorithm should know whether to increase/decrease the value based on the original value so if the value is 9 it knows the answer is 7 - (Abs(7 - 9). If the value is 14 the value has wrapped around so it will result in an increase of 1.
Higher values will also increase or decrease the value depending on the number of times it wraps around the original range.
I hope that makes sense as I'm finding it difficult to explain.
EDIT:
Doesn't oscillate with floating point values:
for (float i = 0; i < 100; i += 0.1f)
{
Console.WriteLine("{0} {1}", i, Oscillate(2.5f, 7.5f, i));
}
private float Oscillate(float min, float max, float value)
{
float range = max - min;
float multiple = value / range;
bool ascending = multiple % 2 == 0;
float modulus = value % range;
return ascending ? modulus + min : max - modulus;
}
Here is what I came up with:
public static int Oscillate(int input, int min, int max)
{
int range = max - min ;
return min + Math.Abs(((input + range) % (range * 2)) - range);
}
I'm assuming input will be a counter starting at 0.
Ideally, you should be abstracting this functionality into some kind of a class and not be concerned about how the implementation actually works when you're using it. Here's an initial take on what that would look like in C++ (my C# is a little rusty). I think you can work it into C# with only little difficulty.
class oscillator
{
private:
float min;
float max;
static float mod(float num, float div)
{
float ratio = num / div;
return div * (ratio - std::floor(ratio));
}
public:
oscillator(float a, float b)
: min(a < b ? a : b), max(a > b ? a : b) {}
float range() ( return max-min; }
float cycle_length() { return 2*range(); }
float normalize(float val)
{
float state = mod(val-min, cycle_length());
if (state > range())
state = cycle_length()-state;
return state + min;
}
};
This will oscillate your numbers between 2 & 7, in this example, time is an int:
bool isIncreasing = time <= 7;
for (int i = 0; i < 20; i++) //some random loop
{
time = time + (isIncreasing ? 1 : -1);
if (time >= 7 || time <= 2) isIncreasing = !isIncreasing;
}
New answer to account for float values:
// Note: Increase FACTOR depending on how many decimal places of accuracy you need.
private const float FACTOR = 10;
public void Test()
{
for (float i = 0; i < 1000; i += 0.1F)
{
Console.WriteLine("{0} {1}", i, Oscillate(2.5F, 7.5F, i));
}
}
private float Oscillate(float min, float max, float time)
{
return (float)(Oscillate_Aux(Upscale(min), Upscale(max), Upscale(time))) / FACTOR;
}
private int Upscale(float value)
{
return (int)(value * FACTOR);
}
private int Oscillate_Aux(int min, int max, int time)
{
int range = max - min;
int multiple = time / range;
bool ascending = multiple % 2 == 0;
int modulus = time % range;
return ascending ? modulus + min : max - modulus;
}
What you're describing sounds a lot like periodic linear interpolation between two values. Consider using XNA's MathHelper.Lerp function as the basis for your oscillation.
Note that it uses a percentage to control the oscillation as its third parameter. You'll have to figure out how to translate your time t value into a percentile, but you could start with ex. sin(t) to see how things work.
If you're reluctant to import XNA into your project, the core equation is very simple:
value1 + (value2 - value1) * amount
Edit: If your question, at its heart, really is "What is a good, efficient way for oscillating between two values?", then Math.Sin(t) (or Cos) can provide you with regular oscillation between 0 and 1.

Generate a random number in a Gaussian Range?

I want to use a random number generator that creates random numbers in a gaussian range where I can define the median by myself. I already asked a similar question here and now I'm using this code:
class RandomGaussian
{
private static Random random = new Random();
private static bool haveNextNextGaussian;
private static double nextNextGaussian;
public static double gaussianInRange(double from, double mean, double to)
{
if (!(from < mean && mean < to))
throw new ArgumentOutOfRangeException();
int p = Convert.ToInt32(random.NextDouble() * 100);
double retval;
if (p < (mean * Math.Abs(from - to)))
{
double interval1 = (NextGaussian() * (mean - from));
retval = from + (float)(interval1);
}
else
{
double interval2 = (NextGaussian() * (to - mean));
retval = mean + (float)(interval2);
}
while (retval < from || retval > to)
{
if (retval < from)
retval = (from - retval) + from;
if (retval > to)
retval = to - (retval - to);
}
return retval;
}
private static double NextGaussian()
{
if (haveNextNextGaussian)
{
haveNextNextGaussian = false;
return nextNextGaussian;
}
else
{
double v1, v2, s;
do
{
v1 = 2 * random.NextDouble() - 1;
v2 = 2 * random.NextDouble() - 1;
s = v1 * v1 + v2 * v2;
} while (s >= 1 || s == 0);
double multiplier = Math.Sqrt(-2 * Math.Log(s) / s);
nextNextGaussian = v2 * multiplier;
haveNextNextGaussian = true;
return v1 * multiplier;
}
}
}
Then to verify the results I plotted them with gaussianInRange(0, 0.5, 1) for n=100000000
As one can see the median is really at 0.5 but there isn't really a curve visible. So what I'm doing wrong?
EDIT
What i want is something like this where I can set the highest probability by myself by passing a value.
The simplest way to draw normal deviates conditional on them being in a particular range is with rejection sampling:
do {
retval = NextGaussian() * stdev + mean;
} while (retval < from || to < retval);
The same sort of thing is used when you draw coordinates (v1, v2) in a circle in your unconditional normal generator.
Simply folding in values outside the range doesn't produce the same distribution.
Also, if you have a good implementation of the error function and its inverse, you can calculate the values directly using an inverse CDF. The CDF of a normal distribution is
F(retval) = (1 + erf((retval-mean) / (stdev*sqrt(2)))) / 2
The CDF of a censored distribution is
C(retval) = (F(retval) - F(from)) / (F(to) - F(from)), from ≤ x < to
To draw a random number using a CDF, you draw v from a uniform distribution on [0, 1] and solve C(retval) = v. This gives
double v = random.NextDouble();
double t1 = erf((from - mean) / (stdev*sqrt(2)));
t2 = erf((to - mean) / (stdev*sqrt(2)));
double retval = mean + stdev * sqrt(2) * erf_inv(t1*(1-v) + t2*v);
You can precalculate t1 and t2 for specific parameters. The advantage of this approach is that there is no rejection sampling, so you only need a single NextDouble() per draw. If the [from, to] interval is small this will be faster.
However, it sounds like you might want the binomial distribution instead.
I have similar methods in my Graph generator (had to modify it a bit):
Returns a random floating-point number using a generator function with a specific range:
private double NextFunctional(Func<double, double> func, double from, double to, double height, out double x)
{
double halfWidth = (to - from) / 2;
double distance = halfWidth + from;
x = this.rand.NextDouble() * 2 - 1;// -1 .. 1
double y = func(x);
x = halfWidth * x + distance;
y *= height;
return y;
}
Gaussian function:
private double Gauss(double x)
{
// Graph should look better with double-x scale.
x *= 2;
double σ = 1 / Math.Sqrt(2 * Math.PI);
double variance = Math.Pow(σ, 2);
double exp = -0.5 * Math.Pow(x, 2) / variance;
double y = 1 / Math.Sqrt(2 * Math.PI * variance) * Math.Pow(Math.E, exp);
return y;
}
A method that generates a graph using the random numbers:
private void PlotGraph(Graphics g, Pen p, double from, double to, double height)
{
for (int i = 0; i < 1000; i++)
{
double x;
double y = this.NextFunctional(this.Gauss, from, to, height, out x);
this.DrawPoint(g, p, x, y);
}
}
I would rather used a cosine function - it is much faster and pretty close to the gaussian function for your needs:
double x;
double y = this.NextFunctional(a => Math.Cos(a * Math.PI), from, to, height, out x);
The out double x parameter in the NextFunctional() method is there so you can easily test it on your graphs (I use an iterator in my method).

Categories