Hello.
I'm new to ServUO and i don't have much experience with C# (a little with c, much more with python).
I'm trying to implement an error function and a gaussian function to make a more realistic skill system. I first made it on python just to check that the numbers were right (correct normalization etc.) and then i "translated" it on c#.

Boring part:
The function i tested on python has a spectrum that you can see on the attached file (nevermind the x100 on the x axis, it was there just for readability reasons), and is just an algorithm for calculating an approximation of the CDF of a gaussian, the idea was then to use it to determine the success chance.

THE question:
I implemented it with these functions

Code:
	public static double Factorial(int n)
    	{
        	int result = 1;

        	for (int i = 1; i <= n; i++)
        	{
            	result *= i;
        	}
        	return result;
    	}

	public static double erf(double x)
	{
		double a = 0;
		int i=0;
		while (i<100)
		{
			a+=(2/Math.Sqrt(Math.PI))*(Math.Pow(-1,i)*Math.Pow(x,(2*i+1)))/(Factorial(i)*(2*i+1));
			i+=1;
		}
		return(a);
	}

	public static double Cumulative(double x, double s)
	{
		double cum=0;
		cum=0.5*(1+erf(x/(s*Math.Sqrt(2))));
		return (cum);
	}

But wheneve i call Cumulative(a,b) with a=[0,1] and b=0.1,0.2 it returns NaN
Is there something that is strictrly c# related that i'm missing here?

Thanks for your attention.
 

Attachments

  • figure_1-9.png
    figure_1-9.png
    15 KB · Views: 4
Last edited:
A double or float can return Not A Number in such cases where the function evaluates to infinity, or if 0.0 is divided by 0.0.

Have you done any unit tests with the functions?

You could plug and run your function into rextester.com and evaluate different inputs in real-time that way.

When you post code, use [code] tags :)
 
A double or float can return Not A Number in such cases where the function evaluates to infinity, or if 0.0 is divided by 0.0.

Have you done any unit tests with the functions?
Does that mean try to isolate some specific function and avoid calling them all at once?
No, i tested everything in python because it's a more friendly environment to me. It would be a good idea to test it directly on ServUO but it takes a lot to compile and run, so i was trying to avoid it.

You could plug and run your function into rextester.com and evaluate different inputs in real-time that way.
That's interesting, i'll try it out

When you post code, use [code] tags :)
Sorry, fixed.

Thanks for your help, i'll let you know if something changes
[doublepost=1531856677][/doublepost]There seems to be a problem with the factorial number calculation.
That's weird because it should be well in the range of a double number. In python for the first 100 run of the equivalent of
Code:
(Factorial(i)*(2*i+1))
i get all positive numbers up to
"185719168733448863836581485323970733976524776846119426722499998151483023986527532061793513312551471389644858862446175278919858569724559360000000000000000000000"
in rexter things start to get weird around the 15th run, specifically i get this sequence:
1
3
10
42
216
1320
9360
75600
685440
6894720
76204800
918086400
11975040000
52165444608
37089413120
62133610496
66138243072
-10098278400
-33242021888
4276027392
-86187442176
-51389923328
-23522181120
40535326720
-38021365760
105885204480
-98255765504
81663098880
-78416707584
-73249325056
If i push more iterations it easily becomes zero. The thing is that i need more iterations because the damn thing does not even look like an erf with less than 50.

[edit]: things get weird long before the 15h iteration. This is what i get from 15 iterations on python
1

3

10

42

216

1320

9360

75600

685440

6894720

76204800

918086400

11975040000

168129561600

2528170444800
 
Last edited:
But wheneve i call Cumulative(a,b) with a=[0,1] and b=0.1,0.2 it returns NaN
Is there something that is strictrly c# related that i'm missing here?

Cumulative(0, 1) will return NaN because
Code:
cum=0.5*(1+erf(x/(s*Math.Sqrt(2))));

The first operation involves x (a) = 0, dividing 0 by anything is NaN, therefore every operation after will be NaN.
 
Cumulative(0, 1) will return NaN because
Code:
cum=0.5*(1+erf(x/(s*Math.Sqrt(2))));

The first operation involves x (a) = 0, dividing 0 by anything is NaN, therefore every operation after will be NaN.
Thanks for your help.
You are right, i should have probably written it as a=]0,1[ or whatever it was the way to say 0,1 excluded, in fact when a is <0 or >1 the function is not even called becase it is assumed to be automatic failure/success.
 
I cleaned up the syntax a bit and improved performance by caching the common constants.
Operations using 0 will no longer cause NaN values. Hope this helps, good luck!

Code:
	public static class ERF
	{
		private static readonly double _Sq2 = Math.Sqrt(2);
		private static readonly double _2DSqPI = 2 / Math.Sqrt(Math.PI);

		public static double Factorial(int n)
		{
			if (n == 0)
				return 1;

			var result = 1;
			var index = 1;

			while (--n >= 0)
				result *= ++index;

			return result;
		}

		public static double Compute(double n)
		{
			if (n == 0)
				return 0;

			var result = 0.0;
			var index = 0;

			while (index++ < 100)
				result += _2DSqPI * (Math.Pow(-1, index - 1) * Math.Pow(n, 2 * index)) / (Factorial(index - 1) * (2 * index));

			return result;
		}

		public static double Cumulative(double a, double b)
		{
			if (a == 0 || b == 0)
				return 0;

			return 0.5 * (1 + Compute(a / (b * _Sq2)));
		}
	}
 
Ok the problem was with the declaration of the variable "result" in the factorial function: declaring it as an int caused an overflow that made those crazy negative numbers appear.
Changing it to double made it work.
Thanks Voxpire for cleaning the syntax, it sure made it more readable and easy to debug!
 
Last edited:
Back