Double precision problems when zooming in - c#

I have this algorithm that calcuates the mandelbrot value of a point (x0,y0) (x0 and y0 are somewhere between -1 and 1 i thought, not very important). This is all going very well when scale isn't getting too big, but at higher values of scale, the values returned are very inaccurate and my graphic output starts to go freaky. How do i predict from what value of scale this occurs?
public static byte CalculateMandelbrot(double x0, double y0,double scale)
{
x0 /= scale;
y0 /= scale;
double y = 0;
double x = 0;
byte i = 0;
while (x * x + y * y < 4)
{
double tx = x;
x = x * x - y * y + x0;
y = 2 * tx * y + y0;
i++;
if (i == 0xFF) break;
}
return i;
}

A double has 53 bits of precision. This amounts to about 16 decimal places.
If you zoom in on your fractal 10^13 times, and make picture of 1000x1000 pixels, the precision is about the same as the screen resolution: the minimal change possible in a double is a step of one pixel on the screen.
But you will get into trouble before that, because you iterate the mandelbrot formula a hundred times iteratively on the same number. Each calculation adds a roundoff error (multiple ones, probably) of about 1/10^16. It is possible (although tedious) to predict when this gets noticable.
The FPU internally has a higher number of bits than standard double, this will reduce the abovementioned effect.

This is the classic "decimal vs double" pitfall.
Try using 'decimal' for all vars and see if it clicks.
From the C# Reference page:
Compared to floating-point types, the decimal type has a greater
precision and a smaller range
There are also arbitrary precision implementations like BigFloat Class.

Related

Regarding Binary to Float Conversion in c# program

float resultInteger = 0.0f;
float power = 1/2.0f;
for (i = highPointPosition+1; i <= highResultIndex; i++, power /= 2
resultInteger += result[i] * power;
power = 1.0f;
for (i = highPointPosition, power = 1.0f; i >= 0; i--, power *= 2)
resultInteger += result[i] * power;
if (carry == 1)
resultInteger += carry * power;
The above code converts binary to floating point number.
I have been given an assignment asking me to convert two floating point numbers to binary and then adding them and then converting the result to float.
In the above code when I perform 3.5 + 5.39 the result should be 8.89, but instead it is 8.889999.
For others like 9.5 + 7.39 the answer is right i.e., 16.89.
Can Anyone help explain why I am encountering such problem?
Binary can't expression 1/10 in decimal accurately, like how base 10 can't expression 1/3 accurately, while base 12 can (1 third is 0.4 in base 12).
Normally, if you want to get better math accuracy, you would use decimal to do the math instead, like this:
decimal x = 2.5M;
decimal y = 1.19M;
Console.WriteLine(x + y);
decimal works because it calculates in base ten, not binary. However, if your professor is asking you to do convert into binary to do the math, then it doesn't matter what the initial type was. It will never be possible to get the correct result with binary.
It happens for the reason that 1/10 can't be expressed accurately in binary system.
You can try the following:
float a = 3.5f;
float b = 5.39f;
Console.WriteLine(Math.Round(a + b, 2));
Console.ReadLine();
Use Math.Round(value, digits), you can get the result you want.

C# MathNet FFT Definition

I have some problem when testing FFT from MathNet:
The idea is that if I apply FFT to the characteristic function of a gaussian variable I should find the gaussian density function.
When I plot VectorFFT the figure does seems a density function but in zero it does not have value 1, it has value 1.4689690914109.
There must be some problems with the scaling. I tried out all type of FourierOptions in Fourier.Inverse and all type of divisions/multiplications for PI, 2PI, sqrt(2PI) but nothing gives me the value 1 at the center of the density function.
Also, since various definitions of Fourier Transform and its inverse exists, I was wondering which one is implemented by MathNet, I could not find it in the documentation.
Any ideas?
public void DensityGaussian()
{
double eta = 0.1; //step in discrete integral
int pow2 = 256; // N^2
double mu = 0; // centred gaussian
double sigma = 1; // with unitary variance
//FFT
double lambda = 2 * System.Math.PI / (pow2 * eta);
double b = 0.5 * pow2 * lambda;
Complex[] VectorToFFT = new Complex[pow2];
for (int j = 0; j < pow2; j++)
{
double z = eta * j;
if (z == 0) { z = 0.00000000000001; }
VectorToFFT[j] = System.Numerics.Complex.Exp(new Complex(0, b * z));
VectorToFFT[j] *= (System.Numerics.Complex.Exp(new Complex(
-sigma*sigma*z*z, mu * z))); //char function of gaussian
}
Fourier.Inverse(VectorToFFT, FourierOptions.NoScaling);
//scaling
for (int i = 0; i < pow2; i++)
{
VectorToFFT[i] /= (2 * System.Math.PI); //test
}
Console.WriteLine("Is density?");
Assert.IsTrue(1 == 1);
}
Math.NET Numerics supports all common DFT definitions, controllable with the FourierOptions flags enum. They essentially vary on the exponent and on the scaling.
The FourierOptions docs give some hints on how the options affect the effective definition, essentially:
InverseExponent: use a negative sign in the exponent (default uses a positive sign). A prominent implementation with a negative sign is numerical recipes.
AsymmetricScaling/NoScaling: instead of the default symmetric scaling sqrt(1/N) either only scale in the inverse transformation 1/N (like Matlab) or no scaling at all (like numerical recipes). Obviously, without scaling ifft(fft(x)) != x.
Maybe the answer in Calculating a density from the characteristic function using fft in R can help on the specific use case.

Why result of % operator for double differ from decimal? [duplicate]

Consider this:
double x,y;
x =120.0;
y = 0.05;
double z= x % y;
I tried this and expected the result to be 0, but it came out 0.04933333.
However,
x =120.0;
y = 0.5;
double z= x % y;
did indeed gave the correct result of 0.
What is happening here?
I tried Math.IEEERemainder(double, double) but it's not returning 0 either. What is going on here?
Also, as an aside, what is the most appropriate way to find remainder in C#?
Because of its storage format, doubles cannot store every values exactly as is is entered or displayed. The human representation of numbers is usually in decimal format, while doubles are based on the dual system.
In a double, 120 is stored precisely because it's an integer value. But 0.05 is not. The double is approximated to the closest number to 0.05 it can represent. 0.5 is a power of 2 (1/2), so it can be stored precisely and you don't get a rounding error.
To have all numbers exactly the same way you enter / display it in the decimal system, use decimal instead.
decimal x, y;
x = 120.0M;
y = 0.05M;
decimal z = x % y; // z is 0
You could do something like:
double a, b, r;
a = 120;
b = .05;
r = a - Math.floor(a / b) * b;
This should help ;)
I believe if you tried the same with decimal it would work properly.
http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems can help you understand why you get these "strange" results. There's a particular precision that floating point numbers can have. Just try these queries and have a look at the results:
0.5 in base 2
0.05 in base 2
Modulus should only be used with integer. The remainder come from an euclidean division. With double, you can have unexpected results.
See this article
This is what we use.. :)
public double ModuloOf(double v1, double v2)
{
var mult = 0;
//find number of decimals
while (v2 % 1 > 0)
{
mult++;
v2 = v2 * 10;
}
v1 = v1 * Math.Pow(10, mult);
var rem = v1 % v2;
return rem / Math.Pow(10, mult);
}

How to deal with precision in C#

