I was reading the Swift documentation about Operators, and I came across an example which calculates the remainder of -9 % 4. According to the documentation, the formula to accomplish this is a = (b x multiplier) + remainder. The example goes on to explain that b goes into a, m times, or four goes into negative nine negative two times, yielding the equation -9 = (4 x -2) + remainder, which means that the remainder is negative one. Upon checking this in my playground it works. However, the concept of a negative multiplier didn't make sense to me at first, and the idea of a whole number going into another number a negative number of times didn't make sense. But upon researching it, I found that multiples can be negative, so this now makes sense to me in a way. However, I checked with ChatGPT and the ChatGPT stated the Swift rounds down negative numbers to negative infinity, and so in this example the equation a = (b x multiplier) + remainder becomes -9 = (4 x -3) + remainder, since the quotient of -9/4 is -2.5, and rounded down that equals to -3, yielding a remainder of positive three. So I was wondering, does Swift round down the quotient do negative infinity, and will this have any implications on my equation which calculates the remainder? Many thanks
You can test this in Swift:
(-9).quotientAndRemainder(dividingBy: 4)
// result: (-2, -1)
This is tangentially related.
I am wondering why Swift
does not have an operator for n (modulo M)
, for n an integer and M a natural number > 0
.
n = k x M + r, for M > 0, 0 <= r < M
n (modulo M) := r
ChatGPT, unsurprisingly, is simply making things up here. The integer division operator /
in swift rounds toward zero, and the remainder operator %
matches that behavior.
Rather than asking a LLM, I would always recommend consulting the documentation for such questions about any programming language.
I have no idea what that operator would be. I'm already confused by %
doing something different across different languages.
This, I would welcome:
public extension BinaryInteger {
/// Returns the quotient and modulus of this value divided by the given value.
func quotientAndModulus(dividingBy divisor: Self) -> (quotient: Self, modulus: Self) {
let (quotient, remainder) = quotientAndRemainder(dividingBy: divisor)
return (quotient, (remainder + divisor) % divisor)
}
}
#expect(
1.quotientAndModulus(dividingBy: 2)
==
1.quotientAndRemainder(dividingBy: 2)
)
#expect((-1).quotientAndModulus(dividingBy: 2).modulus == 1)
#expect(
(-3).quotientAndModulus(dividingBy: -2)
==
(-3).quotientAndRemainder(dividingBy: -2)
)
I think he's asking for the Euclidean modulus operator. Which is relatively easy to write from one that rounds to zero.
extension BinaryInteger {
func euclideanQuotientAndRemainder(dividingBy divisor: Self) -> (quotient: Self, remainder: Self)
{
var (q, r) = quotientAndRemainder(dividingBy: divisor)
if r < 0 {
q = if divisor > 0 { q - 1 } else { q + 1 }
// abs(_:) requires T conforms to SignedInteger, so we've got to do this manually
r = if divisor > 0 { r + divisor } else { r - divisor }
}
return (q, r)
}
}
Huh. That's actually in Numerics but it looks like someone forgot to make it public
and test it?
private import Numerics
public extension SignedInteger {
/// Returns the quotient and modulus of this value divided by the given value.
func euclideanQuotientAndModulus(dividingBy divisor: Self) -> (quotient: Self, modulus: Self) {
divided(by: divisor, rounding: self >= 0 ? .towardZero : .awayFromZero) as (_, _)
}
}
I agree, however there are other sources of information which are also backed by Apple which could lead one to have the same confusion that the ChatGPT encountered when I asked this question. For example, the documentation in Apple's "Getting Started with App Development" clearly states: "When you use the division (/) operator on Int
values, the result will be an Int
value rounded down to the nearest whole number, because the Int
type supports whole numbers...". One could interpret "rounding down to the nearest whole number" in this context while performing division on negative integers as rounding towards negative infinity which was in the answer by ChatGPT. To your point, the documentation clearly states that the remainder is dropped when performing division on two integer type values, which clears up this confusion. I wish there was some kind of consensus between the various resources put out there by Apple which eliminate any confusion, for example by adding a note that the remainder is dropped when dividing integers inside the book, "Develop with Swift Fundamentals".
Hi @Danny , I was just wondering, how does Swift calculate (-3).quotientAndRemainder(dividingBy: -2)
? Since I was doing this calculation myself to check the answers and the result I got was that quotient is 0 and the remainder is -3.
To compute the result of a.quotientAndRemainder(dividingBy: b)
, compute a/b
as a real number, then truncate (round toward zero) to an integer. This is the quotient q
. Then compute a - bq
; this is the remainder:
quotient = truncate(-3/-2) = truncate(1.5) = 1
remainder = (-3) - (-2)*1 = -1
If b
is zero then the quotient is not defined, and a precondition failure occurs. If a
is the minimum value of a signed type and b
is -1, then the quotient is not representable, and a precondition failure occurs.
This violates the definition of division; no matter what rounding mode is used for the quotient, the remainder must have magnitude strictly smaller than the divisor (-2 in your example). When division is not exact, there are two (quotient, remainder) pairs that would satisfy this constraint, and the rounding rule chooses between them. Truncating division chooses the representative where the remainder has the same sign as the dividend. Flooring division chooses the representative where the remainder has the same sign as the divisor.
Thanks @scanon. Your answer is very nuanced. I initially flipped the dividend and the divisor hence why I got the quotient of zero.
This is really interesting. I inserted the dividend and the divisor, -9 and 4, here and got the same answer that was in the ChatGPT. I'll add that the ChatGPT stated: "The initial explanation in the documentation that says the remainder is -1 might be an error or might be referring to a different division rule." The latter seems to be the case based on your response. Additionally, the ChatGPT stated: "Here's the important point: Swift and many programming languages follow the rule of "rounding toward negative infinity" when performing integer division." Based on the documentation, this appears to be incorrect, that the normal way of dividing in Swift is by using the truncating variant which @scanon elaborated in one of his replies.
Most programming languages default to round towards zero, because that's what the hardware does. Don't trust anything ChatGPT says. LLMs aren't fact databases they merely randomly generate responses that are statistically shaped like a correct answer.
I’ll have to hand it to the ChatGPT in the first statement for stating that there are different division rules. I don’t really understand the way LLM’s work but this question and answer with the ChatGPT really opened up a lot of discussion and some interesting and useful insights. The second statement though just seems totally off. But that’s the trouble of using ChatGPT I guess.