January 10, 2017
My first version of the program prebuilt the prime string to some large length and simply indexed into that string. That worked, but I was dissatisfied because it required a large amount of storage, and inevitably fails when a too-large n is requested. But it did make a nice way to check results of my finished algorithm, so it wasn’t a total loss.
My second version of the program tried to calculate the lengths of the primes and work out where exactly the index occurred within the sequence of prime numbers, but that didn’t work; more precisely, I never convinced myself that I had found the last bug in the program. The problem is that there are lots of edge cases where the requested index doesn’t point to the beginning of a prime, and there are other edge cases where the next five characters spill across a boundary from one prime length to another, and my code kept getting more and more complicated to handle those edge cases, so eventually I threw away that version.
The third version of the program keeps a sliding window on the string, generating primes as necessary. If the window is too small, it is extended. If the index of the first character in the window is less than the target index, the window slides one character to the right. When the window finally reaches the target index, there are guaranteed to be enough characters to form a result, so the function returns. There are no special edge cases at the beginning of the prime string, or when the number of digits in the current prime is greater than its predecessor, or when the target index points to the middle of a prime, or anything else:
(define (prime-substring n) (let ((ps (primegen))) (let loop ((i 0) (str "")) (cond ((string (ps))))) ((< i n) (loop (+ i 1) (substring str 1 (string-length str)))) (else (substring str 0 5))))))
Here are some examples:
> (prime-substring 50) "03107" > (prime-substring 1000) "98719" > (prime-substring 10000) "02192"
Pages: 1 2