31

I have two values (previous and current) and I want to check change between them (in percent):

(current/previous)*100

But if the previous value is 0 I get Division By Zero, and if value will not change I get 100%.

Mureinik
  • 297,002
  • 52
  • 306
  • 350
Nips
  • 13,162
  • 23
  • 65
  • 103
  • 4
    If the previous value is zero and the current value is nonzero then you can't meaningfully calculate the change as a proportion of the old value; that's a general mathematical principle that has nothing in particular to do with programming. – Hammerite Jun 18 '15 at 22:29
  • If you want the percentage of change ("X% bigger") rather than an absolute comparison ("current is X% of previous"), you need to do `(current/previous)*100 - 100`. Of course, this still won't let you divide by zero. – TigerhawkT3 Jun 18 '15 at 22:35
  • if `current == previous` doesn't that indicate 0% change rather than 100%? If it changes from 100 to 80, is that 20% or 80% in your use case? – krethika Jun 18 '15 at 22:45
  • Yes, as the OP states, they're getting 100% when the value doesn't change, and they don't want that. I think for 100 to 80 they would want -20%, which would require the snippet I mentioned above. – TigerhawkT3 Jun 18 '15 at 22:54
  • I'm voting to close this question as off-topic because it is about arithmetic, not about programming. – High Performance Mark Jun 19 '15 at 15:17

9 Answers9

45
def get_change(current, previous):
    if current == previous:
        return 100.0
    try:
        return (abs(current - previous) / previous) * 100.0
    except ZeroDivisionError:
        return 0

Edit: some have commented that OP was describing a problem with the current code, not asking for this behavior, thus here is an example where, "if the current is equal to previous, there is no change. You should return 0". Also I've made the method return Infinity if the previous value was 0, as there can be no real percentage change when the original value is 0.

  def get_change(current, previous):
    if current == previous:
        return 0
    try:
        return (abs(current - previous) / previous) * 100.0
    except ZeroDivisionError:
        return float('inf')
Matt
  • 5,028
  • 2
  • 28
  • 55
  • 3
    If current is equal to previous, there is no change. You should return 0. – Mureinik Jun 19 '15 at 07:47
  • According to the question asked "if value will not change I get 100%." – Matt Jun 19 '15 at 16:03
  • 3
    OP was describing a problem in his current code, not asking for this behavior. – Mureinik Jun 19 '15 at 16:17
  • Should it not be: `return (abs(current - previous) / current ) * 100.0` – ascendedcrow Feb 07 '22 at 13:41
  • @ascendedcrow Take for example a change from the values of `1` to `2`, the current response gives a response of `100` which makes sense if a value has doubled it has changed 100%, but if we implemented it with the `current` as the denominator it would give a response of `50` but a doubling is not a 50% change. – Matt Feb 07 '22 at 16:39
  • @Matt Yeah, you are correct...I confused myself...where I thought if the current is 100 previous is 80...it goes down with 20%...which is not true...it will go down with 25% and that makes this `(abs(current - previous) / previous) * 100.0` correct – ascendedcrow Feb 08 '22 at 18:31
  • This is totaly wrong its like this **percentage = abs(previous - current)/((previous + current)/2) * 100** – Haseeb Mir Apr 10 '22 at 07:46
  • @HaseeBMir take for example a change from 10 to 15. To me that is clearly a 50% increase and that is what is returned by the above algorithm; but if we take your algorithm (5/12.5) * 100 = 40%. If someone says they had a change of 40% from 10 you'd expect the answer to be 14 not 15. – Matt Apr 15 '22 at 15:54
13

You need to divide the change (current-previous) by the previous, not just the current. So, to make a long story short:

change_percent = ((float(current)-previous)/previous)*100

Note that if previous is 0 you cannot calculate the change in percentage (regardless of the python implementation)

Mureinik
  • 297,002
  • 52
  • 306
  • 350
  • this wont work with all values, try current = 78752 and previous = 39408 I guess its due to rounding. – Sven van den Boogaart Dec 01 '17 at 13:23
  • @SvenvandenBoogaart not rounding, but [integer division](https://en.wikipedia.org/wiki/Division_(mathematics)#Of_integers). My edit should fix the issue. – Mureinik Dec 01 '17 at 14:00
10
def get_percentage_diff(previous, current):
    try:
        percentage = abs(previous - current)/max(previous, current) * 100
    except ZeroDivisionError:
        percentage = float('inf')
    return percentage

This is a better way i discovered.

only covers under 100% diffs. if there is more than 100 percent increase this solution fails

ruhi dağdelen
  • 161
  • 1
  • 8
4

You should divide by the absolute value of the previous number. If the previous number is negative and the current number is negative you will get an erroneous result if you don't use the absolute value in the denominator. For example if your current number is -6 and previous number is -5:

(-6 - (-5)) / -5 = 

(-6 + 5) / -5 =  

-1 / -5 = 20 %

which is clearly false because the percentage change in this case should be negative -6 < -5. So use the function below:

def percentage_change(current, previous):
    if previous != 0 :
        return float(current - previous) / abs(previous) * 100
    else:
        return "undefined"

Keep in mind that if your previous number is zero division by zero is undefined: https://en.wikipedia.org/wiki/Division_by_zero

Also you shouldn't use the absolute value of the nominator instead of the denominator. Here is an example why:

previous value: -5

current value: -4

| (-4 - (-5)) | / -5 = 
| (-4 + 5) | / -5 =  
|1| / -5 = 
1 / -5 = -20%

which is false because -4 > -5

Correct:

(-4 - (-5)) / | -5 | = 
(-4 + 5) / | -5 | =  
1 / 5 = 20%

Reference: https://www.calculatorsoup.com/calculators/algebra/percent-change-calculator.php

Taterhead
  • 5,763
  • 4
  • 31
  • 40
Nikos Tavoularis
  • 2,843
  • 1
  • 30
  • 27
3

To cover all cases of zeroes, you could use ternary operators in your statement

(current - previous) / previous * 100.0 if previous != 0 else float("inf") * abs(current) / current if current != 0 else 0.0
Blair
  • 6,623
  • 1
  • 36
  • 42
2

I use this

  def pct_change(first, second):
    diff = second - first
    change = 0
    try:
        if diff > 0:
            change = (diff / first) * 100
        elif diff < 0:
            diff = first - second
            change = -((diff / first) * 100)
    except ZeroDivisionError:
        return float('inf')
    return change
Caner
  • 1,448
  • 23
  • 38
0

This is to correct answer taking formula from this website:

def get_percentage_diff(previous, current):
    try:
        percentage = abs(previous - current)/((previous + current)/2) * 100
    except ZeroDivisionError:
        percentage = float('inf')
    return percentage
    
difference = get_percentage_diff(500,1750)

Output: 111.111% difference

Haseeb Mir
  • 928
  • 1
  • 13
  • 22
0

My solution:

def find_difference(a, b):
    return ((abs(a - b)) / ((a + b) / 2)) * 100
Magomed Shamaev
  • 198
  • 2
  • 5
-1

The most optimized way will be this I guess

def percentage_change(current,previous):
    if current and previous !=0:
       return round((current/previous)-1*100,2)
Awais khan
  • 37
  • 6