Sure, “negate” doesn’t mean (in this context) “make something negative” but it sure can plausibly sound like it means that. I certainly agree that it is confusable enough to be best avoided.
I would not attempt to reach for “consistency” in naming here with floating-point values. There’s no negated as the non-mutating counterpart because it’s spelled with prefix -, and I don’t think we’d want to use an operator for FloatingPointSign. That, and the general feeling you and others have mentioned that “negate the sign” just sounds weird, are pretty good hints I think that naming manipulation of a sign in the same way as manipulation of a number isn’t the way to go.
Instinctively, I do like “invert” better, but it could be confused with other mathematical operations too. “Flipping” the sign or “switching” the sign are perfectly good terms, but may seem a little weird without the word “sign” next to it. Ultimately, “toggle” seems the best balance of not confusable with an operation it’s not and already precedented in the language.
Because of the way init(sign:exponent:significand:) has been documented, folks are generally unaware that you can create a negated value from another by negating the significand without changing the sign parameter.
In all other cases, too, where I’ve had to deal with changing sign, I’ve been better served by avoiding operations on FloatingPointSign as much as possible. I agree with @scanon that a concrete example would be helpful. It would be useful, for instance, to know the broader use case you have in mind where the sign specifically needs to be remembered rather than the original floating-point value across loop iterations. My experiences with this type lead me to the opinion that, even though it semantically represents signedness, making it “useful to work with” by adding more APIs—even if they are meaningful ones—is likely to be worse than the status quo which steers users more frequently towards alternatives.
However, if you have a concrete scenario where using operations on FloatingPointSign is really the way to go, it would be useful to see. I am just quite convinced that there exist virtually none that would not be better off rewritten to avoid it.
Say you have a recursive formula along the lines of:
f(x) = p(x) + (-1)q(x) f(g(x))
where p, q, and g are easy to calculate.
In order to find f(x), you could write a recursive function, but for performance reasons you might prefer to implement it with an imperative loop.
The loop accumulates p(x) values and updates x to g(x), until some stopping condition is reached. But it needs to know whether to add or subtract each p(x), and that’s not as simple as looking at the parity of q(x).
And we see that the sign applied to any particular value of p is the combined parity of all previous q values, not just the parity of the most recent value of q.
So you need to keep a sign variable outside the loop, and the parity of q(x) tells you whether or not to negate that stored sign value on each iteration.
If p(x) itself is initialized from a sign, exponent, and significand, then it makes sense to use the stored sign directly, rather than introduce an extraneous conditional test to negate p (or its significand).
• • •
That’s a separate issue, about the (lack of) clarity of that initializer.
However it’s worth noting that if you’re using a raw significand, then you can’t simply negate the significand.
Right, but raw significands generally do not come up in the sort of use case that you're describing (for that matter, it's pretty rare to be working with separate exponent and signficands in that sort of scenario, though not unheard of).
I don't understand this; you would usually reverse the order of accumulation in the imperative loop. This doesn't require tracking the sign, and doesn't require explicit recursion, and usually has better numerical stability, since when you're doing this sort of summation it's generally with a series that eventually decays.
As I said, I'm not really opposed to adding this API, but it's actual use seems extremely narrow to me.
At the risk of derailing this thread…how would you reverse the order?
You don’t know the next x value until you calculate g(x), so you’d have to allocate an array of [x, g(x), g(g(x)), …], and even then you wouldn’t necessarily know how far to go since the stopping condition might depend on p(x).
• • •
Frankly I’m surprised to see so much pushback against this. Or indeed any pushback at all, aside from bikeshedding.
Ok, I misinterpreted what you wrote, but honestly that only makes me think this is more niche, because I’ve never once had to evaluate an expression like that.
The reason for my pushback is that I’m wary of adding API to manipulate signs like this, because manipulating the sign of a floating-point number as an abstract thing, rather than just using negation, copy sign, and absolute value on the number itself, is uncommon, and it feels like an attractive nuisance that will lead people into overly convoluted code that repeatedly takes apart and reassembles floating-point representations instead of just operating on the numbers themselves.
I’m not opposed to it, but we’re 20 posts in and you haven’t yet posted a code example showing the use case, just a handwavy “it would be good when you have a weird expression like this”. What is the actual motivating example?