Rare numbers: Difference between revisions

Content deleted Content added
PureFox (talk | contribs)
→‎Version 1: Replaced with much faster version.
Line 120:
=={{header|Go}}==
===Version 1===
This takesuses intomost account allof the hints within Shyam Sunder Gupta's webpage. Itcombined alsowith makesNigel useGalloway's ofgeneral hisapproach observation(see thatTalk nopage) rare number below 10^20of endsworking infrom 3(n-r) and usesdeducing athe bitRare arithmeticnumbers trickwith to further filter outvarious numbers that cannot be perfect squares and thereby avoid theof expensivedigits math.Sqrtfrom operationthere.
 
Although fast (numbers up to 15 digits are processed in around 28 seconds), it runs out of memory when trying to process numbers longer than this.
Despite all this, it's still quite slow, polishing off the first five rare numbers in about 0.75 seconds but taking more than 12.5 minutes to find the next three. However, memory usage is minimal.
 
Timings are for an Intel Core i7-8565U machine with 32GB RAM running Go 1.13.1 on Ubuntu 18.04.
 
Timings are for an Intel Core i7-8565U machine.
<lang go>package main
 
Line 130 ⟶ 131:
"fmt"
"math"
"sort"
"time"
)
 
type term struct {
const (
maxCountcoeff = 8 int64
maxDigitsix1, =ix2 12int8
}
qi = maxDigits - 1 // index of last digit
 
)
const maxDigits = 15
 
func toUint64toInt64(digits []int, ai intint8, reverse bool) uint64int64 {
sum := uint64int64(0)
if !reverse {
for i := ai0; i < maxDigitslen(digits); i++ {
sum = sum*10 + uint64int64(digits[i])
}
} else {
for i := qilen(digits) - 1; i >= ai0; i-- {
sum = sum*10 + uint64int64(digits[i])
}
}
Line 153 ⟶ 156:
}
 
