How to implement separation with rounding to infinity in Python

I want 3/2 to be 2 not 1.5

I know there the mathematical term for this operation (not called rounding), but I can’t remember it right now. Anyway, how can I do this without having to perform two functions?

from what I DO NOT want:

answer = 3/2 then math.ceil(answer)=2 (why does math.ceil(3/2)=1?) 

ex of what i want:

  "function"(3/2) = 2 
+8
python math floating-point rounding division
source share
8 answers

To give a short answer ...

Python offers only native operators for two types of division: true division and rounding of division. So what you want is not available as a single function. However, using short expressions you can easily implement many different types of division with rounding.

According to the title request: when using strictly integer inputs, rounding can be implemented using (a+(-a%b))//b , and rounding from zero can be done using a more complex a//b if a*b<0 else (a+(-a%b))//b . One of them is probably what you want. As for why ...


To give a longer answer ...

First, let me answer the question of why math.ceil(3/2)==1.0 3/2==1 and math.ceil(3/2)==1.0 , explaining how the Python split operator works. There are two main problems in the game ...

float vs int division: In the Python 2 section, division behaves differently depending on the type of inputs. If both a and b are integers, a/b performs the rounding down or integer separation (for example, -3/2==-2 3/2==1 , but -3/2==-2 ). This is equivalent to int(math.floor(float(a)/b)) .

But if at least one of a and b is a float, Python does the “true” division and gives the result float (for example, 3.0/2==1.5 and -3.0/2==-1.5 ). This is why you sometimes see the float(a)/b construct: it is used to force true division, even if both inputs are integers (for example, float(3)/2==1.5 ). This is why your math.ceil(3/2) example returns 1.0 , while math.ceil(float(3)/2) returns 2.0 . The result is already rounded before it reaches math.ceil() .

true division by default . In 2001, it was decided ( PEP 238 ) that the Python division operator should be changed so that it always performs “true” division, regardless of whether the inputs are floats or integers (for example, this would make 3/2 3/2==1.5 ). In order not to break existing scripts, the default behavior change was delayed until Python 3.0; in order to get this behavior under Python 2.x, you must include it for each file by adding from __future__ import division to the top of the file. Otherwise, the old type-specific behavior is used.

But the “rounding” separation is still often necessary, so PEP has not completely dealt with it. Instead, he introduced a new division operator: a//b , which always performs rounded division, even if the inputs contain floats. This can be used without doing anything special under Python 2.2+ and 3.x.


Thus, division with rounding:

To simplify the work, all expressions use the a//b operator when working on integers, since it will behave the same in all versions of python. In addition, I make the assumption that 0<=a%b<b if b positive, and b<=a%b<=0 if b is negative. This is how Python behaves, but in other languages ​​there may be slightly different module statements.

Four main types of integer division with rounding:

  • "round down" aka "integer" aka "round to minus infinity" divsion: python offers this initially through a//b .

  • "round up" aka "ceiling integer", aka "rounding to positive infinity": this can be achieved using int(math.ceil(float(a)/b)) or (a+(-a%b))//b . The last equation works because -a%b is 0 if a is a multiple of b , and the rest is the sum that we need to add to a in order to move to the next largest edge.

  • "round to zero" , aka "truncated" separation - this can be achieved using int(float(a)/b) . Doing this without using a floating point is more complicated ... since Python only offers rounded integer rounding division, and the % operator has a similar rounding offset down, we have no floating point operators that are rounded symmetrically around 0. Therefore, the only way I can to think is to build a piecewise expression from rounding and rounding: a//b if a*b>0 else (a+(-a%b))//b .

  • “round off from zero aka round to (or) infinity” division - unfortunately, this is even more difficult than a round to zero. We can no longer use the shortening behavior of the int operator, so I cannot come up with a simple expression even when using floating point operations. Therefore, I have to go back to the round expression and use a//b if a*b<0 else (a+(-a%b))//b .

Please note that if you use only positive integers, (a+b-1)//b provides rounding up / from zero even more efficiently than any of the above solutions, but falls apart into negatives.

Hope this helps ... and am happy to make a change if anyone can suggest the best equations for a round to / from zero. I find those that I have especially unsatisfactory.

+16
source share

Integral division in Python 3:

3 // 2 == 1

Integer division in Python 3:

