Arithmetic in complex numbers isn't working properly - c

The context is simply a function that solves input quadratic equations. Here's the section of the code which malfunctions:
case NEGATIVE:
printf("\n\n beforehand sqrt(discriminant) is %f%+fi",creal(csqrt(eqn->discriminant)), cimag(csqrt(eqn->discriminant)));
eqn->complex_root = (-(eqn->b)+csqrt(eqn->discriminant))/(2*eqn->a);
printf("\n\n result after full formula is %f%+fi", creal(eqn->complex_root),cimag(eqn->complex_root));
break;
And the output text I get with x^2+5 = 0 as the trial equation. The middle three lines are debugging text, where type simply refers to what kind of solutions the program should expect for the quadratic (0 means 2 complex solutions of course):
Please enter the coefficients of the quadratic separated by spaces: 1 0 5
The coefficients entered are a=1, b=0 and c=5.
TYPE RETURNED: 0
beforehand sqrt(discriminant) is 0.000000+4.472136i
result after full formula is 0.000000+0.000000i
The equation defined by 1x^2 +0x +5=0 has two complex solutions, x = 0+0i and x = 0-0i.
I simply have no idea why the results reduce to 0. What's going on?

Forgot to assign the variable holding these values as complex. i.e. used float instead of float _Complex.

Related

Does the array “sum and/or sub” to `x`?

Goal
I would like to write an algorithm (in C) which returns TRUE or FALSE (1 or 0) depending whether the array A given in input can “sum and/or sub” to x (see below for clarification). Note that all values of A are integers bounded between [1,x-1] that were randomly (uniformly) sampled.
Clarification and examples
By “sum and/or sub”, I mean placing "+" and "-" in front of each element of array and summing over. Let's call this function SumSub.
int SumSub (int* A,int x)
{
...
}
SumSub({2,7,5},10)
should return TRUE as 7-2+5=10. You will note that the first element of A can also be taken as negative so that the order of elements in A does not matter.
SumSub({2,7,5,2},10)
should return FALSE as there is no way to “sum and/or sub” the elements of array to reach the value of x. Please note, this means that all elements of A must be used.
Complexity
Let n be the length of A. Complexity of the problem is of order O(2^n) if one has to explore all possible combinations of pluses and minus. However, some combinations are more likely than others and therefore are worth being explored first (hoping the output will be TRUE). Typically, the combination which requires substracting all elements from the largest number is impossible (as all elements of A are lower than x). Also, if n>x, it makes no sense to try adding all the elements of A.
Question
How should I go about writing this function?
Unfortunately your problem can be reduced to subset-sum problem which is NP-Complete. Thus the exponential solution can't be avoided.
The original problem's solution is indeed exponential as you said. BUT with the given range[1,x-1] for numbers in A[] you can make the solution polynomial. There is a very simple dynamic programming solution.
With the order:
Time Complexity: O(n^2*x)
Memory Complexity: O(n^2*x)
where, n=num of elements in A[]
You need to use dynamic programming approach for this
You know the min,max range that can be made in in the range [-nx,nx]. Create a 2d array of size (n)X(2*n*x+1). Lets call this dp[][]
dp[i][j] = taking all elements of A[] from [0..i-1] whether its possible to make the value j
so
dp[10][3] = 1 means taking first 10 elements of A[] we CAN create the value 3
dp[10][3] = 0 means taking first 10 elements of A[] we can NOT create the value 3
Here is a kind of pseudo code for this:
int SumSub (int* A,int x)
{
bool dp[][];//set all values of this array 0
dp[0][0] = true;
for(i=1;i<=n;i++) {
int val = A[i-1];
for(j=-n*x;j<=n*x;j++) {
dp[i][j]=dp[ i-1 ][ j + val ] | dp[ i-1 ][ j - val ];
}
}
return dp[n][x];
}
Unfortunately this is NP-complete even when x is restricted to the value 0, so don't expect a polynomial-time algorithm. To show this I'll give a simple reduction from the NP-hard Partition Problem, which asks whether a given multiset of positive integers can be partitioned into two parts having equal sums:
Suppose we have an instance of the Partition Problem consisting of n positive integers B_1, ..., B_n. Create from this an instance of your problem in which A_i = B_i for each 1 <= i <= n, and set x = 0.
Clearly if there is a partition of B into two parts C and D having equal sums, then there is also a solution to the instance of your problem: Put a + in front of every number in C, and a - in front of every number in D (or the other way round). Since C and D have equal sums, this expression must equal 0.
OTOH, if the solution to the instance of your problem that we just created is YES (TRUE), then we can easily create a partition of B into two parts having equal sums: just put all the positive terms in one part (say, C), and all the negative terms (without the preceding - of course) in the other (say, D). Since we know that the total value of the expression is 0, it must be that the sum of the (positive) numbers in C is equal to the (negated) sum of the numbers in D.
Thus a YES to either problem instance implies a YES to the other problem instance, which in turn implies that a NO to either problem instance implies a NO to the other problem instance -- that is, the two problem instances have equal solutions. Thus if it were possible to solve your problem in polynomial time, it would be possible to solve the NP-hard Partition Problem in polynomial time too, by constructing the above instance of your problem, solving it with your poly-time algorithm, and reporting the result it gives.

Index exceeds matrix dimension when applied to an array of values

I wrote the following problem in Matlab to get the first 3 digits of a number.
Let x be a real number.
function [y]=mifl(x) % mifl=my float
s=num2str(x);
y=sscanf(s(1:4),'%f');
end
So function mifl returns the first 3 digits of a number.
For example,
mifl(pi)=3.14
But when I tried to apply this function to all the values of the vector v I got "Index exceeds matrix dimensions". I can't figure out why.
I used
v=linspace(0.1, 99.9, 1000);
w=[]
for i=1:5
w(i)=mifl(v(i))
end
That's when I get the "Index exceeds matrix dimensions".
At the end, what I want is, given a vector
v=linspace(0.1, 99.9, 1000);
to get a vector
w=[mifl(0.1),...mifl(99.9)]
The reason is because you are specifying a number in your function that doesn't have three significant digits. Specifically, try 0.1 from your vector. This doesn't have 3 digits and so you get an out of bounds error because you're assuming it does.
As such, in your function, check the length of the string and ensure that there are 4 characters to extract. If not, then get whatever is available:
function [y]=mifl(x) % mifl=my float
s=num2str(x);
m = min(numel(s), 4); %// Change
y=sscanf(s(1:m),'%f');
end
If you try the above, your code should now work.
I'd like to also suggest that you pre-allocate your arrays before populating them for speed.
Specifically:
v=linspace(0.1, 99.9, 1000);
w=zeros(numel(v),1);
for i=1:numel(v)
w(i)=mifl(v(i));
end
w is initialized to be an array of 0s that is as long as v, then we'll go through each value in v and call mifl, then store this result in the corresponding location in w.
You can use Matlabs rand function.
y = round(x,3,'significant');
This will return the first 3 significant digits of each number in a vector x. This code will also be easy for another person to comprehend since round is a built in Matlab function, which is used for rounding. The argument 'significant' should be clear enough. This will also work for numbers larger than 100, which makes it more general. That is of course if it was 3 significant digits you were after and not the first three digits in the number. In that case this will not work. The number 1001 would then be 1000 and not 100, which your solution would give.

Is neural net only capable of solving problems with 0..1 input values and 0..1 expected output values?

I've just created my first neural net, which uses gradient method and back propagation learning algorithm. It uses hyperbolic tangent as activation function. The code is well unit tested so I was full of good hopes that the net will actually work. Then I decided to create an integration test and try to teach my net to solve some very simple functions. Basically I'm testing if the weight improves (there's only one, as this is a very small net - input plus one neuron).
// Combinations of negative sign for values greater than 1
[TestCase(8, 4)] // FAIL reason 1
[TestCase(-8, 4)] // FAIL reason 1
[TestCase(8, -4)] // FAIL reason 1
[TestCase(-8, -4)] // FAIL reason 1
// Combinations of negative sign for values lesser than 1
[TestCase(.8, .4)] // OK
[TestCase(-.8, .4)] // FAIL reason 2
[TestCase(.8, -.4)] // FAIL reason 2
[TestCase(-.8, -.4)] // OK
// Combinations of negative sign for one value greater than 1 and the other value lesser than 1
[TestCase(-.8, 4)] // FAIL reason 2
[TestCase(8, -.4)] // FAIL reason 2
// Combinations of one value greater than 1 and the other value lesser than 1
[TestCase(.8, 4)] // OK
[TestCase(8, .4)] // FAIL reason 1
public void ShouldImproveLearnDataSetWithNegativeExpectedValues(double expectedOutput, double x)
{
var sut = _netBuilder.Build(1, 1); // one input, only one layer with one output
sut.NetSpeedCoefficient = .9;
for (int i = 0; i < 400; i++)
{
sut.Feed(new[] { x }, new[] { expectedOutput });
}
var postFeedOutput = sut.Ask(new[] { x }).First();
var postFeedDifference = Math.Abs(postFeedOutput - expectedOutput);
postFeedOutput.Should().NotBe(double.NaN);
postFeedDifference.Should().BeLessThan(1e-5);
}
I was very disappointed, because most of the test cases failed (only 3 marked with '// OK' passed). I dug into the code and found out some interesting facts.
The hyperbolic tangent max value is 1. So no matter how big the sum of weight * input is, the neuron's output absolute value will always be <= 1. In other words the net will never learn to solve a function if it's return absolute value is greater than 1. That explains all failures of test cases with 8, -8 expected outputs.
In test cases where one of the numbers is negative the final weight should also be negative. Firstly it decreases, but it would never become negative. It either stops around 0 or jumps back and forth around 0.
Is neural net only capable of solving problems with 0..1 input values and 0..1 expected output values or is there something wrong with my implementation?
You can have other outputs from NN. If you want discrete output (classification), use Softmax Regression. Instead if you want continuous output (regression) then you have to create a bijective map between range of your output (min, max) and (0,1). In most cases, the map f:(min,max)->(0,1), f(x) = (x-min)/(max-min) is sufficient.
In test cases where one of the numbers is negative the final weight should also be negative
Why final weight should also be negative?
You can have any numbers as input. (Though it is good practice to normalize the features to smaller ranges, usually by making them to have mean 0 and standard deviation 1)

Taylor series for arcsin(x), incorrect output C language

I wrote a program that gets from the user a value x and an integer n, the program then prints arcsin(x) using the taylor serie for arcsin
http://tedmuller.us/Math/img/Taylor-arcsin.gif
but for some reason its not working. when i enter x=1 i get an output of 1.19 rather than pi/2.
here's my code:
#include <stdio.h>
#include <conio.h>
void main()
{
int i,n;
double x,sum,last;
printf("Please enter the x you wish to calculate arcsin(x) for \n");
scanf("%lf",&x);
printf("Enter n\n");
scanf("%d",&n);
last=x;
sum=last;
for(i=1;i<=n;i++)
{
last*=((x*x)*(2*i-1))/((2*i)*(2*i+1));
sum+=last;
}
printf("arcsin(%lf) = %lf",x,sum);
getch();
}
basic idea is this: last and sum both start with value of x. then i advance last to be the next number in the serie, add it to sum, advance last again, add to sum...rinse and repeat n times.
Looks like you have a mistake in your expansion.
Try this:
last*=((x*x)*(2*i-1)*(2*i-1))/((2*i)*(2*i+1))
You'll still need lots of terms. With 1000 terms I get arcsin(1.0) ~= 1.552963 . ( Your code 1.194958 )
10000 terms arcsin(1.0) ~= 1.565155. ( Your code 1.194958 )
One problem is that that series converges logarithmically quickly when x=1. Notice that x=1 is at the boundary of arcsin's radius of convergence. So it's not surprising that you'll get extremely slow convergence.
A bigger problem is that you didn't actually implement the series you thought you had implemented. You're summing something that converges linearly. It looks like it might be the integral of something well-knkown, but it's certainly not arcsin.
The Taylor series you expanded has six-place accuracy for |x| < .5, five-place for |x| < .6, four-place for |x| < .7, three-place for |x| < .8, and two-place for |x| < .9.
Of course, there's no reason to think the Taylor polynomial is the best
polynomial of a given degree. Welcome to Numerical Analysis.
It takes too many terms to get a good estimation for |x| = 1, because the derivative of arcsin(x) has a pole at x = 1, so that its Taylor series converges very slowly. This means the Taylor expansion is not an efficient way of approximating arcsin(x) except for small x. If you printed each term of the expansion as you calculate it, you'd see it's extremely small to make the series converge in a reasonable amount of time.
For your aid, Milton Abramowitz and Irene Stegun in their book "Handbook of Mathematical Functions", p.81 derive this approximation formula:
arcsin(x) = pi/2 - sqrt(1 - x)(a0 + a1*x + a2*x^2 + a3*x^3)
where
a0 = 1.5707288
a1 = -0.2121144
a2 = 0.0742610
a3 = -0.0187293
which performs much better near 1.

Genetic Programming with the Mandelbrot Set

I'm reading a chapter in this fascinating book about using genetic programming to interactively evolve images. Most of the function set is comprised of simple arithmetic and trig functions (which really operation on and return images). These functions make up the internal nodes of the parse trees that encode our images. The leaves of the tree, or the terminal values, are random numbers and x,y coordinates.
There's a section about adding iterative functions of the complex plane to the function set:
Say the genetics inserts a particular Mandelbrot set as a node somewhere in
a bushy tree. The function expects two arguments: mandel(cReal, cImag), treating
them as real and imaginary coordinates in the complex plane. If the genome
just happened to supply the pixel coordinates (x,y), and mandel() were the root
node, you would get the familiar Mset. But chances are that cReal and cImag are themselves the results of whole branches of functions, with many instances of coordinates
x,y scattered out among the leaves. Enter the iteration loop, orbit
around for a while, and finally escape with some measure of distance to the Mset
attractor, such as the number of iterations.
My question is how would you make a Mandelbrot set renderer as a function that takes the real and imaginary coordinates of a point on the complex plane as arguments and returns a rendering of the Mandelbrot set?
I'm not sure if this actually answers your question, but my understanding of the text you quoted simply says that the mandel function is just another function (like multiplication, min, max, addition, etc) that can appear in your genetic program.
The mandel function, like the multiplication function, takes two arguments (in_1 and in_2) and returns a single value. Whereas the multiplication function just returns in_1 * in_2, the mandel function might do something like this:
int mandel(int in_1, int in_2) {
x = 0
y = 0
iteration = 0
max_iteration = 1000
while( x*x + y*y <= (2*2) && iteration < max_iteration ) {
xtemp = x*x - y*y + in_1
y = 2*x*y + in_2
x = xtemp
++iteration
}
if( iteration == max_iteration ) return 0
else return iteration
}
If your whole genetic program tree consists of nothing but the mandel function with one input as x and the other input as y, then repeatedly evaluating your program for a bunch of different (x,y) values and saving the result will give you a nice picture of the Mandelbrot set.
Of course, the neat thing about genetic programming is that the inputs can be fancier than just x and y. For example, what would the result look like if one input was x and the other input was x + 2*y? Or if one input was x and the other was mandel(x,y)?

Resources