@@ -320,9 +320,153 @@ func Div32(hi, lo, y uint32) (quo, rem uint32) {
320320 return q1 * two16 + q0 , (un21 * two16 + un0 - q0 * y ) >> s
321321}
322322
323- //gopherjs:remove
323+ //gopherjs:replace
324324func Div64 (hi , lo , y uint64 ) (quo , rem uint64 ) {
325- // TODO: Agent insert code here
325+ // Reference: "The Art of Computer Programming" (TAoCP) Vol. 2 by Knuth
326+ // (a copy can be found at https://github.com/Code42Cate/The-Art-of-Computer-Programming/blob/master/Volume2.pdf)
327+ // describes Algorithm D (Division of nonnegative integers) in 4.3.1 starting on page 257.
328+ //
329+ // This code is similar to the original math/bits.Div64 with all arithmetic
330+ // operating on 32-bit halves to avoid using uint64 operations that we have
331+ // to emulate in JS.
332+ yHi := js .Uint64High (y )
333+ yLo := js .Uint64Low (y )
334+ if yHi == 0 && yLo == 0 {
335+ panic (divideError )
336+ }
337+ hiHi := js .Uint64High (hi )
338+ hiLo := js .Uint64Low (hi )
339+ if yHi < hiHi || (yHi == hiHi && yLo <= hiLo ) {
340+ panic (overflowError )
341+ }
342+ loHi := js .Uint64High (lo )
343+ loLo := js .Uint64Low (lo )
344+
345+ // Fast path: divisor fits in 32 bits. The y > hi precondition forces
346+ // hiHi == 0 and hiLo < yLo, so neither Div32 below can overflow.
347+ if yHi == 0 {
348+ q1 , r1 := Div32 (hiLo , loHi , yLo )
349+ q0 , r0 := Div32 (r1 , loLo , yLo )
350+ return js .MakeUint64 (float64 (q1 ), float64 (q0 )),
351+ js .MakeUint64 (0 , float64 (r0 ))
352+ }
353+
354+ // General case: yHi != 0 (full 64-bit divisor).
355+ // Normalize so the divisor's top bit is set; s is in [0, 31].
356+ s := uint (LeadingZeros32 (yHi ))
357+ rs := 32 - s
358+
359+ // Shifted divisor Y = y << s = (Yn1:Yn0).
360+ // Shifted dividend U = (hi:lo) << s = (un32Hi:un32Lo:un1:un0).
361+ // Because hi < y (precondition), hi << s still fits in 64 bits.
362+ var Yn1 , Yn0 , un32Hi , un32Lo , un1 , un0 uint32
363+ if s == 0 {
364+ Yn1 , Yn0 = yHi , yLo
365+ un32Hi , un32Lo = hiHi , hiLo
366+ un1 , un0 = loHi , loLo
367+ } else {
368+ Yn1 = yHi << s | yLo >> rs
369+ Yn0 = yLo << s
370+ un32Hi = hiHi << s | hiLo >> rs
371+ un32Lo = hiLo << s | loHi >> rs
372+ un1 = loHi << s | loLo >> rs
373+ un0 = loLo << s
374+ }
375+
376+ // --- First quotient digit q1 ≈ (un32Hi:un32Lo) / Yn1 ---
377+ // Precondition un32 < Y gives un32Hi <= Yn1. When un32Hi == Yn1 the
378+ // true digit is 2^32 or 2^32+1; Knuth's loop implicitly decrements it
379+ // to 2^32-1 with rhat = un32Lo + Yn1. If that sum overflows uint32 the
380+ // loop's "rhat >= two32" early-exit fires and no further adjustment is
381+ // possible from 32-bit rhat, so we mark skipAdj.
382+ var q1 , rhat uint32
383+ var skipAdj bool
384+ if un32Hi >= Yn1 {
385+ q1 = 0xFFFFFFFF
386+ sum , carry := Add32 (un32Lo , Yn1 , 0 )
387+ if carry != 0 {
388+ skipAdj = true
389+ } else {
390+ rhat = sum
391+ }
392+ } else {
393+ q1 , rhat = Div32 (un32Hi , un32Lo , Yn1 )
394+ }
395+
396+ // Track q1 * Yn0 incrementally across the correction loop so we avoid
397+ // re-multiplying every iteration and can reuse the final value for un21.
398+ qynHi , qynLo := Mul32 (q1 , Yn0 )
399+ if ! skipAdj {
400+ for qynHi > rhat || (qynHi == rhat && qynLo > un1 ) {
401+ q1 --
402+ if qynLo < Yn0 {
403+ qynHi --
404+ }
405+ qynLo -= Yn0
406+ sum , carry := Add32 (rhat , Yn1 , 0 )
407+ if carry != 0 {
408+ break
409+ }
410+ rhat = sum
411+ }
412+ }
413+
414+ // un21 = (un32:un1) - q1*y, mod 2^64.
415+ // (un32 << 32) mod 2^64 = (un32Lo : 0), so the top half of un21 is
416+ // computed from un32Lo (not un32Hi). q1*y mod 2^64 has high 32 bits
417+ // q1*Yn1 + carry(q1*Yn0); both intentionally wrap modulo 2^32.
418+ qyHi := q1 * Yn1 + qynHi
419+ un21Lo := un1 - qynLo
420+ un21Hi := un32Lo - qyHi
421+ if un1 < qynLo {
422+ un21Hi --
423+ }
424+
425+ // --- Second quotient digit q0 ≈ (un21Hi:un21Lo) / Yn1 ---
426+ var q0 uint32
427+ skipAdj = false
428+ if un21Hi >= Yn1 {
429+ q0 = 0xFFFFFFFF
430+ sum , carry := Add32 (un21Lo , Yn1 , 0 )
431+ if carry != 0 || un21Hi > Yn1 {
432+ skipAdj = true
433+ } else {
434+ rhat = sum
435+ }
436+ } else {
437+ q0 , rhat = Div32 (un21Hi , un21Lo , Yn1 )
438+ }
439+
440+ qynHi , qynLo = Mul32 (q0 , Yn0 )
441+ if ! skipAdj {
442+ for qynHi > rhat || (qynHi == rhat && qynLo > un0 ) {
443+ q0 --
444+ if qynLo < Yn0 {
445+ qynHi --
446+ }
447+ qynLo -= Yn0
448+ sum , carry := Add32 (rhat , Yn1 , 0 )
449+ if carry != 0 {
450+ break
451+ }
452+ rhat = sum
453+ }
454+ }
455+
456+ // Remainder = (un21:un0) - q0*y, mod 2^64, then >> s to denormalize.
457+ qyHi2 := q0 * Yn1 + qynHi
458+ remLo := un0 - qynLo
459+ remHi := un21Lo - qyHi2
460+ if un0 < qynLo {
461+ remHi --
462+ }
463+ if s != 0 {
464+ remLo = remLo >> s | remHi << rs
465+ remHi = remHi >> s
466+ }
467+
468+ return js .MakeUint64 (float64 (q1 ), float64 (q0 )),
469+ js .MakeUint64 (float64 (remHi ), float64 (remLo ))
326470}
327471
328472//gopherjs:replace
0 commit comments