Floating point precision matlab filter2 - matlab

I'm having round-off errors caused by filter2.
Here is a minimal code example:
format long
x=[ 0 0 0 0 0
64 65 72 74 72
104 111 109 106 112];
h=[ 0 0 0 0 0
0 0.500000000000000 0 0.500000000000000 0
0 0 0 0 0]
y=filter2(h,x, 'valid')
y_= x(2,2)/2 + x(2,4)/2
y__= sum(sum(x .* h))
round(y)
round(y_)
round(y__)
results in
y = 69.499999999999986
y_ = 69.500000000000000
y_ = 69.500000000000000
ans = 69
ans = 70
ans = 70
I'm guessing this is a result of doing the filtering in the fft domain (or something similar). Unfortunately this is giving me issues when verifying the test vectors I'm generating agains an FPGA implementation.
Any ideas how to fix/avoid this error?
PS I'm using matlab 2007b.
Edit: 2007a to 2007b
Edit2: Added y__ example

It is expected behavior that operations performed with floating-point arithmetic produce approximate results. Floating-point arithmetic uses a fixed number of bits to represent numbers, and the result of each floating-point operation is rounded to the nearest representable number (unless another rounding mode is set).
In particular, performing an FFT requires sines and cosines of many values, and the sines and cosines are not exactly representable, and the arithmetic upon those values and the values in the FFT data produces many intermediate results that are not exactly representable. Consequently, the results of FFTs are expected to be approximate.
Studies of errors in floating-point FFTs have shown the error behavior is generally good. However, you cannot expect that a result will land on the “correct” side of 69.5 to cause the rounding you desire. Essentially, it is an error to expect that rounding the results of an FFT will produce exact results.
Generally, using floating-point formats with greater precision can reduce the magnitudes of errors. Thus, using greater precision could produce FFT results closer to ideal results. However, consider what is necessary to make rounding work. Any number 69.5 or slightly greater will round to 70. Any number slightly less than 69.5 will round to 69, which you do not want. Therefore, to round as you desire, no error that produces a number less than 69.5 is acceptable, regardless of how small that error is. However, every floating-point format has some error. Therefore, there is no precision that is guaranteed to produce results that can be rounded in the way you desire. (Errors can be controlled somewhat by setting rounding modes, to cause rounding upward or downward as desired. However, the FFT is a complex operation, and getting the desired rounding in the final product would require controlling the rounding in every intermediate operation and is impractical.)
So, a floating-point FFT will not produce the results you desire. Some options available to you are:
Change your expectations; do not expect the filter to produce results identical to exact arithmetic.
Perform the filter using direct arithmetic, not an FFT. (I do not use Matlab and cannot advise on good ways to do this in Matlab.) Note that doing this with floating-point arithmetic will produce exact results only so long as all intermediate values are representable in the floating-point format. This is generally true only for small filters with “simple” values in the filter and in the data. (For this purpose, and supposing a binary floating-point format, “simple” values are those representable with just a few bits in the fraction portion of the floating-point format, i.e., those that are sums of a few integer powers of two that are close to each other, such as .625, which is 2-1+2-3.)
Use exact arithmetic. Some mathematics software, such as Maple and Mathematica, support exact arithmetic. As far as I know, Matlab does not. This generally requires performing the filter with direct arithmetic, not an FFT, since performing an FFT exactly requires greater mathematical capabilities (manipulating sines and cosines exactly).
Since you state this is for testing, I suggest that you either:
Allow small errors in the results. Small errors are typical of floating-point arithmetic and generally do not indicate errors in the filter you are testing. The bugs you are looking for in your tests will generally produce large and numerous errors.
Use direct arithmetic, if it is sufficient, or exact arithmetic if necessary. This will consume more processor time. However, testing generally does not need to be high-performance, so it is okay to use more processor time.

The standard way to deal with this is to avoid floating point comparison.
Rather than checking whether two things are equal, check whether the absolute difference is smaller than some epsilon.
So if you want to see whether your two numbers match you can do:
abs(y-y_)

Related

Estimate the derivative doing the limit in MATLAB

I want write a script in MATLAB that computes the quotient of the derivative (f(x+h)-f(x))/h for the function x^2 at x=2 and h starting at 1 and decreasing by a factor of 10, and the book said that the effect of the rounding error becomes apparent when h gets to small (less than 10^-12).
Then I wrote the following code:
for i=0:-2:-16
h=10^i;
((2+h)^2-(2)^2)./h
end
Then my question is, How can I improve my code? because It gives me indeed an error saying that the last approximation to the derivative is zero.
Thanks a lot in advance :)
Due to the limit of floating point arithmetic you are limited in how small you can choose h. An reasonable option for choosing a "safe" small h is using h=x*sqrt(eps) where eps is the distance from 1.0 to the next largest double-precision number, that is, eps = 2^-52
This Wikipedia page contains some more information
If you REALLY wanted higher precision arithmetic you could consider using an implementation of multi-precision arithmetic. For example this is a MATLAB wrapper around the well-established GMP (GNU Multiple Precision Arithmetic Library) and MPFR (multiple-precision floating-point computations with exact rounding)

Matlab Bug in Sine function?

Has anyone tried plotting a sine function for large values in MATLAB?
For e.g.:
x = 0:1000:100000;
plot(x,sin(2*pi*x))
I was just wondering why the amplitude is changing for this periodic function? As per what I expect, for any value of x, the function has a period of 2*pi. Why is it not?
Does anyone know? Is there a way to get it right? Also, is this a bug and is it already known?
That's actually not the amplitude changing. That is due to the numerical imprecisions of floating point arithmetic. Bear in mind that you are specifying an integer sequence from 0 to 100000 in steps of 1000. If you recall from trigonometry, sin(n*x*pi) = 0 when x and n are integers, and so theoretically you should be obtaining an output of all zeroes. In your case, n = 2, and x is a number from 0 to 100000 that is a multiple of 1000.
However, this is what I get when I use the above code in your post:
Take a look at the scale of that graph. It's 10^{-11}. Do you know how small that is? As further evidence, here's what the max and min values are of that sequence:
>> min(sin(2*pi*x))
ans =
-7.8397e-11
>> max(sin(2*pi*x))
ans =
2.9190e-11
The values are so small that they might as well be zero. What you are visualizing in the graph is due to numerical imprecision. As I mentioned before, sin(n*x*pi) = 0 when n and x is are integers, under the assumption that we have all of the decimal places of pi available. However, because we only have 64-bits total to represent pi numerically, you will certainly not get the result to be exactly zero. In addition, be advised that the sin function is very likely to be using numerical approximation algorithms (Taylor / MacLaurin series for example), and so that could also contribute to the fact that the result may not be exactly 0.
There are, of course, workarounds, such as using the symbolic mathematics toolbox (see #yoh.lej's answer). In this case, you will get zero, but I won't focus on that here. Your post is questioning the accuracy of the sin function in MATLAB, that works on numeric type inputs. Theoretically with your input into sin, as it is an integer sequence, every value of x should make sin(n*x*pi) = 0.
BTW, this article is good reading. This is what every programmer needs to know about floating point arithmetic and functions: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html. A more simple overview can be found here: http://floating-point-gui.de/
Because what is the exact value of pi?
This apparent error is due to the limit of floating point accuracy. If you really need/want to get around that you can do symbolic computation with matlab, see the difference between:
>> sin(2*pi*10)
ans =
-2.4493e-15
and
>> sin(sym(2*pi*10))
ans =
0

Approximation for mean(abs(fft(vector)))?

Some MatLab code I'm trying to simplify goes through the effort of finding FFT, only to take the absolute value, and then the mean:
> vector = [0 -1 -2 -1 0 +1 +2 +1];
> mean(abs(fft(vector)))
ans = 2
All these coefficients are built up, then chopped back down to a single value. The platform I'm working on is really limited, and if I can get by without using FFT, all the better. Is there a way to approximate these operations without FFT?
Can assume vector will be at most 64 values in length.
I think this is a just a very inefficient way of calculating the RMS value of the signal. See Parseval's Theorem. You can probably just simplify the expression to:
sqrt(mean(vector.*vector))
If your vector is real and has zero average as in your example, you can take advantage of the fact that the two halves of the DFT are complex-conjugate (from basic signal processing) and save half the abs computations. Also, use sum, which is faster than mean:
fft_vector = fft(vector);
len = length(fft_vector)/2;
sum(abs(fft_vector(1:len)))/len

Probability of generating a particular random number, such as in MATLAB

In real probability, there is a 0% chance that a random number p, selected from all of the real numbers in the interval (0,1), will be 0.5. However, what are the odds that
rand == 0.5
in MATLAB? I suppose this is like asking how many double-precision numbers are between zero and one, or maybe there are other factors at play.
No particular info on MATLAB's generator...
In general even simple pseudo-random generators have long enough cycles which would cover all values representable by double.
If MATLAB uses some other form of generating random numbers it would be even better - so assuming it uniformly covers whole range of double values.
I believe probability would be: distance between representable numbers around values you are interested divided by length of the interval. See What is the minimal step in double data type? (.NET) for discussion on the distance.
Looking at this question, we see that there are 262 - 252
doubles in the interval (0 1). Therefore, the probability of picking any single one (like 0.5) would be roughly equal to one divided by this number, or
>> p = 1/(2^62-2^52)
ans =
2.170523997312134e-019
However, as horchler already indicates, it also depends on the type of random number generator you use, as well as MATLAB's implementation thereof. Sadly, I have only basic knowledge on the implementaion details for each, but you can look here for a list of available random number generators in MATLAB and google a bit further for more precise numbers.
I am not sure whether Alexei was trying to say this, but inspired by him I think the probability will indeed be approximately the distance between numbers around 0.5.
Therefore I expect the probability to be approximately:
eps(0.5)
Which evaluates to 1.1102e-16
Given the monotonic nature of the difference between double numbers I would actually think this holds:
eps(0.5-eps(0.5)) <= yourprobability <= eps(0.5)
Implying a range of 5.5511e-17 to 1.1102e-16

Matlab: reverse of eps? Accuracy on positive weight?

eps returns the distance from 1.0 to the next largest double-precision number, so I can use it to interpret the numbers value on negative weight position. But for very large number with value on high positive weight position, what can I use to interpret?
I mean that I need to have some reference to count out computation noise on numbers obtained on Matlab.
Have you read "What Every Computer Scientist Should Know About Floating-Point Arithmetic"?
It discusses rounding error (what you're calling "computation noise"), the IEEE 754 standard for representation of floating-point numbers, and implementations of floating-point math on computers.
I believe that reading this paper would answer your question, or at least give you more insight into exactly how floating point math works.
Some clarifications to aid your understanding - too big to fit in the comments of #Richante's post:
Firstly, the difference between realmin and eps:
realmin is the smallest normalised floating point number. You can represent smaller numbers in denormalised form.
eps is the smallest increment between distinct numbers. realmin = eps(realmin) * 2^52.
"Normalised" and "denormalised" floating point numbers are explained in the paper linked above.
Secondly, rounding error is no indicator of how much you can "trust" the nth digit of a number.
Take, for example, this:
>> ((0.1+0.1+0.1)^512)/(0.3^512)
ans =
1.0000
We're dividing 0.3^512 by itself, so the answer should be exactly one, right? We should be able to trust every digit up to eps(1).
The error in this calculation is actually 400 * eps:
>> ((0.1+0.1+0.1)^512)/(0.3^512) - 1
ans =
9.4591e-014
>> ans / eps(1)
ans =
426
The calculation error, i.e. the extent to which the nth digit is untrustworthy, is far greater than eps, the floating-point roundoff error in the representation of the answer. Note that we only did six floating-point operations here! You can easily rack up millions of FLOPs to produce one result.
I'll say it one more time: eps() is not an indicator of the error in your calculation. Do not attempt to display : "My result is 1234.567 +/- eps(1234.567)". That is meaningless and deceptive, because it implies your numbers are more precise than they actually are.
eps, the rounding error in the representation of your answer, is only 1 part per billion trillion or so. Your real enemy is the error that accumulates every time you do a floating point operation, and that is what you need to track for a meaningful estimate of the error.
Easier to digest than the paper Li-aung Yip recommends would be the Wikipedia article on machine epsilon. Then read What Every Computer Scientist ...
Your question isn't very well worded, but I think you want something that gives the distance from a number to the next smallest double-precision number? If this is the case, then you can just use:
x = 100;
x + eps(x) %Next largest double-precision number
x - eps(-x) %Next smallest double-precision number
Double-precision numbers have a single sign bit, so counting up from a negative number is the same as counting down from a positive.
Edit:
According to help eps, "For all X, EPS(X) is equal to EPS(ABS(X))." which really confuses me; I can't see how that can be consistent with double having a single sign bit, and values not being equally spaced.