Bizarre precision behavior in finding the number of integral points between two points exclusive:
I was writing an algorithm for this which went like this (pseudo).
Given x1,y1 and x2, y2
I calculated double m where m is the gradient of the line segment given as (double)(y2-y1)/(x2-x1)
then I calculated double c where c is the y intercept given as y1 - (m*x1)
then
for i = Min(x1,x2) i < Max(x1,x2) for j = Min(y1, y2) j < Max(y1,y2) if j = (m*i) + c then ++
finally, return the result -1
The code works for some test cases but fails on others for instance when the two endpoints are perpendicular to each other I had to deal with infinity for m, and NaN cases for c. But, one particular case caught my eye, Test case 43,38,17,6 for x1,y1 and x2, y2 respectively.
running the code j starts at 6 and i at 17 so this point is definitely on the line segment even though I shouldn't be counting it because it is an end-point. What's bizarre is for this value i, j != (m*i)+c = 5.9999999999... instead of 6. how is that possible? where am I losing precision for this? More importantly how i'm I losing precision?
code:
int cnt = 0;
double i, j;
double m = (double)(y2 - y1) / (x2 - x1);
double c = y1 - (m * x1);
for (i = Math.Min(x1, x2); i <= Math.Max(x1, x2); i++)
{
for (j = Math.Min(y1, y2); j <= Math.Max(y1, y2); j++)
{
if (j == (m * i) + c||double.IsInfinity(m) && double.IsNaN(c))
cnt++;
}
}
return cnt - 2;
So I changed all my variables to decimal but unfortunately, I still get failed test cases. But I think i've narrowed it down to this point here :decimal m = (decimal)(y2 - y1) / (x2 - x1);
m and c are doubles, so (m*i)+c is going to return a double. j however, is an int. So you're comparing an integer to a double. Given floating point representation, this is going to be an issue SOMEWHERE when doing direct comparisons. You need to either cast the right-hand side of that comparison as an integer, or do some sort of non-exact comparison. Alternatively you could use something that is not floating point precision, like decimal, which won't show this issue.
Doubles cannot be precise. They are only precise up to a certain number of digits. Remember they use an internal format to be stored in bytes. This will inevitable cause some precision error.
And even worse, some values you put into a double are unable to be precisely stored, even with no calculation made.
Example to make you aware:
Assigning 1.94 to a double variable can be tested here and will result in:
1.939999999999999946709294817992486059665679931640625!
Its bad practice and doomed to fail to compare two floating point numbers with equality operator.
Important read about floating point numbers:
What Every Computer Scientist Should Know About Floating-Point Arithmetic
Squeezing infinitely many real numbers into a finite number of bits
requires an approximate representation. Although there are infinitely
many integers, in most programs the result of integer computations can
be stored in 32 bits. In contrast, given any fixed number of bits,
most calculations with real numbers will produce quantities that
cannot be exactly represented using that many bits. Therefore the
result of a floating-point calculation must often be rounded in order
to fit back into its finite representation. This rounding error is the
characteristic feature of floating-point computation.
As solution if you really want to compare you can sensitively round the results with Math.round(x, decimals) before comparing them.

Randomly pick two numbers in a range so that the sum of their squares is constant

I'm currently developing a 2-player Ping-Pong game (in 2D - real simple) from scratch, and it's going good. However Theres a problem I just can't seem to solve - I'm not sure if this should be located here or on MathExchange - anyway here goes.
Initially the ball should be located in the center of the canvas. When pressing a button the ball should be fired off in a completely random direction - but always with the same velocity.
The Ball object has (simplified) 4 fields - The position in X and Y, and the velocity in X and Y. This makes it simple to bounce the ball off the walls when it hits, simple by inverting the velocities.
public void Move()
{
if (X - Radius < 0 || X + Radius > GameWidth)
{
XVelocity = -XVelocity;
}
if (Y - Radius < 0 || Y + Radius > GameHeight)
{
YVelocity = -YVelocity;
}
X+= XVelocity;
Y+= YVelocity;
}
I figured the velocity should be the same in each game, so I figures I would use Pythagoras - the square of the two velocities should always be the same.
SO for the question:
Is there a way to randomly select two numbers (doubles) such that the sum of their squares is always a specific number - more formally:
double x = RandomDouble();
double y = RandomDouble();
if (x^2 + y^2 = 16) {/* should always be true */ }
Any help appreciated :)
Randomly pick an angle theta and multiply that by the magnitude of the distance d you want. Something like:
double theta = rand.NextDouble() * 2.0 * Math.PI;
double x = d * Math.Cos(theta);
double y = d * Math.Sin(theta);
If the constant is C, pick a number x between 0 and sqrt(C).
Solve for the other number y using simple algebra.
why not try this:
double x = RandomDouble();
double y = square(16-x^2);
as your application allow double type.
does this solve your problem?
if not, please let me know

Categories