def max_chunk_size(mem_bytes):
    """Determine maximum chunk size for use with given ammount of memory.

    :param mem_bytes: size of available memory in bytes. This might mean different things
     depending on for what computation method the chunk_size is being computed but the
     bottom line is: this is the ammount of memory that we are able to use
    :type mem_bytes: int
    :returns: maximum chunk size as a exponent determining part of search spaced sweep
     during a single iteration. More precisely, if the returned value is `m` then
     2 ** `m` states can be searched during a single pass of the algorithm (and this is
     a maximal such exponent `m` that can be used).
    :rtype: int
    """
    elements_max = mem_bytes // 16 // 2
    chunk_size = 0
    while elements_max > 1:
        elements_max >>= 1
        chunk_size += 1
    if 2 * 16 * 2 ** chunk_size + 1024 * 1024 * 1024 > mem_bytes:
        chunk_size -= 1
    return chunk_size
