Best way to do plus or minus - swift

Is there a native or simpler way to do plus or minus when comparing two double values. Right now I have done two comparisons like this but I feel like there should be a cleaner way to do this. We are doing a lot of these comparisons in our app so I would prefer to use the simplest and cleanest function for this.
let y: Double = 5 // main value
let x: Double = 6 // value that we are comparing y to
if x > y + 2 || x > y - 2 {
//Do something
}
I am basically looking to check if x (in this case 6) is between 3 (5-2) and 7 (5+2). I want to do something if it is between the two value and do something else if it is not.
If possible, I want to do it by using the value of 2 opposed to explicitly writing out 3 and 7.

To check whether x is within 2 of y:
if abs(x - y) < 2 {
...
}
It's simple enough to understand alone, I think, but for the sake of completeness:
this moves the test to being around 0. If x is exactly equal to y then x - y is 0. If x is two less than y then x - y is -2. If it is two greater than x - y is 2. If it is anywhere between then it is somewhere in the middle. So the interesting range is (-2, 2);
applying an abs both gives an interesting range of [0, 2) and guarantees no outcome is below 0;
therefore a comparison only to the upper end of the range is sufficient.

You can use pattern matching:
if (y-2)...(y+2) ~= x {
// your code in case the value is within the range
}

Depending on your use it may be helpful to check to see if X is in a set of numbers.

Related

Zero crossings around mean

I am working on developing a suite classifiers for EEG signals and I will be needing a zero-crossings around mean function, defined in the following manner:
Ideally if I have some vector with a range of values representing a sinusoid or any time varying signal, I will want to return a vector of Booleans of the same size as the vector saying if that particular value is a mean crossing. I have the following Matlab implementation:
ZX = #(x) sum(((x - mean(x)>0) & (x - mean(x)<0)) | ((x - mean(x)<0) & (x - mean(x)>0)));
Testing it on toy data:
[0 4 -6 9 -20 -5]
Yields:
0
EDIT:
Yet I believe it should return:
3
What am I missing here?
An expression like:
((x-m)>0) & ((x-m)<0)
is always going to return a vector of all zeros because no individual element of x is both greater and less than zero. You need to take into account the subscripts on the xs in the definition of ZX:
((x(1:end-1)-m)>0) & ((x(2:end)-m)<0)
You can use the findpeaks function on -abs(x), where x is your original data, to find the peak locations. This would give you the zero crossings in general for continuous signals which do not have zero as an actual maximum of the signal.
t = 0:0.01:10;
x = sin(pi*t);
plot(t,x)
grid
y = -abs(x);
[P,L] = findpeaks(y,t);
hold on
plot(L,P,'*')
A simple solution is to use movprod, and count the products which are negative, i.e.,
cnt = sum(sign(movprod(x-mean(x),2))<0);
With your toy example, you will get cnt = 3.

Generate matrix based on density function

I'm trying to generate a 2-by-6 matrix of random numbers based on their density function, for example
f(x)= 2x-4 for 2 < x < 3; 0 otherwise
So from what I understand I have to find the cumulative density function first, x2-4x, and then I have to invert it so that I can use the rand function.
This is that part I do not understand, how do I get the inverted function
Try something similar to this method: https://stackoverflow.com/a/13914141/1011724.
However, your PDF is continuous so you need to adjust it slightly. The cumsum part becomes your CDF and the sum(r >= ... part becomes a definite integral from 0 to rand (which is just your CDF since it evaluates to 0 at x==0) so (ignoring your limits) you get
X = #(x)x.^2 - 4x
To generate a random matrix go X(rand(2,6))
To account for your limits you can just multiply the entire function by x > 2 & x < 3 but also if it's greater than 3 then although the PDF is 0, the CDF should still be 32 - 4 =5
X_limited = #(x)(x.^2 - 4x ).*(x > 2 & x < 3) + (x>=3)*5
If you plot a graph of (x > 2 & x < 3) you will see it is a rectangular function between 2 and 3 and so multiplying by it makes anything outside of that window 0 but leaves anything inside the window unchanged. Similarly, x >= 3 is a step function start at x == 3 and thus it adds 5 to any values higher than 3 and since the windowing function will make sure the first term is zero when x is greater then 3, this step function ensures a value of 5 for all x greater than 3.
Now you just need to generate random numbers in whatever your range is. Assuming it's between 0 and 5
x = rand(2,6)*5
X_limited(x)

Create an increasing integer alternating sequence in MATLAB / Octave

I'm trying to find a way to create a number pattern like the one below
0,1,-2,3,-4,5....
Please note: it needs to go to 200000, but I will be splitting them up into groups of 2000.
I found a formula that looks like it would work on http://oeis.org/A181983, but when I create the formula in MATLAB / Octave, the numbers don't match up:
f_num= #(x) x / (1 + x)^2;
numval = f_num(1)
numval = 0.25000
Is there another way I should be doing this?
Method #1 - Using (-1)^x
Just use a linear increment operator to go from 0 to 200000 and multiply the sequence by (-1)^(x+1) to allow the sign of the sequence to alternate:
x = 0:200000;
y = ((-1).^(x+1)) .* x;
The addition of the +1 is important so that the even positions get a positive sign while the odd positions get a negative sign.
Method #2 - Using indexing
Alternatively, you can declare the same array from 0 to 200000, index into every even position and negate the sign:
x = 0:200000;
x(2:2:end) = -x(2:2:end);
Method #3 - Using trigonometry and integers
One more to throw into the mix. You know that for cos(x*pi), the output is -1 when x is odd and the output is 1 when x is even. We need to flip this for your case and ultimately use this alternating sequence to multiply with the same array going from 0 to 200000, and therefore:
x = 0:200000;
y = (-cos(x*pi)).*x;
Aside
Interestingly enough, (-1)^x is also equal to exp(i*pi*x) for all values of x that are integer. We can verify this by using Euler's formula where: exp(i*pi*x) = cos(pi*x) + i*sin(pi*x). Since i*sin(pi*x) = 0 for all x belonging to an integer, we really get exp(i*pi*x) = cos(pi*x). Substituting even numbers of x will give us 1 while odd numbers of x will give us -1, and hence exp(i*pi*x) = cos(pi*x) = (-1)^x for all x belonging to integers.
Also, (-1)^(x+1) = -(-1)^x = -cos(x*pi) for all x belonging to integers and so the first method is really equal to the third method anyway!
try
f_num= #(x) x * (-1)^(x+1);

determine the frequency of a number if a simulation

I have the following function:
I have to generate 2000 random numbers from this function and then make a histogram.
then I have to determine how many of them is greater that 2 with P(X>2).
this is my function:
%function [ output_args ] = Weibullverdeling( X )
%UNTITLED Summary of this function goes here
% Detailed explanation goes here
for i=1:2000
% x= rand*1000;
%x=ceil(x);
x=i;
Y(i) = 3*(log(x))^(6/5);
X(i)=x;
end
plot(X,Y)
and it gives me the following image:
how can I possibly make it to tell me how many values Do i Have more than 2?
Very simple:
>> Y_greater_than_2 = Y(Y>2);
>> size(Y_greater_than_2)
ans =
1 1998
So that's 1998 values out of 2000 that are greater than 2.
EDIT
If you want to find the values between two other values, say between 1 and 4, you need to do something like:
>> Y_between = Y(Y>=1 & Y<=4);
>> size(Y_between)
ans =
1 2
This is what I think:
for i=1:2000
x=rand(1);
Y(i) = 3*(log(x))^(6/5);
X(i)=x;
end
plot(X,Y)
U is a uniform random variable from which you can get the X. So you need to use rand function in MATLAB.
After which you implement:
size(Y(Y>2),2);
You can implement the code directly (here k is your root, n is number of data points, y is the highest number of distribution, x is smallest number of distribution and lambda the lambda in your equation):
X=(log(x+rand(1,n).*(y-x)).*lambda).^(1/k);
result=numel(X(X>2));
Lets split it and explain it detailed:
You want the k-th root of a number:
number.^(1/k)
you want the natural logarithmic of a number:
log(number)
you want to multiply sth.:
numberA.*numberB
you want to get lets say 1000 random numbers between x and y:
(x+rand(1,1000).*(y-x))
you want to combine all of that:
x= lower_bound;
y= upper_bound;
n= No_Of_data;
lambda=wavelength; %my guess
k= No_of_the_root;
X=(log(x+rand(1,n).*(y-x)).*lambda).^(1/k);
So you just have to insert your x,y,n,lambda and k
and then check
bigger_2 = X(X>2);
which would return only the values bigger than 2 and if you want the number of elements bigger than 2
No_bigger_2=numel(bigger_2);
I'm going to go with the assumption that what you've presented is supposed to be a random variate generation algorithm based on inversion, and that you want real-valued (not complex) solutions so you've omitted a negative sign on the logarithm. If those assumptions are correct, there's no need to simulate to get your answer.
Under the stated assumptions, your formula is the inverse of the complementary cumulative distribution function (CCDF). It's complementary because smaller values of U give larger values of X, and vice-versa. Solve the (corrected) formula for U. Using the values from your Matlab implementation:
X = 3 * (-log(U))^(6/5)
X / 3 = (-log(U))^(6/5)
-log(U) = (X / 3)^(5/6)
U = exp(-((X / 3)^(5/6)))
Since this is the CCDF, plugging in a value for X gives the probability (or proportion) of outcomes greater than X. Solving for X=2 yields 0.49, i.e., 49% of your outcomes should be greater than 2.
Make suitable adjustments if lambda is inside the radical, but the algebra leading to solution is similar. Unless I messed up my arithmetic, the proportion would then be 55.22%.
If you still are required to simulate this, knowing the analytical answer should help you confirm the correctness of your simulation.

Comparing two matrices in Matlab

I have two matrices x and y, both are results from different algorithms/routines that are supposed to calculate the same result. While I know that the isequal() would check if x and y are the same matrix, the entries in those matrices would not be exactly the same (i.e. some entries may be with 5% off in worst case scenario). In this scenario, what would be the best method of comparing them to see if they are close enough to be considered the same result? Thanks in advance for the advices.
Try this:
tf = abs((A-B)./B)<0.05
This will return a logical matrix which will be true for each element if the relative difference between A and B with respect to B is less than 5 percent.
If you want to ask if all of these are true (they all satisfy the above condition):
all(tf(:))
Modifying Edric's solution:
absTol = 1e-3; % You choose this value to be what you want!
relTol = 0.05; % This one too!
absError = x(:)-y(:);
relError = absError./x(:);
relError(~isfinite(relError)) = 0; % Sets Inf and NaN to 0
same = all( (abs(absError) < absTol) & (abs(relError) < relTol) );
The variable same will be false if either the absolute or the relative error of any element is larger than whatever tolerances you choose. Also, if any elements of x happen to be exactly 0, then some of the elements of relError could end up being either infinite or not-a-number, so I used the ISFINITE function to ignore those values by setting them to 0.
I wouldn't suggest using IMAGESC to compare plots, since 1) the data is scaled when it is displayed, 2) the colormap for the display has a discrete number of color values (which I think is 256 by default, hence lots of rounding), and 3) subtle variations in color may not be all that apparent from visual comparison of two plots.
I would consider doing something like this with an absolute tolerance as well as a relative tolerance:
function same = tol( x, y )
absTol = 1e-3;
relTol = 0.05;
errVec = abs( x(:) - y(:) );
same = all( (errVec < absTol) | (errVec./x(:) < relTol) );
When you have very small value pairs in x and y, the result would return 0 although the values are ignorable themselves. So, an addition to the accepted solution
relError(x < absTol) = 0;
might be used to discard very small errors. Thus, the relative error is not considered for these values.
For matrices x and y containing floating point values, you may check if array elements are within a given tolerance of one another.
Sample code:
tol = 0.05;
result = abs(x - y) <= tol;
make use of 'isequal(a,b) where a and b are two matrices, if 1 it is true