func sumDigits(n uint64int64) uint64int64 {
var sum uint64int64
for n > 0 {
d := n % 10
Line 163 ⟶ 166:
}
 
func sumDigitSliceisSquare(digitsn []int, ai intint64) uint64bool {
if 0x202021202030213&(1<<(n&63)) != 0 {
sum := 0
root := int64(math.Sqrt(float64(n)))
for i := ai; i < maxDigits; i++ {
sumreturn +root*root == digits[i]n
}
return uint64(sum)false
}
 
// From the Cartesian product of two or more lists task - Extra credit 1.
func digRoot(n uint64) int {
func cp(a ...[]int8) [][]int8 {
for n > 9 {
c n := sumDigits(n)1
for _, a := range a {
c *= len(a)
}
returnif int(n)c == 0 {
return nil
}
}
 
p := make([][]int8, c)
// 'inc' assumed to be <= 10
b := make([]int8, c*len(a))
func add(digits []int, ai, inc int) int {
for in := qi; i >= ai-1; i--make([]int8, {len(a))
qs := digits[i]0
for i := range q +=p inc{
ife q:= <s 10+ {len(a)
pi := digitsb[is:e] = q
if p[i] < ai= {pi
s = return ie
for j, n := }range elsen {
pi[j] = return aia[j][n]
}
for j := len(n) - 1; j >= 0; j-- {
n[j]++
if n[j] < int8(len(a[j])) {
break
}
} else { n[j] = 0
digits[i] = q - 10
inc = 1
}
}
return aip
}
 
func possibleSquareseq(nfrom, uint64to, step int8) bool[]int8 {
var res []int8
if 0x202021202030213&(1<<(n&63)) != 0 {
for i := from; returni true<= to; i += step {
res = append(res, i)
}
return falseres
}
 
func commatize(n uint64int64) string {
s := fmt.Sprintf("%d", n)
le := len(s)
Line 216 ⟶ 225:
func main() {
start := time.Now()
digitspow := makeint64([]int, maxDigits1)
ai// :=terms maxDigitsof (n-r) 2expression //for indexnumber of firstdigits non-zerofrom digit2 into slicemaxDigits
allTerms := make([][]term, maxDigits-1)
a := 2 // first non-zero digit
digits[ai]for r := 2; r <= maxDigits; r++ // start from 20 say{
var terms []term
count := 0
pow *= 10
fmt.Printf("The first %d rare numbers are:\n", maxCount)
pow1, pow2 := pow, int64(1)
outer:
for i1, i2 := int8(0), int8(r-1); i1 < i2; i1, i2 = i1+1, i2-1 {
for {
terms = append(terms, term{pow1 - pow2, i1, i2})
switch a {
case 2, 4: pow1 /= 10
aipow2 *= add(digits, ai, 10)
case 6:
ai = add(digits, ai, 5)
case 8:
switch digits[qi] {
case 2:
ai = add(digits, ai, 5)
case 7:
ai = add(digits, ai, 1)
case 8:
ai = add(digits, ai, 4)
}
}
aallTerms[r-2] = digits[ai]terms
}
if a%2 == 1 {
// map of first minus last digits for i'n' :=to qipairs -giving 1;this i > ai; i-- {value
fml := map[int8][][]int8{
digits[i] = 0
0: {{2, 2}, {8, 8}},
1: {{6, 5}, {8, 7}},
4: {{4, 0}},
6: {{6, 0}, {8, 2}},
}
// map of other digit differences for 'n' to pairs giving this value
dmd := make(map[int8][][]int8)
for i := int8(0); i < 100; i++ {
a := []int8{i / 10, i % 10}
d := a[0] - a[1]
dmd[d] = append(dmd[d], a)
}
fl := []int8{0, 1, 4, 6}
dl := seq(-9, 9, 1)
zl := []int8{0}
el := seq(-8, 8, 2)
ol := seq(-9, 9, 2)
il := seq(0, 9, 1)
var rares []int64
lists := make([][][]int8, 4)
for i, f := range fl {
lists[i] = [][]int8{{f}}
}
fmt.Printf("The rare numbers with up to %d digits are:\n", maxDigits)
for nd := 2; nd <= maxDigits; nd++ {
digits := make([]int8, nd)
if nd == 4 {
lists[0] = append(lists[0], zl)
lists[1] = append(lists[1], ol)
lists[2] = append(lists[2], el)
lists[3] = append(lists[3], ol)
} else if len(allTerms[nd-2]) > len(lists[0]) {
for i := 0; i < 4; i++ {
lists[i] = append(lists[i], dl)
}
switch a {
case 3:
digits[ai], digits[qi] = 4, 0
case 5:
digits[ai], digits[qi] = 6, 0
case 7:
digits[ai], digits[qi] = 8, 2
case 9:
digits[ai], digits[qi] = 0, 2
ai--
digits[ai] = 2
}
a = digits[ai]
}
ifvar qi-ai >indices [][2 {]int8
for b_, pt := digits[ai+1],range digitsallTerms[qind-12] {
switchindices a= append(indices, [2]int8{t.ix1, t.ix2})
case 2:}
 
if b < p {
for _, list := range lists {
cands := cp(list...)
for _, cand := range cands {
nmr := int64(0)
for i, t := range allTerms[nd-2] {
nmr += t.coeff * int64(cand[i])
}
if nmr <= 0 || !isSquare(nmr) {
continue
} else if b > p {
digits[qi-1] = b
}
case 4: var dis [][]int8
ifdis = append(b-p)%2dis, !=seq(0, int8(len(fml[cand[0]]))-1, {1))
for i := 1; if pi < 9len(cand); i++ {
dis = append(dis, seq(0, digitsint8(len(dmd[qicand[i]]))-1]++, 1))
} else {
continue
}
}
case 6: if nd%2 == 1 {
if (b-p)%2 = dis = 0append(dis, {il)
if p < 9 {
digits[qi-1]++
} else {
continue
}
}
case 8: dis = cp(dis...)
switchfor digits[qi]_, di := range dis {
case 2: digits[indices[0][0]] = fml[cand[0]][di[0]][0]
ifdigits[indices[0][1]] b+p != 9 {fml[cand[0]][di[0]][1]
le := if p < 9-b {len(di)
if nd%2 == digits[qi-1] = 9 - b{
} else {le--
digits[nd/2] = continuedi[le]
}
}
case 7 for i, d := range di[1:le] {
if b > 1 && (bdigits[indices[i+p)1][0]] != 11 {dmd[cand[i+1]][d][0]
ifdigits[indices[i+1][1]] p= < 11-b {dmd[cand[i+1]][d][1]
digits[qi-1] = 11 - b
} else {
continue
}
} else if b < 1 && (b+p) != 1 {
if p == 0 {
digits[qi-1] = 1
} else {
continue
}
}
case 8 r := toInt64(digits, true)
ifnpr b:= <nmr p+ {2*r
if !isSquare(npr) {
continue
} else if b > p {
if (b-p)%2 == 0 {
digits[qi-1] = b
} else {
continue
}
}
rares = append(rares, toInt64(digits, false))
}
}
}
s := sumDigitSlice(digits, ai)
dr := digRoot(s)
if dr != 2 && dr != 5 && dr != 8 && dr != 9 {
continue
}
n := toUint64(digits, ai, false)
r := toUint64(digits, ai, true)
if n <= r || !possibleSquare(n+r) || !possibleSquare(n-r) {
continue
}
for _, x := range [2]uint64{n + r, n - r} {
z := x % 10
if z == 2 || z == 3 || z == 7 || z == 8 {
continue outer
}
y := (x / 10) % 10
switch z {
case 0:
if y != 0 {
continue outer
}
case 5:
if y != 2 {
continue outer
}
case 6:
if y%2 == 0 {
continue outer
}
case 1, 4, 9:
if y%2 == 1 {
continue outer
}
}
dr = digRoot(x)
if dr != 1 && dr != 4 && dr != 7 && dr != 9 {
continue outer
}
}
fn, fr := float64(n), float64(r)
sr := uint64(math.Sqrt(fn + fr))
if sr*sr != n+r {
continue
}
sr = uint64(math.Sqrt(fn - fr))
if sr*sr != n-r {
continue
}
count++
fmt.Printf(" %d: %15s\n", count, commatize(n))
if count == maxCount {
break
}
}
sort.Slice(rares, func(i, j int) bool { return rares[i] < rares[j] })
fmt.Printf("\nTook %s\n", time.Since(start))
for i, rare := range rares {
fmt.Printf(" %2d: %19s\n", i+1, commatize(rare))
}
fmt.Printf("\nUp to %d digits processed in %s\n", maxDigits, time.Since(start))
}</lang>
 
{{output}}
<pre>
The first 8 rare numbers with up to 15 digits are:
1: 65
2: 621,770
3: 281,089,082
4: 2,022,652,202
5: 2,042,832,002
6: 868,591,084,757
7: 872,546,974,178
8: 872,568,754,178
9: 6,979,302,951,885
10: 20,313,693,904,202
11: 20,313,839,704,202
12: 20,331,657,922,202
13: 20,331,875,722,202
14: 20,333,875,702,202
15: 40,313,893,704,200
16: 40,351,893,720,200
17: 200,142,385,731,002
18: 204,238,494,066,002
19: 221,462,345,754,122
20: 244,062,891,224,042
21: 245,518,996,076,442
22: 248,359,494,187,442
23: 403,058,392,434,500
24: 441,054,594,034,340
25: 816,984,566,129,618
 
Up to 15 digits processed in 28.174979081s
Took 12m43.807949011s
</pre>