Skip to content

Ceil division with /// operator #87421

Closed
Closed

Description

@PedanticHacker
BPO 43255
Nosy @tim-one, @rhettinger, @mdickinson, @vstinner, @serhiy-storchaka, @PedanticHacker, @nathanielmanistaatgoogle

Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

Show more details

GitHub fields:

assignee = None
closed_at = <Date 2021-02-18.15:00:41.696>
created_at = <Date 2021-02-18.14:18:04.452>
labels = ['type-feature', 'library', '3.10']
title = 'Ceil division with /// operator'
updated_at = <Date 2022-02-04.19:31:00.211>
user = 'https://github.com/PedanticHacker'

bugs.python.org fields:

activity = <Date 2022-02-04.19:31:00.211>
actor = 'Nathaniel Manista'
assignee = 'none'
closed = True
closed_date = <Date 2021-02-18.15:00:41.696>
closer = 'vstinner'
components = ['Library (Lib)']
creation = <Date 2021-02-18.14:18:04.452>
creator = 'PedanticHacker'
dependencies = []
files = []
hgrepos = []
issue_num = 43255
keywords = []
message_count = 10.0
messages = ['387231', '387236', '387237', '387248', '387264', '387267', '387268', '387269', '387270', '387325']
nosy_count = 7.0
nosy_names = ['tim.peters', 'rhettinger', 'mark.dickinson', 'vstinner', 'serhiy.storchaka', 'PedanticHacker', 'Nathaniel Manista']
pr_nums = []
priority = 'normal'
resolution = 'rejected'
stage = 'resolved'
status = 'closed'
superseder = None
type = 'enhancement'
url = 'https://bugs.python.org/issue43255'
versions = ['Python 3.10']

Activity

  1. PedanticHacker commented on Feb 18, 2021

    PedanticHackermannequin
    MannequinAuthor

    I hope I'm not too late for a Python 3.10 feature request. I love the fact that Python 3.x does floor division with the // operator.

    We, however, don't have a ceil division operator, besides importing the math module and using its math.ceil() function.

    Is it possible we have /// as a ceil division operator in Python 3.10?

    I just wanted to put this thought out of my head if anyone becomes entertained by this idea.

  2. added
    stdlibStandard Library Python modules in the Lib/ directory
    type-featureA feature request or enhancement
    on Feb 18, 2021
  3. serhiy-storchaka commented on Feb 18, 2021

    @serhiy-storchaka
    Member

    Since adding new operator is a syntax-level change, it needs a PEP. It is better to start with discussing on the Python-ideas mailing list (https://mail.python.org/mailman3/lists/python-ideas.python.org/). Let's see if this idea will be accepted favorably.

    BTW, the ceiling division can be expressed as -(-a // b) or -(a // -b).

  4. vstinner commented on Feb 18, 2021

    @vstinner
    Member

    I'm not convinced that this operation is so common that it deserves a new operator. As Serhiy wrote, it must be first on python-ideas first. I close the issue.

    --

    floor division is x//y

    integer ceil division can be implemented with math.ceil(x/y) for small numbers.

    For large integer numbers, I like to use something like:

    def ceil_div(x, y):
        rem=x % y
        if rem:
            x += y - rem
        return x//y

    I let you adjust it for negative numbers ;-)

  5. mdickinson commented on Feb 18, 2021

    @mdickinson
    Member

    I can't recall where I saw this originally, but you can use the spaceship operator "--0--" to turn floor division into ceiling division:

    >>> 12//5
    2
    >>> --0-- 12//5
    3

    There's also the ++0++ operator when you want to emphasize that you really *do* mean floor division:

    >>> ++0++ 12//5
    2

    But yes, -(-n // d) is the easy (if a little bit cryptic) way to get the ceiling of n / d.

  6. PedanticHacker commented on Feb 18, 2021

    PedanticHackermannequin
    MannequinAuthor

    The spaceship operator is kinda cool! :)

    Well, I was hoping to avoid importing the math module just to have ceil division capabilities.

    Anyway, my need for ceiling is that I am coding a chess GUI where I have a table with 2 columns and I create a new row whenever White makes a move. So, my implementation for row creation is math.ceil(len(moves) // 2) where moves is a list of chess moves.

    So, the sequence of table rows after White and Black make their moves is initially 0 (since there are no moves yet) and then 1 (first row created after White made a move) and then 1 (again on row 1 after Black made a move, but on column 2), then 2 2 3 3 4 4 5 5 6 6 and so on.

    If we had the ceil operator in Python, I could do: len(moves) /// 2 :)

    By the way -- do you happen to know any better idea to get that kind of a sequence? That is 0 1 1 2 2 3 3 4 4 5 5 6 6 and so on.

  7. tim-one commented on Feb 18, 2021

    @tim-one
    Member

    (len(moves) + 1) // 2

  8. vstinner commented on Feb 18, 2021

    @vstinner
    Member

    Anyway, my need for ceiling is that I am coding a chess GUI where I have a table with 2 columns and I create a new row whenever White makes a move. So, my implementation for row creation is math.ceil(len(moves) // 2) where moves is a list of chess moves.

    You may like the new int.bit_count() attribute of Python 3.10 ;-)
    https://docs.python.org/dev/library/stdtypes.html#int.bit_count

  9. PedanticHacker commented on Feb 18, 2021

    PedanticHackermannequin
    MannequinAuthor

    My hat off to you, Mr. Peters! Your suggestion (len(moves) + 1) // 2 works perfectly and is much more elegant than --0-- len(moves) // 2. :)

    Mr. Stinner, in what way would int.bit_count() be beneficial to me?

  10. vstinner commented on Feb 18, 2021

    @vstinner
    Member

    Mr. Stinner, in what way would int.bit_count() be beneficial to me?

    I found https://www.chessprogramming.org/Population_Count when I investigated the C implementation of _Py_popcount32(), which is used by int.bit_count().

    I read it when I tried to document this surprising code:
    ---

    x = x - ((x >> 1) & 0x55555555);
    x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
    x = (x + (x >> 4)) & 0x0F0F0F0F;
    return (uint32_t)((uint64_t)x * (uint64_t)0x01010101) >> 24;

    I reformatted it as:
    ---
    // 32-bit SWAR (SIMD Within A Register) popcount

    // Binary: 0 1 0 1 ...
    const uint32_t M1 = 0x55555555;
    // Binary: 00 11 00 11. ..
    const uint32_t M2 = 0x33333333;
    // Binary: 0000 1111 0000 1111 ...
    const uint32_t M4 = 0x0F0F0F0F;
    // 256**4 + 256**3 + 256**2 + 256**1
    const uint32_t SUM = 0x01010101;
    
    // Put count of each 2 bits into those 2 bits
    x = x - ((x >> 1) & M1);
    // Put count of each 4 bits into those 4 bits
    x = (x & M2) + ((x >> 2) & M2);
    // Put count of each 8 bits into those 8 bits
    x = (x + (x >> 4)) & M4;
    // Sum of the 4 byte counts
    return (uint32_t)((uint64_t)x * (uint64_t)SUM) >> 24;
    

    ---

  11. PedanticHacker commented on Feb 19, 2021

    PedanticHackermannequin
    MannequinAuthor

    Mr. Stinner, I really don't understand what are you hinting at.

  12. transferred this issue fromon Apr 10, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.10 (EOL)end of lifestdlibStandard Library Python modules in the Lib/ directorytype-featureA feature request or enhancement

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions