Search code examples
pythondecimaldivisionreminders

The math calculations behind using (%, //) in python by applying (Decimal(), signed numbers )?


I was trying to understand the math behind calculations using / and // and % operators by doing some trials and found the results are similar to calculator only when using Decimal() but without it the results kinda confusing, i tried to add comments #No Ideato my code to mark the points i don't understand,for example:

  1. in this trial for % operator by applying signed and unsigned number the results and with and without Decimal() the results are :

    >>> 9%5    #This result will be the reminder
    4         
    >>> (-9)%5    #No Idea
    1
    >>> Decimal(9)% Decimal(5)    #This result will be the reminder
    Decimal('4')  
    >>> Decimal(-9)% Decimal(5)    #The result will be the signed reminder
    Decimal('-4')
    
  2. in this trial for // operator and using signed and unsigned number with and without Decimal() the results are :

    >>> 9//5    #int result
    1
    >>> -9//5    #No Idea
    -2
    >>> Decimal(9)/Decimal(5)    #Same result as using calculator
    Decimal('1.8')
    >>> Decimal(-9)//Decimal(5)    #No Idea
    Decimal('-1')
    

Please consider that this question is not a duplicate and i have done some research to get an answer but i found some answered questions that explain only about // operator using only positive signed numbers and doesn't include information about negative signed numbers or using the Decimal() and doesn't have answer about % operator.

so,It will be helpful if someone knows why the results are different and how they are calculated.


Solution

  • As I understand the question, the OP is asking about the different behavior between Python integers and Decimals. I don't think there is any good reason for it. Both choices are possible, but it is a bit confusing for the user that they differ.

    Let's call the numerator n, the denominator d and split the result in the interger result i and the remainder r. This means that

    n // d = i
    n % d = r
    

    For the operations to make sense, we need

    i * d + r == n
    

    For n = -9 and d = 5 we see that this is uphold for both i = -1, r = -4 and for i = -2, r = 1 as can be seen by

    (i = -1, r = -4) => -1 * 5 + -4 == -9
    (i = -2, r = 1) => -2 * 5 + 1 == -9
    

    Now, in Python integer division is defined as always truncate towards minus infinity (down) and the Decimal implementation has chosen to round towards zero. That means that positive values are truncated/rounded down, whereas negative values are rounded up.

    Rounding towards zero is the choice made also made in the C language. However, my personal opinion is that the Python choice is much more sane, specifically coming from a hardware background. And given that this is the choice made in Python, I think it is strange (and bad) that Decimal has chosen to do as in the C language.