Вопрос о round_up макросе

A CyclicBarrier можно использовать повторно, так что это больше похоже на гоночный тур, где все встречаются в путевой точке, прежде чем перейти к следующему этапу тура.

12
задан lillq 2 September 2009 в 03:13
поделиться

5 ответов

The ROUND_UP macro is relying on integer division to get the job done. It will only work if both parameters are integers. I'm assuming that N is the number to be rounded and S is the interval on which it should be rounded. That is, ROUND_UP(12, 5) should return 15, since 15 is the first interval of 5 larger than 12.

Imagine we were rounding down instead of up. In that case, the macro would simply be:

#define ROUND_DOWN(N,S) ((N / S) * S)

ROUND_DOWN(12,5) would return 10, because (12/5) in integer division is 2, and 2*5 is 10. But we're not doing ROUND_DOWN, we're doing ROUND_UP. So before we do the integer division, we want to add as much as we can without losing accuracy. If we added S, it would work in almost every case; ROUND_UP(11,5) would become (((11+5) / 5) * 5), and since 16/5 in integer division is 3, we'd get 15.

The problem comes when we pass a number that's already rounded to the multiple specified. ROUND_UP(10, 5) would return 15, and that's wrong. So instead of adding S, we add S-1. This guarantees that we'll never push something up to the next "bucket" unnecessarily.

The PAGE_ macros have to do with binary math. We'll pretend we're dealing with 8-bit values for simplicity's sake. Let's assume that PAGE_SIZE is 0b00100000. PAGE_SIZE-1 is thus 0b00011111. ~(PAGE_SIZE-1) is then 0b11100000.

A binary & will line up two binary numbers and leave a 1 anywhere that both numbers had a 1. Thus, if x was 0b01100111, the operation would go like this:

  0b01100111  (x)
& 0b11100000  (~(PAGE_SIZE-1))
------------
  0b01100000

You'll note that the operation really only zeroed-out the last 5 bits. That's all. But that was exactly that operation needed to round down to the nearest interval of PAGE_SIZE. Note that this only worked because PAGE_SIZE was exactly a power of 2. It's a bit like saying that for any arbitrary decimal number, you can round down to the nearest 100 simply by zeroing-out the last two digits. It works perfectly, and is really easy to do, but wouldn't work at all if you were trying to round to the nearest multiple of 76.

PAGE_ROUND_UP does the same thing, but it adds as much as it can to the page before cutting it off. It's kinda like how I can round up to the nearest multiple of 100 by adding 99 to any number and then zeroing-out the last two digits. (We add PAGE_SIZE-1 for the same reason we added S-1 above.)

Good luck with your virtual memory!

16
ответ дан 2 December 2019 в 07:03
поделиться

The most common way to achieve this is to set a background image to the password field with the text "password" and remove the background image when it gets the focus.

неправдоподобно для реальной жизни, но достаточно для демонстрации, что ULONG_PTR является беззнаковым 16-битным целым числом) равно 0xBFAB , затем

PAGE_SIZE         PAGE_ROUND_DN(0xBFAB)   PAGE_ROUND_UP(0xBFAB)

0x0400     -->    0xBC00                  0xC000
0x0800     -->    0xB800                  0xC000
0x1000     -->    0xB000                  0xC000

Макросы округляют вниз и вверх до ближайшее кратное размеру страницы. Последние пять битов будут обнулены, только если PAGE_SIZE == 0x20 (или 32).

1
ответ дан 2 December 2019 в 07:03
поделиться

При использовании целочисленной арифметики при делении всегда округляется в меньшую сторону. Чтобы исправить это, вы добавляете наибольшее возможное число, которое не повлияет на результат, если исходное число было делимым поровну. Для числа S это наибольшее возможное число - S-1.

Округление до степени 2 является особенным, потому что вы можете сделать это с помощью битовых операций. Кратное 2 всегда будет иметь ноль в нижнем бите, кратное 4 всегда будет иметь ноль в двух нижних битах и ​​т. Д. Двоичное представление степени 2 - это один бит, за которым следует группа нулей; вычитание 1 очистит этот бит и установит все биты вправо. Инвертирование этого значения создает битовую маску с нулями в тех местах, которые необходимо очистить. Оператор & очистит эти биты в вашем значении, округляя значение в меньшую сторону.

4
ответ дан 2 December 2019 в 07:03
поделиться

The & makes it so.. well ok, lets take some binary numbers.

(with 1000 being page size)
PAGE_ROUND_UP(01101b)=
01101b+1000b-1b & ~(1000b-1b) =
01101b+111b & ~(111b) =
01101b+111b & ...11000b = (the ... means 1's continuing for size of ULONG)
10100b & 11000b=
10000b

So, as you can see(hopefully) This rounds up by adding PAGE_SIZE to x and then ANDing so it cancels out the bottom bits of PAGE_SIZE that are not set

0
ответ дан 2 December 2019 в 07:03
поделиться

Based on the current draft standard (C99) this macro is not entirely correct however, note that for negative values of N the result will almost certainly be incorrect.

The formula:

#define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))

Makes use of the fact that integer division rounds down for non-negative integers and uses the S - 1 part to force it to round up instead.

However, integer division rounds towards zero (C99, Section 6.5.5. Multiplicative operators, item 6). For negative N, the correct way to 'round up' is: 'N / S', nothing more, nothing less.

It gets even more involved if S is also allowed to be a negative value, but let's not even go there... (see: How can I ensure that a division of integers is always rounded up? for a more detailed discussion of various wrong and one or two right solutions)

1
ответ дан 2 December 2019 в 07:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: