`not not x` much faster than `bool(x)`

Before the introduction of bool and also in other languages, `not not x` was/is used to convert to True (1) and False (0). However, the old way is still much faster than bool(x) or even operator.truth(x). Test:
py -3.10 -m timeit -s "objects = 1, 0, -0.0, "20", "False", 93, 28.569, [], set(), {1: 5}" "[(not not x) for x in objects]" 200000 loops, best of 5: 1.12 usec per loop py -3.10 -m timeit -s "objects = 1, 0, -0.0, "20", "False", 93, 28.569, [], set(), {1: 5}" "[(bool(x)) for x in objects]" 200000 loops, best of 5: 2.32 usec per loop py -3.10 -m timeit -s "from operator import truth; objects = 1, 0, -0.0, "20", "False", 93, 28.569, [], set(), {1: 5}" "[(truth(x)) for x in objects]" 200000 loops, best of 5: 2.04 usec per loop py -3.10 -V Python 3.10.0rc1
That's nearly 52%/46% faster! I guess the name lookup and the FUNCTION_CALL is slower than UNARY_NOT. So actually, using `not not` is an optimize, although it isn't clear. This is interesting.

On Fri, Aug 6, 2021 at 5:31 PM <wyz23x2@163.com> wrote:
Before the introduction of bool and also in other languages, `not not x` was/is used to convert to True (1) and False (0). However, the old way is still much faster than bool(x) or even operator.truth(x). Test:
py -3.10 -m timeit -s "objects = 1, 0, -0.0, "20", "False", 93, 28.569, [], set(), {1: 5}" "[(not not x) for x in objects]" 200000 loops, best of 5: 1.12 usec per loop py -3.10 -m timeit -s "objects = 1, 0, -0.0, "20", "False", 93, 28.569, [], set(), {1: 5}" "[(bool(x)) for x in objects]" 200000 loops, best of 5: 2.32 usec per loop py -3.10 -m timeit -s "from operator import truth; objects = 1, 0, -0.0, "20", "False", 93, 28.569, [], set(), {1: 5}" "[(truth(x)) for x in objects]" 200000 loops, best of 5: 2.04 usec per loop py -3.10 -V Python 3.10.0rc1
That's nearly 52%/46% faster! I guess the name lookup and the FUNCTION_CALL is slower than UNARY_NOT. So actually, using `not not` is an optimize, although it isn't clear. This is interesting.
Interesting perhaps, but not really surprising. Name lookups and function calls aren't as fast as operators. But why is this on python-ideas? ChrisA

I thought that many places in stdlib could be made faster by this (bool is used a lot), maybe this is a major speedup.

how does it compare with the old: ``` def rh(ham, _bool=bool): return _bool(ham) ```

On Fri, Aug 06, 2021 at 08:29:03AM -0000, wyz23x2@163.com wrote:
I thought that many places in stdlib could be made faster by this (bool is used a lot), maybe this is a major speedup.
I doubt that there are many places in the stdlib where the call to bool is the bottleneck, and a micro-optimization of avoiding the function call would make it a "major speedup". If you profile the stdlib modules, do you find any where calls to bool make up a major part of the run time cost? -- Steve

06.08.21 10:29, wyz23x2@163.com пише:
Before the introduction of bool and also in other languages, `not not x` was/is used to convert to True (1) and False (0). However, the old way is still much faster than bool(x) or even operator.truth(x). Test:
py -3.10 -m timeit -s "objects = 1, 0, -0.0, "20", "False", 93, 28.569, [], set(), {1: 5}" "[(not not x) for x in objects]" 200000 loops, best of 5: 1.12 usec per loop py -3.10 -m timeit -s "objects = 1, 0, -0.0, "20", "False", 93, 28.569, [], set(), {1: 5}" "[(bool(x)) for x in objects]" 200000 loops, best of 5: 2.32 usec per loop py -3.10 -m timeit -s "from operator import truth; objects = 1, 0, -0.0, "20", "False", 93, 28.569, [], set(), {1: 5}" "[(truth(x)) for x in objects]" 200000 loops, best of 5: 2.04 usec per loop py -3.10 -V Python 3.10.0rc1
That's nearly 52%/46% faster! I guess the name lookup and the FUNCTION_CALL is slower than UNARY_NOT. So actually, using `not not` is an optimize, although it isn't clear. This is interesting.
I got very different results on Linux (optimized build). bool() and truth() are only 18%/32% slower in 3.10. In 3.9 it is 88%/28% slower. Calling a constructor in general is slower that calling a simple builtin function, but some constructors, including the bool constructor, were optimized in 3.10. What surprised me is that bool() is faster than truth(). I have no other explanation of this except that it may be a compiler glitch. The compiler can randomly optimize some parts of code at the expense of others. Microbenchmarking results are unreliable in these cases.
participants (5)
-
Chris Angelico
-
Serhiy Storchaka
-
Steven D'Aprano
-
Thomas Grainger
-
wyz23x2@163.com