-
-
Notifications
You must be signed in to change notification settings - Fork 33.2k
gh-124879: simplify colorsys.rgb_to_hsv
#124880
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
base: main
Are you sure you want to change the base?
Conversation
Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool. If this change has little impact on Python users, wait for a maintainer to apply the |
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.
Please provide performance data for both cases.
before |
I think Nikita wanted more relevant benchmarks such as using |
One factor to consider here is that in floating point operations, mathmatically equivalent does not guarantee the same result. This is not desicive but it introduces the possibility to break someone's test. This is a general issue for all the old but not deprecated libraries - people are using them, but we are not actively developing them. We need a strong motivation to change it, and a benchmark is persuasive. If the perf improvement is not observable, we should probably not risk it. |
In this specific case, it might be a bit hard to say whether we gain in numerical stability or not. But yes, I think that except for the nice reading improvement, historical numerical stability is probably better (so unless we really gain a performance, we shouldn't change this code) |
Trying to test just this line, there is actually a noticeable improvement.
|
Can we rather have the timings for the entire function? I think it would be easier to judge. In addition, is your build a debug/release or PGO/LTO/BOLT build? |
But no one calls this line only. |
import timeit
def rgb_to_hsv_old(r, g, b):
maxc = max(r, g, b)
minc = min(r, g, b)
rangec = (maxc-minc)
v = maxc
if minc == maxc:
return 0.0, 0.0, v
s = rangec / maxc
rc = (maxc-r) / rangec
gc = (maxc-g) / rangec
bc = (maxc-b) / rangec
if r == maxc:
h = bc-gc
elif g == maxc:
h = 2.0+rc-bc
else:
h = 4.0+gc-rc
h = (h/6.0) % 1.0
return h, s, v
def rgb_to_hsv_new(r, g, b):
maxc = max(r, g, b)
minc = min(r, g, b)
rangec = (maxc-minc)
v = maxc
if minc == maxc:
return 0.0, 0.0, v
s = rangec / maxc
if r == maxc:
h = (g-b) / rangec
elif g == maxc:
h = 2.0 + (b-r) / rangec
else:
h = 4.0 + (r-g) / rangec
h = (h/6.0) % 1.0
return h, s, v
nums = [x/100 for x in range(0,100)]
def test_old():
for r in nums:
for g in nums:
for b in nums:
rgb_to_hsv_old(r,g,b)
def test_new():
for r in nums:
for g in nums:
for b in nums:
rgb_to_hsv_new(r,g,b)
print('Old:',timeit.timeit(test_old,number=10))
print('New:',timeit.timeit(test_new,number=10))
|
stable release of 3.11.9 on Windows |
I can confirm a similar perf result on main. Also the hsv diff on the example is |
Even though this is a perf optimization, there is user observable behavior changes - the result is a "bit" (pun intended) different. You should at least include a news entry and we can ask for @sobolevn 's opinion on the change. |
@gaogaotiantian I am neutral :) Because |
Misc/NEWS.d/next/Library/2024-10-02-16-47-45.gh-issue-124879.9m2Wmx.rst
Outdated
Show resolved
Hide resolved
I remember @terryjreedy has reviewed(and declined) one of my PRs to |
…m2Wmx.rst Co-authored-by: Tian Gao <gaogaotiantian@hotmail.com>
minc = min(r, g, b) | ||
rangec = (maxc-minc) | ||
v = maxc | ||
if minc == maxc: |
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.
Does the function become faster for greyscale values if rangec = (maxc-minc)
is moved after the if check?
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.
surprisingly, no
Old: 6.133919600164518
New: 6.310812799958512
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.
Yes:
Old: 4.684144808999999
New: 4.411844383999999
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.
Strange, could you try running this?
import timeit
def rgb_to_hsv_old(r, g, b):
maxc = max(r, g, b)
minc = min(r, g, b)
rangec = (maxc-minc)
v = maxc
if minc == maxc:
return 0.0, 0.0, v
s = rangec / maxc
if r == maxc:
h = (g-b) / rangec
elif g == maxc:
h = 2.0 + (b-r) / rangec
else:
h = 4.0 + (r-g) / rangec
h = (h/6.0) % 1.0
return h, s, v
def rgb_to_hsv_new(r, g, b):
maxc = max(r, g, b)
minc = min(r, g, b)
v = maxc
if minc == maxc:
return 0.0, 0.0, v
rangec = (maxc-minc)
s = rangec / maxc
if r == maxc:
h = (g-b) / rangec
elif g == maxc:
h = 2.0 + (b-r) / rangec
else:
h = 4.0 + (r-g) / rangec
h = (h/6.0) % 1.0
return h, s, v
print('Old:',timeit.timeit(lambda: rgb_to_hsv_old(9,9,9),number=10_000_000))
print('New:',timeit.timeit(lambda: rgb_to_hsv_new(9,9,9),number=10_000_000))
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.
Old: 4.841873000143096
New: 4.7804170998279005
The arguments to rgb_to_hsv
are floats in the range [0,1] though, not integers.
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.
Yeah my bad, try with 0.5 then.
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.
Old: 4.947571000084281
New: 4.570939600002021
though with (0.2,0.5,0.7) I get
Old: 6.850879299920052
New: 6.9389673001132905
so it is faster when the numbers are the same, but slower when they aren't
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.
No, it's just random:
Old: 5.283142290998512
New: 5.288310900999932
By inlining some variables, the number of operations performed can be reduced. Example:
with
then
colorsys.rgb_to_hsv
#124879