rescale function does not work correctly

8 views (last 30 days)
bd l
bd l on 29 Mar 2023
Edited: DGM on 30 Mar 2023
In my computer, the code
load('B');
min(rescale(B(:)),[],'all')
ans = 1.1102e-16
get answer 1.1102e-16, not 0, does anyone have the same problem?

Answers (1)

Jack
Jack on 29 Mar 2023
Hi,
Yes, it is a common issue in numerical computing due to the limitations of floating-point arithmetic. In floating-point arithmetic, numbers are represented with a finite number of bits, which can lead to rounding errors and inaccuracies in calculations.
In your case, the value of 1.1102e-16 is very close to zero, but it is not exactly zero. When you use the rescale function, it scales the elements of B so that the minimum value becomes 0 and the maximum value becomes 1. However, due to rounding errors in the computation, the minimum value of B may not be exactly zero, but rather a very small number close to zero.
When you apply the min function to the rescaled B, it returns the smallest value in the matrix, which is very close to zero but not exactly zero. The 'all' option specifies that the minimum value should be computed over all elements of the matrix.
To avoid this issue, you can use a tolerance value when comparing values to zero. For example, you could modify your code to check if the minimum value is within a certain tolerance of zero, like this:
load('B');
tolerance = 1e-10; % set a tolerance value
min_val = min(rescale(B(:)));
if abs(min_val) < tolerance
disp('Minimum value is approximately zero');
else
disp('Minimum value is not approximately zero');
end
This code checks if the absolute value of the minimum value is less than the tolerance value. If it is, it displays a message indicating that the minimum value is approximately zero. Otherwise, it indicates that the minimum value is not approximately zero.
  9 Comments
bd l
bd l on 30 Mar 2023
I think there may be some "magic" processing in rescale.m, more exactly, in the matlab.internal.math.rescaleKernel internal function, may be to a) reduce memory usage, b) speed up. But I do not think it is a good idea. Since MATLAB can rescale it correctly, using the simplest code, not the rescale.m.
The non-exact behavior may be not important, beacuse 1e-16 reaches the double precision limitation. I think more important is the rescale.m does not do what it said it can do. May be it is time to revise the rescale.m or point out that sometimes non-exact behavior happens.
DGM
DGM on 30 Mar 2023
Edited: DGM on 30 Mar 2023
I think that explaining relevant non-obvious internal operations is precisely what an "algorithms" section in the documentation is supposed to clarify, so I think I agree about that.
I fhought about trying to rewrite the code to share, but I'm not sure how much I can really "rewrite" it in such a way that it's not just obfuscated copypasta -- especially since I'd rather just keep the comments verbatim.
EDIT: I'm just going to paste my little excerpt that I was poking at. It's still largely the original code, though I rearranged and renamed some things for my own viewing comfort. I threw in a few comments and removed some complications that aren't relevant to this specific usage. If someone objects that it's still too infringement-like, then I invite them to offer a better clarification.
load('B');
% we don't actually need the entire array
% we only need the extrema to observe the effect
B = [min(B(:)) max(B(:))]
B = 1×2
-2.8819 2.2453
% assuming default input limits
inlo = double(min(B(:)));
inhi = double(max(B(:)));
% assuming default output limits
outlo = 0;
outhi = 1;
% clamp input to input range
B = min(max(B,inlo),inhi);
% Regularize constant values to return lowerbound of output range
% i'm guessing this is to avoid dividing by zero
constReg = (inlo == inhi);
% Determine where to center the problem based on the input range
sigma = min(max(0,inlo),inhi); % zero if inrange crosses zero; otherwise input limit closest to zero
inlo = inlo - sigma; % shift the input limits so that zero is on or between them
inhi = inhi - sigma;
% Scale to prevent overflow/underflow
% i'll leave this to you to unpack
e1 = nextpow2(max(abs(inlo), abs(inhi)));
e2 = nextpow2(max(abs(outlo),abs(outhi)));
r1 = 2.^(e1-1);
r2 = 2.^(e2-1);
r3 = 2.^(fix((e1+e2)/2)-1);
z = ( (inhi./r1).*(outlo./r3) ...
- (inlo./r1).*(outhi./r3) ...
+ (outlo./r3).*(constReg./r1) ) ...
./ ((inhi./r1) - (inlo./r1) + (constReg./r1));
slope = ((outhi./r2) - (outlo./r2)) ...
./ ((inhi./r3) - (inlo./r3) + (constReg./r3));
% assuming input is float
R = r2.*((slope./r3).*(B - sigma) + (r3./r2).*z);
% clamp output to output range
R = min(max(R,outlo),outhi);
fprintf('%.20f\n',R)
0.00000000000000011102 1.00000000000000000000

Sign in to comment.

Products


Release

R2022a

Community Treasure Hunt

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

Start Hunting!