here is my formula:
y = b*exp(-((x-c)^2)/2(d^2)) if x < c, else y = b*exp(-(x-c)^2/2g^2);
this is how i coded it:
for (double x = 0; x <= 7D; x += .01D)
{
b = 6.0410638; c = 2.1344769; d = 0.59183047; g = 0.77384504;
if (x < c)
y = b * Math.Exp(-Math.Pow((x - c), 2)) / (2 * Math.Pow(d, 2D));
else
y = b * Math.Exp(-Math.Pow((x - c), 2)) / (2 * Math.Pow(g, 2D));
qResults.Rows.Add(x, y);
}
the output:
0.0529826172
0.05528786
0.05768187
0.0601675063
0.0627477
0.06542546
0.06820385
0.07108601
0.074075155
0.0771745443
0.08038754
0.08371756
0.08716809
0.0907426849
0.0944449753
0.0982786641
0.102247514
0.106355369
0.110606134
0.115003787
0.119552381
0.124256022
0.1291189
0.13414526
0.139339417
0.144705743
0.150248691
0.155972764
0.16188252
0.167982608
0.1742777
0.180772528
0.187471911
0.1943807
0.201503783
0.2088461
0.2164127
0.224208578
0.232238829
0.2405086
0.24902302
0.257787317
0.2668067
is there a problem with my syntax?
the output should be:
0.009332048
0.009915393
0.010532198
0.011184179
0.011873133
0.012600931
0.013369526
0.014180954
0.015037339
0.015940891
0.016893914
0.017898806
0.01895806
0.020074273
0.021250142
0.022488471
0.023792173
0.025164271
0.026607905
0.028126332
0.029722928
0.031401194
0.033164757
0.035017372
0.036962928
0.039005447
0.041149089
0.043398156
0.045757092
0.048230485
0.050823073
0.053539744
0.05638554
0.059365657
0.062485449
0.065750429
0.069166271
0.072738815
0.076474061
0.08037818
0.084457508
0.088718551
0.093167983
0.097812651
0.102659571
0.107715931
0.112989091
0.118486582
0.124216105
0.130185532
0.136402905
0.142876432
0.149614489
0.156625615
0.163918513
0.171502045
0.17938523
0.187577239
0.196087395
0.204925165
0.21410016
0.223622125
0.233500937
0.2437466
0.254369235
0.265379079
0.276786473
0.288601856
0.30083576
0.313498797
0.326601652
0.340155077
0.354169874
0.368656891
0.383627009
0.39909113
0.415060167
0.431545027
0.448556606
0.466105768
0.484203337
0.502860078
0.522086688
0.541893773
0.562291841
0.583291279
0.604902341
0.627135126
0.649999569
0.673505413
0.697662199
0.722479244
0.747965622
0.774130146
0.800981347
0.828527458
0.856776387
0.885735705
0.915412619
0.945813957
0.976946142
1.008815173
1.041426608
1.074785537
1.108896564
1.143763787
1.179390775
1.21578055
Based on your formula, the code should be:
for (double x = 0; x <= 7D; x += .01D)
{
b = 6.0410638; c = 2.1344769; d = 0.59183047; g = 0.77384504;
if (x < c)
y = b * Math.Exp(-Math.Pow(x - c, 2) / (2 * Math.Pow(d, 2D)));
else
y = b * Math.Exp(-Math.Pow(x - c, 2) / (2 * Math.Pow(g, 2D)));
qResults.Rows.Add(x, y);
}
Basically, the Math.Exp function should be applied to the result of the division, not just to the result of -Math.Pow(x - c, 2)
Also, it's not very clear based on the formula and your code example whether you need to divide by 2 in the exponent computation, then multiply the result by d^2, or actually divide by 2 * d^2 as you are doing in the implementation.
Related
I'm looking for a high precision solution to find the center point of a circle from 3 data points on a canvas (x,y). I found this example in the attached screenshot above, now I'm using the Math.NET package to solve the equation and I'm comparing the results against this online tool: https://planetcalc.com/8116/.
However, when I calculate the radius its completely off and often a negative number???
using MathNet.Numerics.LinearAlgebra.Double.Solvers;
using MathNet.Numerics.LinearAlgebra.Double;
using System;
namespace ConsoleAppTestBed
{
class Program
{
static void Main(string[] args)
{
var dataPoints = new double[,]
{
{ 5, 80 },
{ 20, 100 },
{ 40, 140 }
};
var fitter = new CircleFitter();
var result = fitter.Fit(dataPoints);
var x = -result[0];
var y = -result[1];
var c = result[2];
Console.WriteLine("Center Point:");
Console.WriteLine(x);
Console.WriteLine(y);
Console.WriteLine(c);
//// (x^2 + y^2 - c^2)
var radius = Math.Pow(x, 2) + Math.Pow(y, 2) - Math.Pow(c, 2);
//// sqrt((x^2 + y^2 - c^2))
radius = Math.Sqrt(radius);
Console.WriteLine("Radius:");
Console.WriteLine(radius);
Console.ReadLine();
}
public class CircleFitter
{
public double[] Fit(double[,] v)
{
var xy1 = new double[] { v[0,0], v[0,1] };
var xy2= new double[] { v[1, 0], v[1, 1] };
var xy3 = new double[] { v[2, 0], v[2, 1] };
// Create Left Side Matrix of Equation
var a = CreateLeftSide_(xy1);
var b = CreateLeftSide_(xy2);
var c = CreateLeftSide_(xy3);
var matrixA = DenseMatrix.OfArray(new[,]
{
{ a[0], a[1], a[2] },
{ b[0], b[1], b[2] },
{ c[0], c[1], c[2] }
});
// Create Right Side Vector of Equation
var d = CreateRightSide_(xy1);
var e = CreateRightSide_(xy2);
var f = CreateRightSide_(xy3);
double[] vector = { d, e, f };
var vectorB = Vector<double>.Build.Dense(vector);
// Solve Equation
var r = matrixA.Solve(vectorB);
var result = r.ToArray();
return result;
}
//2x, 2y, 1
public double[] CreateLeftSide_(double[] d)
{
return new double[] { (2 * d[0]), (2 * d[1]) , 1};
}
// -(x^2 + y^2)
public double CreateRightSide_(double[] d)
{
return -(Math.Pow(d[0], 2) + Math.Pow(d[1], 2));
}
}
}
}
Any ideas?
Thanks in advance.
The solution to your problem is here: The NumberDecimalDigits property
Code:
using System;
using System.Globalization;
namespace ConsoleApp1
{
class Program
{
static void Main()
{
double x1 = 1, y1 = 1;
double x2 = 2, y2 = 4;
double x3 = 5, y3 = -3;
findCircle(x1, y1, x2, y2, x3, y3);
Console.ReadKey();
}
static void findCircle(double x1, double y1,
double x2, double y2,
double x3, double y3)
{
NumberFormatInfo setPrecision = new NumberFormatInfo();
setPrecision.NumberDecimalDigits = 3; // 3 digits after the double point
double x12 = x1 - x2;
double x13 = x1 - x3;
double y12 = y1 - y2;
double y13 = y1 - y3;
double y31 = y3 - y1;
double y21 = y2 - y1;
double x31 = x3 - x1;
double x21 = x2 - x1;
double sx13 = (double)(Math.Pow(x1, 2) -
Math.Pow(x3, 2));
double sy13 = (double)(Math.Pow(y1, 2) -
Math.Pow(y3, 2));
double sx21 = (double)(Math.Pow(x2, 2) -
Math.Pow(x1, 2));
double sy21 = (double)(Math.Pow(y2, 2) -
Math.Pow(y1, 2));
double f = ((sx13) * (x12)
+ (sy13) * (x12)
+ (sx21) * (x13)
+ (sy21) * (x13))
/ (2 * ((y31) * (x12) - (y21) * (x13)));
double g = ((sx13) * (y12)
+ (sy13) * (y12)
+ (sx21) * (y13)
+ (sy21) * (y13))
/ (2 * ((x31) * (y12) - (x21) * (y13)));
double c = -(double)Math.Pow(x1, 2) - (double)Math.Pow(y1, 2) -
2 * g * x1 - 2 * f * y1;
double h = -g;
double k = -f;
double sqr_of_r = h * h + k * k - c;
// r is the radius
double r = Math.Round(Math.Sqrt(sqr_of_r), 5);
Console.WriteLine("Center of a circle: x = " + h.ToString("N", setPrecision) +
", y = " + k.ToString("N", setPrecision));
Console.WriteLine("Radius: " + r.ToString("N", setPrecision));
}
}
}
I have just converted William Li's answer to Swift 5 for
those who like to cmd+C and cmd+V like me :)
func calculateCircle(){
let x1:Float = 0
let y1:Float = 0
let x2:Float = 0.5
let y2:Float = 0.5
let x3:Float = 1
let y3:Float = 0
let x12 = x1 - x2
let x13 = x1 - x3
let y12 = y1 - y2
let y13 = y1 - y3
let y31 = y3 - y1
let y21 = y2 - y1
let x31 = x3 - x1
let x21 = x2 - x1
let sx13 = pow(x1, 2) - pow(x3, 2)
let sy13 = pow(y1, 2) - pow(y3, 2)
let sx21 = pow(x2, 2) - pow(x1, 2)
let sy21 = pow(y2, 2) - pow(y1, 2)
let f = ((sx13) * (x12)
+ (sy13) * (x12)
+ (sx21) * (x13)
+ (sy21) * (x13))
/ (2 * ((y31) * (x12) - (y21) * (x13)))
let g = ((sx13) * (y12)
+ (sy13) * (y12)
+ (sx21) * (y13)
+ (sy21) * (y13))
/ (2 * ((x31) * (y12) - (x21) * (y13)))
let c = -pow(x1, 2) - pow(y1, 2) - 2 * g * x1 - 2 * f * y1
let h = -g
let k = -f
let r = sqrt(h * h + k * k - c)
print("center x = \(h)")
print("center y = \(k)")
print("r = \(r)")
}
Updated Answer
The equation for radius is incorrect; it should be (not c squared):
which is why you get incorrect values for the radius.
The original answer was incorrect, but it is still 'interesting'.
(Incorrect) Original Answer
The cause of the problematic calculation is not solely due to the precision of the numbers, but more because problem is ill-conditioned. If you look at the three points and where they are located on the circle, you'll see that they are bunched on a small segment of the circumference. When the points are so close to each other, it is a tough ask to find the circle's centre and radius accurately.
So the intermediate calculations, which will have small rounding errors, result in hugely exaggerated errors.
You can see the ill-conditioned nature of the problem by adding the ConditionNumber() method.
// Solve Equation
Console.WriteLine(matrixA.ConditionNumber()); // <<< Returns 5800 -> Big!
var r = matrixA.Solve(vectorB); // Existing code
A large result indicates an ill-conditioned problem. In this case a value of 5800 is returned, which is large. You might get better results using Gaussian Elimination with partial pivoting, but it still does not address the fact that the basic problem is ill-conditioned, which is why you get wildly incorrect answers.
I have a math equation and I want use it in my program
but I got an error. The result from this equation is non number ..
the math equation i:
note: n is the number in the textbox
((298/2)^2*ACOS(((298/2)-n)/(298/2))-((298/2)-n)*((2*(298/2)*n-n^2))^(0.5))*1213/1000
in button code
double a = Math.Pow((298.00 / 2), 2);
double b = (Math.Acos(((298.00 / 2) - Convert.ToDouble(textBox1.Text)) / (298.00 / 2)));
double c = ((298.00 / 2) - Convert.ToDouble(textBox1.Text));
double d = (2 * (298.00 / 2) * Convert.ToDouble(textBox1.Text));
double f = Math.Pow(Convert.ToDouble(textBox1.Text), 2);
double r = ((a * b) - (c * d) )- f;
double result = Math.Pow(r, (0.5));
double h = result * 1213.00 / 1000;
textBox1.Text = Convert.ToString(h );
}
If anyone knows what is wrong here, tell me please.
The error is in variable r because the result from r is less that 0!
Lets rewrite given math expression in more convenient way:
( (298/2)^2 * ACOS(((298/2)-n)/(298/2)) - ((298/2)-n) * ( (2*(298/2)*n - n^2 ) ) ^ (0.5) ) * 1213/1000
--------- ------------------------- ----------- ------------ ---
a b c d f
--------------------------------
r = (d - f) ^ 0.5
------------------------------------------------------------------------------------------------------
(a * b - c * r) * 1213/1000
Now it is easier to see that you have an error in formula:
double r = ((a * b) - (c * d) )- f;
r must be calculated using the next formula:
double r = Math.Sqrt(d - f); // It is better to use Math.Sqrt(x) instead of Math.Pow(x, 0.5).
Now knowing where the error is we can fix it:
double n = Convert.ToDouble(textBox1.Text);
double a = Math.Pow(298.00 / 2, 2);
double b = Math.Acos( (298.00 / 2 - n) / (298.00 / 2) );
double c = 298.00 / 2 - n;
double d = 2 * 298.00 / 2 * n;
double f = Math.Pow(n, 2);
double r = Math.Sqrt(d - f);
double result = a * b - c * r;
double h = result * 1213.00 / 1000;
textBox1.Text = Convert.ToString(h);
But for values of n > 298 you will still get r = NaN because for such values of n expression d - f is negative.
private static string GetMinX(int a, int b, int c)
{
double x1 = 0;
double x2 = 0;
double x3 = 0;
if (b * b - 4 * a * c > 0)
{
x1 = (-b - Math.Sqrt(b * b - 4 * a * c)) / 2 * a;
x2 = (-b + Math.Sqrt(b * b - 4 * a * c)) / 2 * a;
if (x2 > x1)
return x1.ToString();
else
return x2.ToString();
}
if (b * b - (4 * a * c) == 0)
{
x3 = -b / 2 * a;
return x3.ToString();
}
if (b * b - 4 * a * c < 0)
return "IMP";
}
So every condition returns value (d > 0, == 0, < 0). Why does it write not all code paths return a value?
Because the last condition if (b * b - 4 * a * c < 0) has no else case and there is no return statement following it.
This condition might always true because of your logic, but C# doesn't know that. C# just assumes that any condition can be true or false (except when the condition is a constant expression).
You have two cases:
Either this condition is supposed to be always true: then just drop the condition and always return "IMP". This is the case here.
This condition might be false sometimes: then add another return statement at the end.
private static string GetMinX(int a, int b, int c)
{
int discriminant = b * b - 4 * a * c;
if (discriminant > 0) {
double root = Math.Sqrt(discriminant);
double x1 = (-b - root) / (2 * a); // Put brackets around the divisor!
double x2 = (-b + root) / (2 * a); // Put brackets around the divisor!
if (x1 < x2)
return x1.ToString();
else
return x2.ToString();
}
if (discriminant == 0) {
double x = -b / (2 * a); // Put brackets around the divisor!
return x.ToString();
}
return "IMP";
}
It is also good to do the same calculation only once and to store the result in a variable.
There is a subtle error in ... / 2 * a. It should be ... / (2 * a), otherwise you divide by 2 and then multiply by a. But you want to divide by 2 * a.
There is no point in assigning 0 to x1, x2 and x3. These values will never be used. Better declare the variables where they are used (in the local code block) and initialize them directly with the right value. Their scope will be limited to this code block. This means that for instance x1 does not exist after the first if-statement and will therefore never have an undetermined value.
"if x1 is less than x2" sounds more natural than "if x2 is greater than x1", since you want to know which one the smallest is. But both variants will work.
I advise you to use if/else if/else statement, it should be more efficient. Also you can use Math.Min and discard x3.
private static string GetMinX(int a, int b, int c)
{
double x1, x2, m;
m = b * b - 4 * a * c;
if (m > 0)
{
x1 = (-b - Math.Sqrt(b * b - 4 * a * c)) / 2 * a;
x2 = (-b + Math.Sqrt(b * b - 4 * a * c)) / 2 * a;
return Math.Min(x1, x2).ToString();
}
else if (m == 0)
{
x1 = -b / 2 * a;
return x3.ToString();
}
else
return "IMP";
}
You can also use only one condition by combining the first two cases:
private static string GetMinX(int a, int b, int c)
{
double x1, x2, m;
m = b * b - 4 * a * c;
if (m >= 0)
{
x1 = (-b - Math.Sqrt(b * b - 4 * a * c)) / 2 * a;
x2 = (-b + Math.Sqrt(b * b - 4 * a * c)) / 2 * a;
return Math.Min(x1, x2).ToString();
}
else
return "IMP";
}
I'm trying to find solutions to a simple MDAS (i.e. Multiplication, Division...) problem using C#, and while it mostly gets correct solutions, I have problems when the variables add up to x.99999... so I get wrong answers because it doesn't compute to 1.
For example, if I have:
decimal a = 1M;
decimal b = 2M;
decimal c = 6M;
decimal d = 4M;
decimal e = 7M;
decimal f = 8M;
decimal g = 3M;
decimal h = 5M;
decimal i = 9M;
Console.WriteLine(a + 13 * b / c + d + 12 * e - f - 11);
Console.WriteLine(g * h / i);
Console.WriteLine(a + 13 * b / c + d + 12 * e - f - 11 + g * h / i);
Which gives me:
74.33333333333333333333333333
1.6666666666666666666666666667
75.999999999999999999999999997
But I want:
74.33333333333333333333333333
1.6666666666666666666666666667
76
Is there a way that I can always get a precise answer to .(6)+.(3) = 1 without needing to check and modify the values? If not what is the best way to go about it?
The following will round your double value to within a precision of 0.1:
// parameters
double d = -7.9;
double precision = 0.1;
//the conversion
double v = (Math.Abs(Math.Round(d)-d)) < precision ? Math.Round(d) : d;
//output
int i = (int) v;
Console.WriteLine(i);
I went with #tia and Dai's suggestion to use a Rational data type. I got tompazourek's Rationals NuGet package and used it like this:
Rational a = 1;
Rational b = 2;
Rational c = 6;
Rational d = 4;
Rational e = 7;
Rational f = 8;
Rational g = 3;
Rational h = 5;
Rational i = 9;
Console.WriteLine(a + (Rational)13 * b / c + d + (Rational)12 * e - f - (Rational)11);
Console.WriteLine(g * h / i);
Rational toTest = a + (Rational)13 * b / c + d + (Rational)12 * e - f - (Rational)11 + g * h / i;
Console.WriteLine(toTest);
Console.WriteLine(toTest.Equals(76));
Which gives me:
446/6
15/9
4104/54
True
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).