MATLAB - floor question - matlab

I'm a MATLAB beginner. Here's the problem:
>> a = floor(7/2.5)
a =
2.00
>> b = rem(7,2.5)
b =
2.00
>> c = floor(b/2)
c =
0
c should be 1, right? Why is it 0???
It is different when b = 2 is entered directly as follows:
>> b = 2
b =
2.00
>> c = floor(b/2)
c =
1.00

In two words: truncation errors.
You're right, c should be 1.0 in exact arithmetic. However, since you used a float in the arguments of rem, you get the answer as a float. Apparently, b is not exactly 2, but 2.0, which means that it is a double very close to 2. Therefore, b/2 becomes the double 1.0, apparently in this case its value is slightly less than one, giving you a 0 as the integer value. If you want to prevent this, use both floor and ceil, and compare the values.
If you want to convert the answer to integer, just use round instead of floor.

If you add the line
d = b-a
to your example you'll see the result
d =
-4.4409e-016
meaning Matlab calculated a number close to, but not exactly, 2 for b. This comes up quite a bit in working with floating point numbers. Try
help eps
for more information.

Numerical issues of this sort are also dealt with in the MATLAB FAQ

Yeah that is a numerical issue. You should use such things with care. If you want exact arithmetic , you should try 'sym' for your number e.g.
b=rem(sym(7),sym(2.5))
Then you will not any such errors, but your computations will be much slower.

Related

Mod function returns 0 for Matlab

I have a problem with the mod function output in Matlab. I am trying to perform some calculations for ECC double and add algorithm. I am reading data from a file and storing it in a variable and then performing some operations. All works smoothly except that I get 0 in temp1 when I use mod(X2,P). However if I put in values stored in X2(3.0323e+153) and P(1.1579e+77) on command window (mod( 3.0323e+153, 1.1579e+77)), I get the correct values. Can anyone please help me? Below is the part of script which is problematic.
P = hex2dec('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F');
line = fread(fileID,[1,67],'*char');
while ~feof(fileID)
PX = line(4:67);
X = hex2dec(PX);
X2 = X^2;
temp1= mod(X2 , P)
end
line = fread(fileID,[1,69],'*char');
end
fclose(fileID);
I think the problem lies with how you're initializing P. From the documentation for hex2dec (emphasis mine):
d = hex2dec('hex_value') converts hex_value to its floating-point integer representation. The argument hex_value is a hexadecimal integer stored as text. If the value of hex_value is greater than the hexadecimal equivalent of the value returned by flintmax, then hex2dec might not return an exact conversion.
And the value of flintmax is:
>> flintmax
ans =
9.007199254740992e+15
Quite a bit smaller than your value for P. In fact, if we use num2hex to look at the two ways you initialize P, you can see a clear difference:
>> P = hex2dec('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F');
>> num2hex(P)
ans =
4ff0000000000000
>> num2hex(1.1579e+77)
ans =
4fefffda293c30de
As it turns out, the inexact conversion done by hex2dec results in a number that evenly divides into 3.0323e+153, thus giving you a remainder of 0:
>> mod(3.0323e+153, P)
ans =
0
>> mod(3.0323e+153, 1.1579e+77)
ans =
8.795697942083107e+76

Multiply two variables in Matlab with vpa - high precision

I want to be sure that two variables, a and b, are multiplied with high precision, i.e., perform the product c of a and b with arbitrary precision (in my case 50 correct decimal digits):
a = vpa(10/3,50);
b = vpa(7/13,50);
c = eval(vpa(vpa(a,50)*vpa(b,50),50)); % I basically want to do just c = a*b;
which gives me
a = 3.3333333333333333333333333333333333333333333333333
b = 0.53846153846153846153846153846153846153846153846154
c = 23.333333333333333333333333333333
Testing
d = eval(vpa(c*13,50))
gives
d = 23.333333333333333333333333333333333333335292490585
which shows that the multiplication to get c was not carried out with 50 significant digits.
What's wrong here, but, more importantly, how do I get a correct result for a*b and for other operations such as exp?
First, should use vpa('7/13',50) or vpa(7,50)/13 to avoid the possibility of losing precision dues to 7/13 being calculated in double precision floating point (I believe that vpa, like sym, tries to guess common constants and rational fractions, but you shouldn't rely on it).
The issue is that while a and b are stored as 50-digit variable precision values, your multiplication is still being performed according to the default value of digits (32). The second argument to vpa only appears to specify the precision of the variable, not any subsequent operations on or with it (the documentation is not particularly helpful in this respect).
One way to accomplish what you want would be:
old_digits = digits(50);
a = vpa('10/3')
b = vpa('7/13')
c = a*b
d = 13*c
digits(old_digits);
Another would be to use exact symbolic expressions for all of the math (potentially more expensive) and then convert the result to 50-digit variable precision at the end:
a = sym('10/3')
b = sym('7/13')
c = a*b
d = vpa(13*c,50)
Both methods return 23.333333333333333333333333333333333333333333333333 for d.

Do variables contain extra hidden metadata - aka When is zero not zero (but still is)

I hate having to ask this because I assume the answer must be simple, but I cannot for the life of me seem to track down the source. While trying to rewrite a function I ran across this problem:
a = -j
x = real(a)
y = imag(a)
y/x
Which spits out Inf, unexpectedly for me. However...
a = 0
b = -1
b/a
returns -Inf, like I would expect. Inquiring further, a == x, b == y. Clearly that isn't true however. I finally tracked down the problem to this after a lot of frustration. If the original input for a is instead 0-j (vs. -j) then there is no problem.
Both real(-j) and real(0-j) return zero and test as zero, but obviously seem to retain some metadata relating to their origin that I absolutely cannot discover. What precisely am I missing here? It will feel downright wrong if I have to solve this with something like if (x == 0) then x = 0;
Not metadata, just the sign bit of the double precision float.
>> a = 0-j;
>> b = -j;
>> ra = real(a)
ra =
0
>> rb = real(b)
rb =
0
>> ra==0
ans =
1
>> isequal(ra,rb)
ans =
1
Looks the same so far. However, the difference is that with b, we set the sign bit for both the real and imaginary parts when we do -j = -complex(0,1) vs. 0-j = complex(0,-1) (see Creating Complex Numbers). Looking deeper with typecast, which does no conversion of the underlying data:
>> dec2bin(typecast(ra,'uint64'),64)
ans =
0000000000000000000000000000000000000000000000000000000000000000
>> dec2bin(typecast(rb,'uint64'),64)
ans =
1000000000000000000000000000000000000000000000000000000000000000
That 1 is bit 63 (of 0) in the IEEE 754 double precision floating point representation:
Voila! -0 exists in MATLAB too!
When using IEEE 754 floating point numbers there is a convention to have a number approaching zero that cannot be represented by the smallest possible float called an underflow where the precision of the number is being lost with each step below the smallest possible float. Some operating systems will consider the underflow to be equal to zero.
I was surprised to be testing some software and find that a threshold test of zero actually went below zero almost as far as the smallest possible negative float.
Perhaps this is why your getting a negative infinity instead of a divide by zero error which I am assuming is the problem your referring to.

Increase Hex2dec or dec2hex output range in Matlab

I have a strange problem with hex2dec function in Matlab.
I realized in 16bytes data, it omits 2 LSB bytes.
hex2dec('123123123123123A');
dec2hex(ans)
Warning: At least one of the input numbers is larger than the largest integer-valued floating-point
number (2^52). Results may be unpredictable.
ans =
1231231231231200
I am using this in Simulink. Therefore I cannot process 16byte data. Simulink interpret this as a 14byte + '00'.
You need to use uint64 to store that value:
A='123123123123123A';
B=bitshift(uint64(hex2dec(A(1:end-8))),32)+uint64(hex2dec(A(end-7:end)))
which returns
B =
1310867527582290490
An alternative way in MATLAB using typecast:
>> A = '123123123123123A';
>> B = typecast(uint32(hex2dec([A(9:end);A(1:8)])), 'uint64')
B =
1310867527582290490
And the reverse in the opposite direction:
>> AA = dec2hex(typecast(B,'uint32'));
>> AA = [AA(2,:) AA(1,:)]
AA =
123123123123123A
The idea is to treat the 64-integer as two 32-bit integers.
That said, Simulink does not support int64 and uint64 types as others have already noted..

How do I select individual elements of a given (very large) matrix, see if they are in a particular range and change them in Matlab?

I have a matrix which is 256x938. I need to go through each individual element, see if it is in the range -pi < element < pi, if it is not then we need to subtract or add a multiple of 2*pi to get the element in the range. Preferrably without for loops as we have found that they are very inefficient.
Not unlike the other solutions posed, but a bit cleaner since it requires only one simple line of code...
B = mod(A+pi,2*pi) - pi;
A = -20:2:20;
mod(A+pi,2*pi) - pi
ans =
Columns 1 through 12
-1.1504 0.84956 2.8496 -1.4336 0.56637 2.5664 -1.7168 0.28319 2.2832 -2 0 2
Columns 13 through 21
-2.2832 -0.28319 1.7168 -2.5664 -0.56637 1.4336 -2.8496 -0.84956 1.1504
Is this what you want?
B=rem(A,2*pi)
B(A<-pi)=A(A<-pi)+2*pi
B(A>pi)=A(A>pi)-2*pi
Every element b in B is now -pi <= b <= pi.
It can not become -pi < b < pi as asked for in the question.
I don't have Matlab at hand right now, so my suggestion might not work, but I hope the idea will.
Try something along this way:
c = cos(B); % will set all your elements between [-1 1]
B2 = acos(c); % will return values between [0 PI] but for some the sign will be wrong
B2 = B2.*sign(sin(B)); % should set the correct sign for each element.
Hope this works.
I could have condensed all three lines to 1, but I tried to make the idea as clear as possible.