The floating point error exists in both linspace and array creation if the increment is not an integer value. Intersect and ismember fails.

clc;
clear all;
A=round(345684*rand(3000,100,10))/1000;
pmn_inc=0.0001;
pmn_saved=linspace(pmn_inc,500,500/pmn_inc);
% pmn_saved is all possible combinations of numbers
% with 0.0001 accuracy ranging from
% 0.0001 to 500
[Cval,ia,ic]=unique(A); % have determined unique values of A
% -> 3 decimal spaced values -> maximum value:345.6840
[C2,Ipmn,ICval]=intersect(pmn_saved',Cval);
% length of C2 is not equal to Cval
C1=pmn_saved(Ipmn)';

2 Comments

What do you mean by not working? Error? What is the problem?
"Why does intersect function not work "
How are you checking this? Are you comparing floating point values?
"The floating point error exists in both linspace and array creation if the increment is a decimal value."
Not always, as there are plenty of decimal numbers that can be represented exactly by binary floating point numbers. Try starting from an integer and incrementing by 0.5 or 0.25: no floating point error!
"Intersect and ismember fails."
No, they don't fail. You are comparing different values, which means that ismember and intersect correctly identify them as being different values. Nothing fails.

Sign in to comment.

 Accepted Answer

This is probably due to the floating point accuracy. Multiplying so you expect only integers, rounding and then performing this operation should work.
You might be able to use ismembertol instead, but that would require changing the rest of your code and might not fit your needs.

10 Comments

inc=0.0001; p=[inc:inc:500]; plot(p/inc-p*10000);
and
inc2=0.0001; p2=linspace(inc2,500,500/inc2); plot(p2/inc2-p2*10000);
Both give inaccurate answers. This creates ambiguity in using the search functions like ismember and intersect functions.
The alternate is to use p=[1:1:5000000]/10000; for creating the elements without trouble in using ismember or intersect later on. However, this is not a solution, as we will not always deal with increment value that is a multiple of (1/10).
"Both give inaccurate answers"
Not really. Both give answers which are accurate to the precision of the floating point numbers that you are using. Floating point arithmetic is well documented:
If I measure some experiment value to three significant figures, and then perform calculations on the data, do I expect to get twenty significant figure accuracy for my results?
"The alternate is to use p=[1:1:5000000]/10000; for creating the elements without trouble in using ismember or intersect later on"
That is not a "solution", which is easy to check by generating the "same" decimal numbers two different ways:
>> p = (1:5000000)/10000;
>> q = linspace(1/10000,5000000/10000,5000000);
>> ismember(p(1:13),q(1:13)) % the first 13 elements
ans =
1 1 0 1 1 0 0 0 0 1 1 0 0
>> p(1:13)-q(1:13) % differences between the first 13 values
ans =
1.0e-18 *
0 0 -0.0542 0 0 -0.1084 -0.1084 -0.1084 -0.1084 0 0 -0.2168 -0.2168
"...we will not always deal with increment value that is a multiple of (1/10)."
Actually using an increment of 1/10 is never a solution, because 1/10 is not exactly representable by binary floating point numbers, so you have not actually resolved the problem and have just hidden it under some code obfuscation. The actual solution is to use a tolerance when comparing floating point values, exactly as Rik Wisselink wrote an hour ago. How to compare using a tolerance depends on the algorithm and the magnitude of the values being compared.
Exactly. But for a simple program to compare and get similar values, should the programmer understand how the data is taken in and up to what level of accuracy the program takes into consideration?
1/10000:1/10000:500 and [1:1:5000000]/10000 - which one should be used alway? from a programmer's perspective? Not always we will have integers as increments. That's my point.
"should the programmer understand how the data is taken in and up to what level of accuracy the program takes into consideration?"
Yes, they have to.
Computers do not have infinite memory, infinite speed, or infinite precision.
Floating point maths is fast and very efficient, in part because it is well supported by all CPU's on the market, and also because of millions of person-hours developing efficient algorithms. There are alternatives to binary floating point numbers, such as:
  • symbolic math (limited/no CPU support, so requires processor cycles, so is much slower than floating point math). Note that MATLAB offers a symbolic math toolbox.
  • fixed point representation (e.g. used in embedded systems, not supported by many CPUs).
  • decimal floating point (new standard, not supported by many CPUs).
There is no silver bullet encoding for numbers. All of them have advantages and disadvantages. Binary floating point is what most numeric computation SW uses.
"1/10000:1/10000:500 and [1:1:5000000]/10000 - which one should be used alway?"
For compactness and clarity I would probably use (1:5000000)/10000, but it really depends on how the end values are specified.
So, in matlab, 1/10000:1/10000:500 and [1:1:5000000]/10000 are different, right? That's for optimization of memory and for increasing speed.
"So, in matlab, 1/10000:1/10000:500 and [1:1:5000000]/10000 are different, right?"
Correct. With floating point mathematics those two sets of operations are not commutative. But they both give equally correct outputs!
When we compare two variables created in two different methods:
a=1/10000:1/10000:500; b=[1:1:5000000]/10000;
they are mathematically same, but they dont give same answer. Right. This can be observed by plot(a-b). So, cant compare using "intersect" or "ismember" functions.
Catch: When you are working with problems where you need to compare variables(arrays/matrices), a) make sure that you have created both the variables(arrays/matrices) using the same method. Or b) you need to Round off the matrices, and then use compare.
a) yes. but in practice you can be sure that at some point somebody will compare a value that has been obtained using a different method.
b) No. the two values that should be equal may round off a different way.
The proper way, as explained before is
c) check that the two values are within a certain tolerance of each other. So instead of
a == b
you use
abs(a-b) <= appropriate_tolerance
If you want to do membership comparisons, ismembertol does that for you.
This was good, however, ismembertol takes additional computational time. When this is used inside loops, the computational duration is going to increase drastically. Anyway, thank you everyone (Rik Wisselink, Stephen Cobeldick and Guillaume).
Neither a) nor b) is correct. You should use a tolerance when comparing floating point values:
abs(A-B)<tol
or using ismembertol, uniquetol, etc.
Sometimes beginners use rounding, but this introduces artifacts into the data that do not exist.

Sign in to comment.

More Answers (1)

Categories

Find more on MATLAB in Help Center and File Exchange

Products

Release

R2018a

Asked:

on 27 Jul 2018

Edited:

on 27 Jul 2018

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!