Make division by zero equal to zero

How can I ignore ZeroDivisionError and make n / 0 == 0?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

Check if the denominator is zero before dividing. This avoids the overhead of catching the exception, which may be more efficient if you expect to be dividing by zero a lot.

def weird_division(n, d):
    return n / d if d else 0

Method 2

You can use a try/except block for this.

def foo(x,y):
    try:
        return x/y
    except ZeroDivisionError:
        return 0

>>> foo(5,0)
0

>>> foo(6,2)
3.0

Method 3

I think try except (as in Cyber’s answer) is usually the best way (and more pythonic: better to ask forgiveness than to ask permission!), but here’s another:

def safe_div(x,y):
    if y == 0:
        return 0
    return x / y

One argument in favor of doing it this way, though, is if you expect ZeroDivisionErrors to happen often, checking for 0 denominator ahead of time will be a lot faster (this is python 3):

import time

def timing(func):
    def wrap(f):
        time1 = time.time()
        ret = func(f)
        time2 = time.time()
        print('%s function took %0.3f ms' % (f.__name__, int((time2-time1)*1000.0)))
        return ret
    return wrap

def safe_div(x,y):
    if y==0: return 0
    return x/y

def try_div(x,y):
    try: return x/y
    except ZeroDivisionError: return 0

@timing
def test_many_errors(f):
    print("Results for lots of caught errors:")
    for i in range(1000000):
        f(i,0)

@timing
def test_few_errors(f):
    print("Results for no caught errors:")
    for i in range(1000000):
        f(i,1)

test_many_errors(safe_div)
test_many_errors(try_div)
test_few_errors(safe_div)
test_few_errors(try_div)

Output:

Results for lots of caught errors:
safe_div function took 185.000 ms
Results for lots of caught errors:
try_div function took 727.000 ms
Results for no caught errors:
safe_div function took 223.000 ms
Results for no caught errors:
try_div function took 205.000 ms

So using try except turns out to be 3 to 4 times slower for lots of (or really, all) errors; that is: it is 3 to 4 times slower for iterations that an error is caught. The version using the if statement turns out to be slightly slower (10% or so) when there are few (or really, no) errors.

Method 4

Solution

When you want to efficient handle ZeroDivisionError (division by zero) then you should not use exceptions or conditionals.

result = b and a / b or 0  # a / b

How it’s works?

  • When b != 0 we have True and a / b or 0. True and a / b is equal to a / b. a / b or 0 is equal to a / b.
  • When b == 0 we have False and a / b or 0. False and a / b is equal to False. False or 0 is equal to 0.

Benchmark

Timer unit: 1e-06 s

Total time: 118.362 s
File: benchmark.py
Function: exception_div at line 3

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
     3                                           @profile
     4                                           def exception_div(a, b):
     5 100000000   23419098.5      0.2     19.8      try:
     6 100000000   40715642.9      0.4     34.4          return a / b
     7 100000000   28910860.8      0.3     24.4      except ZeroDivisionError:
     8 100000000   25316209.7      0.3     21.4          return 0

Total time: 23.638 s
File: benchmark.py
Function: conditional_div at line 10

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    10                                           @profile
    11                                           def conditional_div(a, b):
    12 100000000   23638033.3      0.2    100.0      return a / b if b else 0

Total time: 23.2162 s
File: benchmark.py
Function: logic_div at line 14

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    14                                           @profile
    15                                           def logic_div(a, b):
    16 100000000   23216226.0      0.2    100.0      return b and a / b or 0

Method 5

def foo(x, y):
    return 0 if y == 0 else x / y

Method 6

I think if you don’t want to face Zer0DivErrr, you haven’t got to wait for it or go through it by using try-except expression. The quicker way is to jump over it by making your code simply not to do division when denominator becomes zero:

(if Y Z=X/Y else Z=0)

Method 7

You can use the following :

x=0,y=0
print (y/(x or not x))

Output:

>>>x=0
>>>y=0
>>>print(y/(x or not x))
0.0
>>>x =1000
>>>print(y/(x or not x))
0.000999000999000999

not x will be false if x is not equal to 0, so at that time it divides with actual x.

Method 8

If you are trying to divide two integers you may use :

if y !=0 :
   z = x/y
else:
    z = 0

or you can use :

z = ( x / y ) if y != 0 else 0

If you are trying to divide two lists of integers you may use :

z = [j/k if k else 0 for j, k in zip(x, y)]

where here, x and y are two lists of integers.

Method 9

I was intrigued why ToTomire‘s solution would be faster. If feels like conditional_div should often be preferred for its natural language readability, but if I can understand exactly why logic_div is faster that might help me in the future. I looked to python’s dis for this.

>>> conditional_div = lambda n,d: n/d if d else 0
>>> logic_div = lambda n,d: d and n/d or 0
>>> dis.dis(conditional_div)
  1           0 LOAD_FAST                1 (d)
              2 POP_JUMP_IF_FALSE       12
              4 LOAD_FAST                0 (n)
              6 LOAD_FAST                1 (d)
              8 BINARY_TRUE_DIVIDE
             10 RETURN_VALUE
        >>   12 LOAD_CONST               1 (0)
             14 RETURN_VALUE
>>> dis.dis(logic_div)
  1           0 LOAD_FAST                1 (d)
              2 POP_JUMP_IF_FALSE       12
              4 LOAD_FAST                0 (n)
              6 LOAD_FAST                1 (d)
              8 BINARY_TRUE_DIVIDE
             10 JUMP_IF_TRUE_OR_POP     14
        >>   12 LOAD_CONST               1 (0)
        >>   14 RETURN_VALUE

And it appears that logic_div should actually have an extra step. Up to ‘8’ the two bytecodes are identical. At ’10’ conditional_div would just return a value whereas logic_div has to do a jump if its true and then return. Perhaps the alternative ..._OR_POP is faster than returning so some percent of the time it has a shorter last step? But the only way that ..._OR_POP would be activated is if the numerator were zero and the denominator non-zero. Both bytecodes take the same route when the denominator is zero. This doesn’t feel like a satisfying conclusion. Maybe someone can explain if I’m misunderstanding something.

For reference

>>> sys.version
'3.9.6 (tags/v3.9.6:db3ff76, Jun 28 2021, 15:26:21) [MSC v.1929 64 bit (AMD64)]'


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x