Once again, while reviewing some source code, I’ve come across two new solutions to the Pizza Box Problem. For those who don’t remember, the Pizza Box Problem is about finding an answer to the question how many pizza bags you need to ship a certain quantity of pizza boxes. This problem pops up frequently in systems programming, albeit in different guises. The solution I gave then was:

1 2 3 |
pizza_bags = (pizza_boxes + N - 1) / N; |

where N is the number of pizza boxes that fit into a pizza bag and ‘/’ is the integer division operator that rounds towards zero.

Here is the first alternative I’ve seen. Someone wants to chop-up a larger message into smaller packets and in order to find out how many packets are to be sent:

1 2 3 4 5 6 7 8 |
static const uint32_t MAX_PACKET_SIZE = 6000; uint32_t packets = size / MAX_PACKET_SIZE; if (size % MAX_PACKET_SIZE != 0) { ++packets; } |

What this code does is add one to the result of the division, except for cases where the remainder of the division is zero. This code seems to work fine, but is it also efficient?

At first glance, you might think that it is way less efficient than my official solution on the grounds that it uses the modulo operator and this requires yet another expensive integer division operation.

As usual, the real answer is: “it depends”. Some architectures (like Intel x86) have DIV instructions that return the division result and the remainder at the same time, while others do not. If the former is the case, you get the modulo operation for free. If not, you will have to pay the price. For instance, the PowerPC architecture requires you to calculate the remainder in three steps “by hand”:

1 2 3 4 5 |
divd RT,RA,RB # RT = quotient mulld RT,RT,RB # RT = quotient*divisor subf RT,RT,RA # RT = remainder |

Another downside is the fact that the code is not branch-free. Depending on the platform you are on, you might get a penalty if the branch is taken (“pipeline flush”). Yet, the likelihood that the branch is taken is actually low, as it happens only if size is not evenly divisible by MAX_PACKET_SIZE.

By and large, I don’t like this approach. It requires more typing and is likely to have an efficiency issue.

But I’ve come across another, more promising solution:

1 2 3 |
packets = 1 + ((size - 1) / MAX_PACKET_SIZE); |

Compared to my original solution, this version has a clear advantage: it doesn’t suffer from overflow issues. Consider the original pizza box formula:

1 2 3 |
pizza_bags = (pizza_boxes + N - 1) / N; |

Depending on the value of size and N it is possible that their sum overflows the value range of their underlying types, which would result in a wrong value of pizza_bags.

On the other hand, the original solution has one distinct advantage over the other two solutions: it handles the case where size (or the number of pizza boxes) is zero correctly.

Only the original version will yield a result of zero in this case; the others will compute one, which is — of course — wrong. Any pizza delivery guy knows that if you have no pizzas you don’t need no bags at all!

So depending on the constraints of your context, you now have two efficient possibilities to choose from. Regardless of your decision, I advise you to use explicit assertions to state and check your assumptions. Either:

1 2 3 4 |
assert(pizza_boxes + N - 1 >= pizza_boxes); pizza_bags = (pizza_boxes + N - 1) / N; |

or

1 2 3 4 |
assert(pizza_boxes >= 1); pizza_bags = 1 + ((pizza_boxes - 1) / N); |