3 / 2 == 1.5

What you are talking about is not division by all means.

+5
source share

The goal of the OP question "How to implement separation with rounding to infinity in Python" (I propose to change the name).

This is a completely legal rounding mode in accordance with the IEEE-754 standard (read this review ), and the term for it is "rounded to infinity" (or "rounded from zero"). Most of the 9 downvotes beat on the OP unfairly. Yes, in native Python there is no single-function way, but we can use round(float(a)/b) or a subclass of numbers.Number and override __div__() .

The OP will need to clarify whether they want to round -3/2 to -2 or -1 (or not worry about negative operands). Since they already said that they do not want to round up, we can assume that -3/2 should round to -2.

Sufficient theory. For implementations:

  • If you just need a quick and dirty single-line solution for round-to-infinity, use round(float(a)/b)
  • math.ceil(float(a)/b) gives you a round up and you said you didn't want

  • But if this is your default default operation, or you do a lot of it, then do, for example, the pseudocode below: inherit from one of the subclasses of numbers.Number Real, Rational or Integral (new in version 2.6) , override __div__() or define an alternative __divra__() is the default operation. You can define a class member or classmethod rounding_mode and see it during the division. Be careful with __rdiv__() and mix with regular floats.

.

 import numbers class NumberWithRounding(numbers.Integral): # Here you could implement a classmethod setRoundingMode() or member rounding_mode def __div__(self,other): # here you could consider value of rounding_mode, or else hardwire it like: return round(float(self)/other) # You also have to raise ImplementationError/ pass/ or implement the other 31 # methods for Float: __abs__(),...,__xor__() Just shortcut that for now... 
+4
source share

When you divide two integers, the result will be an integer.
3 / 2 is 1 , not 1.5 .
See documentation , note 1:

For (simple or long) integer division, the result is an integer. The result is always rounded to minus infinity: 1/2 is 0, (-1) / 2 is -1, 1 / (- 2) is -1, and (-1) / (- 2) is 0. Note that the result is a long integer if either the operand is a long integer, regardless of the numerical value.

Once you get 1 from the division, there is no way to include it in 2 .

To get 1.5 , you will need floating point division: 3.0 / 2 .
Then you can call math.ceil to get 2 .

You are wrong; There is no mathematical function that divides, then rounds.
The best you can do is write your own function that takes two floats and calls math.ceil .

+2
source share

What you might want is something like:

 math.ceil(3.0/2.0) # or math.ceil(float(3)/float(2)) 

You can also import from the future:

 from __future__ import division math.ceil(3/2) # == 2 

But if you do this to get the current behavior of integer division, you need to use a double slash:

 3 // 2 == 1 # True 
+1
source share

I think you are looking for the following:

assuming you have x (3) and y (2),

result = (x + y - 1) // y;

it is the equivalent of a ceiling without the use of floating points.

Of course, y cannot be 0.

+1
source share

Integer division with ceiling rounding (up to + Inf), floor rounding (up to -Inf) and truncation (up to 0) are available in gmpy2.

 >>> gmpy2.c_div(3,2) mpz(2) >>> help(gmpy2.c_div) Help on built-in function c_div in module gmpy2: c_div(...) c_div(x,y): returns the quotient of x divided by y. The quotient is rounded towards +Inf (ceiling rounding). x and y must be integers. >>> help(gmpy2.f_div) Help on built-in function f_div in module gmpy2: f_div(...) f_div(x,y): returns the quotient of x divided by y. The quotient is rounded towards -Inf (floor rounding). x and y must be integers. >>> help(gmpy2.t_div) Help on built-in function t_div in module gmpy2: t_div(...) t_div(x,y): returns the quotient of x divided by y. The quotient is rounded towards 0. x and y must be integers. >>> 

gmpy2 is available at http://code.google.com/p/gmpy/

(Disclaimer: I am the current one supporting gmpy and gmpy2.)

+1
source share

First, you want to use floating point division in the arguments. Using:

 from __future__ import division 

If you always want to round, then f(3/2)==2 and f(1.4)==2 , then you want f be math.trunc(math.ceil(x)) .

If you want to get the nearest integer, but you have ties, then you want math.trunc(x + 0.5) . Thus f(3/2)==2 and f(1.4)==1 .

0
source share

All Articles