Make division by zero equal to zero

Question:

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

Asked By: octosquidopus

||

Answers:

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
Answered By: Cory Kramer

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
Answered By: davidism

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.

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

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)
Answered By: Vynylyn

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.

Answered By: Saurav Panda

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.

Answered By: my shark

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
Answered By: ToTamire

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)]'
Answered By: jbf81tb

Yet another way:

def safe_division(numerator, denominator):
    """Return 0 if denominator is 0."""
    return denominator and numerator / denominator

and returns either zero denominator or the result of the division.

Bytecode:

In [51]: dis(safe_division)
 25           0 LOAD_FAST                1 (denominator)
              2 JUMP_IF_FALSE_OR_POP     5 (to 10)
              4 LOAD_FAST                0 (numerator)
              6 LOAD_FAST                1 (denominator)
              8 BINARY_TRUE_DIVIDE
        >>   10 RETURN_VALUE

Zero denominator removes the need to load zero with LOAD_CONST.

Answered By: Maxim Egorushkin
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.