OLD | NEW |
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 // This file contains operations on unsigned multi-precision integers. | 5 // This file contains operations on unsigned multi-precision integers. |
6 // These are the building blocks for the operations on signed integers | 6 // These are the building blocks for the operations on signed integers |
7 // and rationals. | 7 // and rationals. |
8 | 8 |
9 // This package implements multi-precision arithmetic (big numbers). | 9 // This package implements multi-precision arithmetic (big numbers). |
10 // The following numeric types are supported: | 10 // The following numeric types are supported: |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
62 if n <= cap(z) { | 62 if n <= cap(z) { |
63 return z[0:n] // reuse z | 63 return z[0:n] // reuse z |
64 } | 64 } |
65 // Choosing a good value for e has significant performance impact | 65 // Choosing a good value for e has significant performance impact |
66 // because it increases the chance that a value can be reused. | 66 // because it increases the chance that a value can be reused. |
67 const e = 4 // extra capacity | 67 const e = 4 // extra capacity |
68 return make(nat, n, n+e) | 68 return make(nat, n, n+e) |
69 } | 69 } |
70 | 70 |
71 | 71 |
| 72 func (z nat) setWord(x Word) nat { |
| 73 if x == 0 { |
| 74 return z.make(0) |
| 75 } |
| 76 z = z.make(1) |
| 77 z[0] = x |
| 78 return z |
| 79 } |
| 80 |
| 81 |
72 func (z nat) setUint64(x uint64) nat { | 82 func (z nat) setUint64(x uint64) nat { |
73 if x == 0 { | |
74 return z.make(0) | |
75 } | |
76 | |
77 // single-digit values | 83 // single-digit values |
78 » if x == uint64(Word(x)) { | 84 » if w := Word(x); uint64(w) == x { |
79 » » z = z.make(1) | 85 » » return z.setWord(w) |
80 » » z[0] = Word(x) | |
81 » » return z | |
82 } | 86 } |
83 | 87 |
84 // compute number of words n required to represent x | 88 // compute number of words n required to represent x |
85 n := 0 | 89 n := 0 |
86 for t := x; t > 0; t >>= _W { | 90 for t := x; t > 0; t >>= _W { |
87 n++ | 91 n++ |
88 } | 92 } |
89 | 93 |
90 // split x into n words | 94 // split x into n words |
91 z = z.make(n) | 95 z = z.make(n) |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
187 case x[i] > y[i]: | 191 case x[i] > y[i]: |
188 r = 1 | 192 r = 1 |
189 } | 193 } |
190 return | 194 return |
191 } | 195 } |
192 | 196 |
193 | 197 |
194 func (z nat) mulAddWW(x nat, y, r Word) nat { | 198 func (z nat) mulAddWW(x nat, y, r Word) nat { |
195 m := len(x) | 199 m := len(x) |
196 if m == 0 || y == 0 { | 200 if m == 0 || y == 0 { |
197 » » return z.setUint64(uint64(r)) // result is r | 201 » » return z.setWord(r) // result is r |
198 } | 202 } |
199 // m > 0 | 203 // m > 0 |
200 | 204 |
201 z = z.make(m + 1) | 205 z = z.make(m + 1) |
202 z[m] = mulAddVWW(z[0:m], x, y, r) | 206 z[m] = mulAddVWW(z[0:m], x, y, r) |
203 | 207 |
204 return z.norm() | 208 return z.norm() |
205 } | 209 } |
206 | 210 |
207 | 211 |
(...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
522 // Uses z as storage for q, and u as storage for r if possible. | 526 // Uses z as storage for q, and u as storage for r if possible. |
523 // See Knuth, Volume 2, section 4.3.1, Algorithm D. | 527 // See Knuth, Volume 2, section 4.3.1, Algorithm D. |
524 // Preconditions: | 528 // Preconditions: |
525 // len(v) >= 2 | 529 // len(v) >= 2 |
526 // len(uIn) >= len(v) | 530 // len(uIn) >= len(v) |
527 func (z nat) divLarge(u, uIn, v nat) (q, r nat) { | 531 func (z nat) divLarge(u, uIn, v nat) (q, r nat) { |
528 n := len(v) | 532 n := len(v) |
529 m := len(uIn) - n | 533 m := len(uIn) - n |
530 | 534 |
531 // determine if z can be reused | 535 // determine if z can be reused |
| 536 // TODO(gri) should find a better solution - this if statement |
| 537 // is very costly (see e.g. time pidigits -s -n 10000) |
532 if alias(z, uIn) || alias(z, v) { | 538 if alias(z, uIn) || alias(z, v) { |
533 z = nil // z is an alias for uIn or v - cannot reuse | 539 z = nil // z is an alias for uIn or v - cannot reuse |
534 } | 540 } |
535 q = z.make(m + 1) | 541 q = z.make(m + 1) |
536 | 542 |
537 qhatv := make(nat, n+1) | 543 qhatv := make(nat, n+1) |
538 if alias(u, uIn) || alias(u, v) { | 544 if alias(u, uIn) || alias(u, v) { |
539 u = nil // u is an alias for uIn or v - cannot reuse | 545 u = nil // u is an alias for uIn or v - cannot reuse |
540 } | 546 } |
541 u = u.make(len(uIn) + 1) | 547 u = u.make(len(uIn) + 1) |
542 u.clear() | 548 u.clear() |
543 | 549 |
544 // D1. | 550 // D1. |
545 shift := Word(leadingZeros(v[n-1])) | 551 shift := Word(leadingZeros(v[n-1])) |
546 shlVW(v, v, shift) | 552 shlVW(v, v, shift) |
547 u[len(uIn)] = shlVW(u[0:len(uIn)], uIn, shift) | 553 u[len(uIn)] = shlVW(u[0:len(uIn)], uIn, shift) |
548 | 554 |
549 // D2. | 555 // D2. |
550 for j := m; j >= 0; j-- { | 556 for j := m; j >= 0; j-- { |
551 // D3. | 557 // D3. |
552 » » var qhat Word | 558 » » qhat := Word(_M) |
553 » » if u[j+n] == v[n-1] { | 559 » » if u[j+n] != v[n-1] { |
554 » » » qhat = _B - 1 | |
555 » » } else { | |
556 var rhat Word | 560 var rhat Word |
557 » » » qhat, rhat = divWW_g(u[j+n], u[j+n-1], v[n-1]) | 561 » » » qhat, rhat = divWW(u[j+n], u[j+n-1], v[n-1]) |
558 | 562 |
559 // x1 | x2 = q̂v_{n-2} | 563 // x1 | x2 = q̂v_{n-2} |
560 » » » x1, x2 := mulWW_g(qhat, v[n-2]) | 564 » » » x1, x2 := mulWW(qhat, v[n-2]) |
561 // test if q̂v_{n-2} > br̂ + u_{j+n-2} | 565 // test if q̂v_{n-2} > br̂ + u_{j+n-2} |
562 for greaterThan(x1, x2, rhat, u[j+n-2]) { | 566 for greaterThan(x1, x2, rhat, u[j+n-2]) { |
563 qhat-- | 567 qhat-- |
564 prevRhat := rhat | 568 prevRhat := rhat |
565 rhat += v[n-1] | 569 rhat += v[n-1] |
566 // v[n-1] >= 0, so this tests for overflow. | 570 // v[n-1] >= 0, so this tests for overflow. |
567 if rhat < prevRhat { | 571 if rhat < prevRhat { |
568 break | 572 break |
569 } | 573 } |
570 » » » » x1, x2 = mulWW_g(qhat, v[n-2]) | 574 » » » » x1, x2 = mulWW(qhat, v[n-2]) |
571 } | 575 } |
572 } | 576 } |
573 | 577 |
574 // D4. | 578 // D4. |
575 qhatv[n] = mulAddVWW(qhatv[0:n], v, qhat, 0) | 579 qhatv[n] = mulAddVWW(qhatv[0:n], v, qhat, 0) |
576 | 580 |
577 c := subVV(u[j:j+len(qhatv)], u[j:], qhatv) | 581 c := subVV(u[j:j+len(qhatv)], u[j:], qhatv) |
578 if c != 0 { | 582 if c != 0 { |
579 c := addVV(u[j:j+n], u[j:], v) | 583 c := addVV(u[j:j+n], u[j:], v) |
580 u[j+n] += c | 584 u[j+n] += c |
(...skipping 471 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1052 } | 1056 } |
1053 if y.cmp(natOne) == 0 { | 1057 if y.cmp(natOne) == 0 { |
1054 return false | 1058 return false |
1055 } | 1059 } |
1056 } | 1060 } |
1057 return false | 1061 return false |
1058 } | 1062 } |
1059 | 1063 |
1060 return true | 1064 return true |
1061 } | 1065 } |
OLD | NEW |