C++ Logo

std-proposals

Advanced search

Re: [std-proposals] D3724 Integer division

From: Jan Schultke <janschultke_at_[hidden]>
Date: Fri, 30 May 2025 14:25:17 +0200
> One thing that wasn't clear to me in reading your paper is why the remainder
> functions don't have the same name as the quotient ones. Whenever I want both,
> I want both of the same mathematical division. In other words, how would I
> know that I need rem_divisor_sign for div_towards_neg_infinity? Why aren't both
> functions suffixed the same way?

That is intentional. The rationale is in
https://isocpp.org/files/papers/P3724R0.html#why-the-asymmetry-between--and-?
In short, symmetrical names suggest symmetry in implementation and
usefulness, but that would be misleading here. You also need to be a
bit of a mathematician to understand that you need Euclidean division
to get a remainder that is always positive.

Euclidean division isn't even in the paper, only its remainder, and
that should stay that way because it's essentially useless and only
defined in order to get those nice remainder properties.

> And for timestamp conversions, that is very likely. A time stamp of -64s as in
> "64 seconds before midnight" is "-1 23:58:56".

Ok fair point, this would be a case where you'd want rounding towards
negative infinity so as to classify the timestamp within a day, and
the remainder would tell you the offset within the day.

I have actually added a section
https://isocpp.org/files/papers/P3724R0.html#why-no-combined-remainder-and-quotient?
which demonstrates that you can compute the remainder and quotient
separately and get bit-identical assembly.

> > Once you get into the more exotic modes like std::div_ties_, it's unclear
> > what you actually need the remainder for, and the adjustments to the result
> > of (x / y) made are so complex that you're better off computing the
> > remainder using the quotient afterwards than to make matching adjustments.
>
> I don't buy this. There is exactly one remainder associated with a particular
> division that satisfies the equation
> dividend = divisor * quotient + remainder
>
> If the argument is to make it easy for people not to get things wrong, then
> "they're better off computing" is not the answer.

People get overflow-safe, correct rounding functions that yield
divisors wrong all the time. Obtaining remainders is quite a benign
operation by comparison, so I don't the "getting things wrong"
argument is significant for this case.

> > Yeah fair point, there's a possibility of introducing a dilemma of choice.
> > I'm not really convinced it would be a big problem though. The user can
> > just not call std::div_to_odd if they don't need it.
>
> You did confuse me, because the paper does talk about homogeneising the
> distribution. So which one should I choose if I want that?

I'm not sure what you're really asking here. Obviously you need to
understand your domain and what kind of rounding you need to perform a
certain operation. If you have no idea whether to round to odd or
round up or to negative infinity, no design of this paper could fix
that problem for you.

In the case of homogenising distribution, that should typically be
rounded to odd, but that's ultimately user choice.

> > I'm also worried about creating some swiss cheese of a function set where
> > some rounding modes are there top-level, some only for tie breaking, and
> > you'll never hear the end of the bikeshedding which ones should be included
> > or not. It's quite simple to just include all of them since they're all
> > small and easy to implement.
>
> I understand the challenge, but that's chickening out. Your job and that of
> the committee is to come up with an API that is consistent, usable and as
> intuitive as can be for both lay people and those with more knowledge of the
> issue but who couldn't write the implementations themselves. Therefore, if
> it's worth doing, it's worth doing right, and therefore you and they should
> spend the time to select the most appropriate ones. Don't just add all of
> them, because then that will not be intuitive and you'll confuse the users.

I still don't see the great potential for confusion here. If the user
wants to check how many buckets size N they need to fit M elements,
that's a division towards positive infinity or away from zero. I don't
buy that the extra functions make it substantially harder. The
workflow I envision is:

1. The user understand what rounding mode they need.
    Say, rounding "up"/"ceiling".
2. The user looks at the list of available functions and realizes
    that rounding to positive infinity is what they mean by "ceiling" or "up",
    or maybe they were thinking about it in terms of infinity all along.
3. Done.

The "too many functions" argument only makes sense if the extra
functions add potential for confusion, but there's really no way you
would confuse std::round_to_odd for ceiling/upwards/whatever division.

Received on 2025-05-30 12:25:30