It’s (a) the inverse operation of doubleWidthMultiply. (b) an important building block for fast “small bignum arithmetic” (2-16 ish words). If you have this operation, it’s easy to build the divide that does DoubleWidth<T> / DoubleWidth<T>. (c) the widest divide operation that maps reasonably cleanly to common hardware when T = Word.
– Steve > On Jan 31, 2017, at 6:59 AM, Nevin Brackett-Rozinsky via swift-evolution > <swift-evolution@swift.org> wrote: > > What, exactly, is the intended purpose of doubleWidthDivide? > > I ask because, outside of degenerate cases, a quotient and remainder will fit > in the same size type as the operands. > > So widthX / widthY will have quotient that fits in width X, and remainder > that fits in width Y. > > In general, we cannot assume either one would be any smaller than that. > > Nevin > > > On Monday, January 30, 2017, Brent Royal-Gordon via swift-evolution > <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote: > > On Jan 30, 2017, at 11:31 AM, Max Moiseev <mois...@apple.com > > <javascript:;>> wrote: > > > > doubleWidthDivide should not return a DoubleWidth<T> for two reasons: > > 1. The components of it’s return type are not high and low, but are > > quotient and remainder instead. > > 2. In DoubleWidth<T> high is T and low is T.Magnitude, which is not the > > case for quotient and remainder. > > You're right about the return value; for `doubleWidthDivide(_:_:)`, I was > thinking about changing the dividend. Specifically, I'm thinking we should > change these to: > > static func doubleWidthMultiply(_ lhs: Self, _ rhs: Self) -> > DoubleWidth<Self> > static func doubleWidthDivide(_ lhs: DoubleWidth<Self>, _ rhs: Self) > -> (quotient: Self, remainder: Self) > > I'm also thinking a little bit about spelling of these operations. I'd *love* > to be able to call them `*` and `/` and let the type system sort things out, > but that would cause problems, especially for multiply (since the return > value is the only thing different from a normal `*`). We could invent a new > operator, but that would be a bit much. Could these be simply `multiply` and > `divide`, and we'll permit the `DoubleWidth` parameter/return type to explain > itself? > > I'm also thinking the second parameter should be labeled `by`, since that's > the way people talk about these operations. Applying both of these > suggestions, we'd get: > > static func multiply(_ lhs: Self, by rhs: Self) -> DoubleWidth<Self> > static func divide(_ lhs: DoubleWidth<Self>, by rhs: Self) -> > (quotient: Self, remainder: Self) > > let x = Int.multiply(a, by: b) > let (aʹ, r) = Int.divide(x, by: b) > assert(a == aʹ) > assert(r == 0) > > Should the standard library provide extensions automatic definitions of > multiplication and division in terms of their double-width equivalents? > > extension FixedWidthInteger { > func multipliedWithOverflow(by other: Self) -> (partialValue: > Self, overflow: ArithmeticOverflow) { > let doubledResult = Self.multiply(self, by: other) > let overflowed = doubledResult.high != (doubledResult > < 0 ? -1 : 0) > return (Self(bitPattern: doubledResult.lowerValue), > overflowed ? .overflowed : .none) > } > > func quotientAndRemainder(dividingBy other: Self) -> > (quotient: Self, remainder: Self) { > precondition(other != 0, "Divide by zero") > return Self.divide(DoubleWidth(self), by: other) > } > > func dividedWithOverflow(by other: Self) -> (partialValue: > Self, overflow: ArithmeticOverflow) { > guard other != 0 else { return (self, .overflowed) } > > let result = Self.divide(self, by: other) > return (result.quotient, .none) > } > > static func * (lhs: Self, rhs: Self) -> Self { > let result = lhs.dividedWithOverflow(by: rhs) > precondition(result.overflow == .none, > "Multiplication overflowed") > return result.partialValue > } > > static func / (lhs: Self, rhs: Self) -> Self { > let result = lhs.quotientAndRemainder(dividingBy: rhs) > return result.quotient > } > > static func % (lhs: Self, rhs: Self) -> Self { > let result = lhs.quotientAndRemainder(dividingBy: rhs) > return result.remainder > } > } > > Hmm...having actually written this out, I now have a couple of concerns: > > 1. There's a lot of jumping back and forth between instance methods and > static methods. Can we standardize on just static methods? Or make sure that > the user-facing interfaces are all either operators or instance methods? > > 2. There is no quotient-and-remainder-with-overflow, either regular or > double-width. Can we do that? > > 3. "Overflow" is not really a good description of what's happening in > division; the value is undefined, not overflowing. Is there a better way to > express this? > > 4. For that matter, even non-fixed-width division can "overflow"; should that > concept be hoisted higher up the protocol hierarchy? > > 5. For *that* matter, should we simply make these operations throw instead of > returning a flag? > > enum ArithmeticError<NumberType: Arithmetic>: Error { > // Are generic errors permitted? > case overflow(partialValue: NumberType) > case undefined > } > > // Should these throwing definitions be higher up so that, when > working with `Arithmetic` > // or similar types, you have an opportunity to handle errors instead > of always trapping? > protocol FixedWidthInteger: BinaryInteger { > ... > func adding(_ other: Self) throws -> Self > func subtracting(_ other: Self) throws -> Self > func multiplied(by other: Self) throws -> Self > func divided(by other: Self) throws -> Self > ... > } > > I'm *really* tempted to suggest adding throwing variants of the actual > operators (strawman example: `^+`, `^-`, `^*`, `^/`, `^%`), but they may be > too specialized to really justify that. > > > Having said that, there is a solution for doubleWidthMultiply, that I think > > is worth trying: > > > > enum DoubleWidth<T> { > > case .parts(high: T, low: T.Magnitude) > > > > var high: T { switch self { case .parts(let high, _): return high } } > > var low: T.Magnitude { switch self { case .parts(_, let low): return low > > } } > > } > > > > This way it will be possible to both do pattern-matching on the result of > > doubleWidthMultiply, and use it as a whole, accessing r.high and r.low when > > needed. > > This sounds like a good idea to me. (Unless we want to create a protocol for > destructuring, but I assume that's out of scope.) > > -- > Brent Royal-Gordon > Architechies > > _______________________________________________ > swift-evolution mailing list > swift-evolution@swift.org <javascript:;> > https://lists.swift.org/mailman/listinfo/swift-evolution > <https://lists.swift.org/mailman/listinfo/swift-evolution> > _______________________________________________ > swift-evolution mailing list > swift-evolution@swift.org > https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution