-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix UnderflowError in _try_rescale_float when maxVal == 0. #2881
base: master
Are you sure you want to change the base?
Conversation
Fix UnderflowError in _try_rescale_float when maxVal == 0.
@@ -640,7 +640,7 @@ def _try_rescale_float(self, image, levels, lut): | |||
|
|||
minVal, maxVal = levels | |||
if minVal == maxVal: | |||
maxVal = xp.nextafter(maxVal, 2*maxVal) | |||
maxVal = xp.nextafter(maxVal, 2*maxVal) if maxVal != 0 else numpy.finfo(maxVal).eps |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a dumb question:
Is it actually intentional that the existing code moves maxval
to the next more negative number when maxval
is already < 0? That makes rng
negative below, and that seems conceptually a little strange.
If the intention is to clamp rng
to a small positive number, then wouldn't
maxVal = math.nextafter( minVal, math.inf )
be what we want? (under all variations of maxVal <0 / ==0 / > 0)
Additional comment:
if minVal
and maxVal
are just simple numbers, then there's probably no need to potentially invoke the cupy version of nextafter here. I suspect that nextafter
from the math library should be enough.
@@ -640,7 +640,7 @@ def _try_rescale_float(self, image, levels, lut): | |||
|
|||
minVal, maxVal = levels | |||
if minVal == maxVal: | |||
maxVal = xp.nextafter(maxVal, 2*maxVal) | |||
maxVal = xp.nextafter(maxVal, 2*maxVal) if maxVal != 0 else numpy.finfo(maxVal).eps | |||
rng = maxVal - minVal | |||
rng = 1 if rng == 0 else rng |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This (pre-existing) line seems redundant if the code above works as intended. If it is indeed still needed, then there's a kind of problem that gets past the check minVal == maxVal
... Possibly something originating from mixed or non-float datatypes?
Is the real thing we want to avoid float(maxval - minval) == 0
? Then the most robust path might be to directly check that. Something like
rng = float(maxVal - minVal)
if rng == 0.:
maxVal = math.nextafter( minVal, math.inf )
rng = float(maxVal - minVal)
maybe?
The code chunk actually comes from pyqtgraph/pyqtgraph/functions.py Lines 1441 to 1462 in 21391e0
Back then, the goal was to make the code behave the same as makeARGB() .
I would replace it with the following: minVal, maxVal = levels
# if minVal == maxVal:
# maxVal = xp.nextafter(maxVal, 2*maxVal)
rng = maxVal - minVal
rng = 1 if rng == 0 else rng The goal is simply to avoid a division by zero shortly after. This simple pattern can be found in:
|
Well, that looks like a dramatic reduction in complexity! And unless I am missing some side effect in the rescale functions, the exact value of the combined scaling factor |
I belive the issue this PR was meant to address is now addressed in #2944 ? |
In ImageItem.py, an UnderflowError exception is thrown in _try_rescale_float by numpy.nextafter() if the histogram levels minVal and maxVal are both 0. This PR fixes the problem by instead setting maxVal to the machine precision if maxVal is 0.
Tested and verified to resolve the issue without introducing new ones.