matlab strange result for mean of single vs double
6 views (last 30 days)
Show older comments
Hello,
I get vastly different result when avraging an array using single vs double precision. Here is a code to reproduce my issue
a=single([99 100 65 101]'+zeros(4,512,512,128));
display(' single mean : ');
display([num2str(mean(a,[2 3 4]))]);
display( ' double mean : ');
display(num2str(mean(double(a),[2 3 4])));
The output on matlab R2020a and R2020b is :
single mean :
64
64
64
64
double mean :
99
100
65
101
I would expect small difference between single and double due to precision error but not that big.
I could also expect the value to become out of range if using the sum operator but this should not occure with a well implemented mean function .
This also only occures if the first dismention is not one; else i have no problem :
for exemple if using
display([num2str(mean(a(1,:,:,:),[2 3 4]))]);
I get the ouput :
99
which is the expected output
ps: i have already read that post : https://www.mathworks.com/matlabcentral/answers/5401-matlab-function-mean-returns-the-exact-same-value-for-uint16-and-double-values-not-for-single but the problem seems different (in the above post only a small difference can be seen which is explained by precision error while in my case results are not even similar)
Thank you
Herve
26 Comments
Paul
on 15 Jan 2024
it is easy to imagine that discontiguous data might not be partitioned in chunks.
B = single(99)*ones(2, 512*512*128,'single');
The "correct" answer for the sum of each row is
format long
dsum = 99*512*512*128
Summing both rows of discontiguous data
Bsum = sum(B,2)
yields the exact same result as a naive, non-chunked loop
ssum = single(0); ninetynine = single(99);
for ii = 1:(512*512*128)
ssum = ssum + ninetynine;
end
isequal(Bsum(1),ssum)
But summing just one row of B, which is discontiguous, yields the correct result
Bsum = sum(B(1,:));
isequal(Bsum,dsum)
Does this imply that B(1,:) is copied to contiguous memory and then summed?
My mental model of sum(B,2) is
Bsum = zeros(2,1,'single');
for ii = 1:2
Bsum(ii) = sum(B(ii,:));
end
Bsum
I guess my mental model needs to be adjusted.
Matt J
on 15 Jan 2024
Edited: Matt J
on 15 Jan 2024
Does this imply that B(1,:) is copied to contiguous memory and then summed?
Yes, extracting a subset of a matrix through indexing, e.g., B(i,:) or B(:,j), always creates a copy (except possibly when the subset is just a scalar). And, because in this case B(1,:) is just a vector, it will be contiguous.
Answers (3)
John D'Errico
on 12 Jan 2024
You need to understand what you did, AND you need to understand floating point arithmetic.
a=single([99 100 65 101]'+zeros(4,512,512,128));
mean(a,[2 3 4])
So what happened there? What is the mean? A mean is just a sum of the list of numbers, divided by the number of elements in that list.
asum = sum(a,[2 3 4])
You can see here that the sum is the SAME, for each of those cases. And that cannot be right, unless you understand what happened. When you compute those sums in single precision, at some point, we have a number where if you add a number on the order of 100 to it, nothing changes.
asum + 100 == asum
Do you see that the accumulation in the sum no longer works? We cannot increase those values, essentially an overflow condition. And that means we get your result.
asum/prod([512,512,128])
How do you fix this? First, I would ask why you are doing this in single precision. The simple solution is to do as @Matt J has suggested. Either compute the mean in multiple steps, or convert to double for the computation.
amean1 = mean(mean(mean(a,2),3),4)
amean2 = single(mean(double(a),[2 3 4]))
7 Comments
Matt J
on 3 Nov 2020
This is fine as workaround...mean(mean(mean(a,2),3),4)
Another workaround is to force the mean calculation in double type,
a=single([99 100 65 101]'+zeros(4,512,512,128));
mean(a,[2,3,4],'double')
ans =
99
100
65
101
0 Comments
Matt J
on 16 Jan 2024
Edited: Matt J
on 16 Jan 2024
I reported the alternative example below to Tech Support and their reply was that they do in fact consider it a bug. I'm not sure from the reply I got if the bug is the occurence of precision underflow itself, or if the bug is just the inconsistency in the result when taking means/sums across different dimensions.
B=99*ones(2, 512*512*128,'single');
mean(B,2) %wrong
mean(B,2,'double') %right
mean(B',1)' %right?
0 Comments
See Also
Categories
Find more on General Applications in Help Center and File Exchange
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!