Deutsch   English   Français   Italiano  
<vqceue$g9g$2@reader1.panix.com>

View for Bookmarking (what is this?)
Look up another Usenet article

Path: news.eternal-september.org!eternal-september.org!feeder3.eternal-september.org!panix!.POSTED.spitfire.i.gajendra.net!not-for-mail
From: cross@spitfire.i.gajendra.net (Dan Cross)
Newsgroups: alt.folklore.computers,comp.os.linux.misc
Subject: Re: The joy of FORTRAN
Followup-To: alt.folklore.computers
Date: Thu, 6 Mar 2025 15:28:14 -0000 (UTC)
Organization: PANIX Public Access Internet and UNIX, NYC
Message-ID: <vqceue$g9g$2@reader1.panix.com>
References: <59CJO.19674$MoU3.15170@fx36.iad> <vqb267$lig$1@reader1.panix.com> <m2sohjF3sciU1@mid.individual.net> <vqceia$g9g$1@reader1.panix.com>
Injection-Date: Thu, 6 Mar 2025 15:28:14 -0000 (UTC)
Injection-Info: reader1.panix.com; posting-host="spitfire.i.gajendra.net:166.84.136.80";
	logging-data="16688"; mail-complaints-to="abuse@panix.com"
X-Newsreader: trn 4.0-test77 (Sep 1, 2010)
Originator: cross@spitfire.i.gajendra.net (Dan Cross)

[Note: Followup-To: set to remove comp.os.linux.misc.
The discussion doesn't feel particularly relevant there.]

In article <vqceia$g9g$1@reader1.panix.com>,
Dan Cross <cross@spitfire.i.gajendra.net> wrote:
>In article <m2sohjF3sciU1@mid.individual.net>,
>rbowman  <bowman@montana.com> wrote:
>>On Thu, 6 Mar 2025 02:44:23 -0000 (UTC), Dan Cross wrote:
>>
>>> At best, he reminds me of Herb Schildt.
>>
>>There's a name I haven't heard in a long time, he of 'void main(void)' 
>>fame.
>
>That's the one.  Generations of programmers led astray by that
>guy's books.
>
>>https://www.seebs.net/c/c_tcn4e.html
>>
>>"C: The Complete Reference is a popular programming book, marred only by 
>>the fact that it is largely tripe. Herbert Schildt has a knack for clear, 
>>readable text, describing a language subtly but quite definitely different 
>>from C."
>
>That describes Martin's books to a T, I think.  He writes very
>well, but what he writes, maybe not so much.
>
>Since the topic of their prime number generator program came up,
>I'll append my version here.  Caveat that I'm not at all a Java
>programmer (let us give things to zog for small blessings), I
>think it's better than ether version presented in the Martin and
>Ousterhout debate, though I'm sure it could be further improved.
>
>This version tends closer to Knuth (and Dijkstra, where Knuth
>got it) than either of the two in the debate at
>https://github.com/johnousterhout/aposd-vs-clean-code

Oh gee; a bunch of tab literals snuck in there, which messed up
the formatting when posted.  :-(  With my apologies, here's a
fixed-up version.

	- Dan C.

--->BEGIN Primes.java<---
package literatePrimes;

public class Primes {
    // The algorithm used here comes from Dijkstra via Knuth.  The basic
    // idea is to special case 2, as the first (and only even) prime
    // number, and then step through the odd integers, testing each as
    // a candidate for primality.  A number is prime iff it is not
    // evenly divisible by any smaller prime.
    //
    // To understand how it works, observe that for any composite
    // number j, the smallest prime factor of j will be less than or
    // equal to sqrt(j).  Hence, when testing a candidate for primality,
    // we need not consider whether primes larger than the candidate's
    // square root evenly divide the candidate.  As the number of
    // generated primes grows, the number of primes smaller than the
    // square root grows much more slowly, cutting down on the search
    // space and yielding a considerable performance benefit.
    //
    // When iterating, we are only concerned about the odd primes,
    // so we only need to consider odd candidates starting from 3.  By
    // definition such candidates are not divisible by 2 and so the
    // problem of determining primality is reduced to determining whether
    // a is candidate odd and divisible by some other prime less than or
    // equal to the square root of the candidate.
    //
    // As a further optimization, we avoid division by maintaining an
    // auxilliary array of multiples of primes; that is, a table,
    // `primeMultiples` of multiples of primes p_n.  By maintaining the
    // invariant that, for a given candidate j and prime p_n,
    // primeMultiples[n] < j + 2*p_n, we can quickly test j for
    // divisibility by p_n: if primeMultiples[n] < j, then clearly the
    // invariant holds if we add 2*p_n to primeMultiples[n].  However,
    // if primeMultiples[n] >= j + 2*p_n, then p_n is a factor of j if
    // and only if primeMultiples[n] = j.
    //
    // Note that the factor of 2 in 2*p_n ensures that `primeMultiples[n]`
    // always remains odd, for n > 0: 2*odd is even, and odd+even is odd.
    //
    // To avoid the performance impact of computing square roots, we keep
    // track of the square of the prime that's square root is greater
    // than the square root of the current candidate, and we use this to
    // define an upper bound on multiples table entries that we must
    // use to test a candidate for divisibility.  When we have increased
    // the candidate value such that it becomes equal to this tracked
    // square value, we increase the bound by 1, reset the tracked square
    // to that of the prime now indexed by the new upper bound, and add
    // an entry to the primeMultiples table.  It is safe to refer to the
    // next such prime because we know from "Bertrand's Postulate" that,
    // for a given prime p_n, the next prime p_{n+1} < 2*p_n, and
    // 2*p_n < p_n^2 for p_nn > 2, so such a prime must already have been
    // generated.  Therefore, we simply add the next prime's square to the
    // table as the first multiple of p_{n+1} and set `square` to that
    // same value.
    //
    // Readers who want a deeper explanation may refer to:
    // Knuth, Donald E. 1982. Literate Programming. _The Computer
    // Journal_ 27, 2 (1984), 97-111.
    // http://www.literateprogramming.com/knuthweb.pdf

    private int[] primeMultiples;
    private int[] primes;
    private int nPrimes;
    private int multiplesUpperBound;
    private int nextCandidate;
    private int square;

    // Resets generator state and fills the `primes` array in
    // ascending order.  Note that, as a special case, `reset`
    // returns the first prime number (2), so that we do not
    // have to consider even numbers later.  This simplifies
    // the `next` method, since it only needs to consider odd
    // numbers, and eliminating a conditional probably confers
    // a slight performance advantage.
    private void fill(int[] primes) {
        primes[0] = reset(primes);
        for (int i = 1; i < primes.length; i++) {
            primes[i] = next();
        }
    }

    // Resets the generator state and returns 2: the first, and
    // only even, prime number.
    //
    // The resulting state is set so that the first subsequent
    // invocation of `next` will return the first odd prime, 3.
    // Note that a user must call `reset` before the first
    // invocation of `next`.
    private int reset(int[] primes) {
        nextCandidate = 3;
        this.primes = primes;
        multiplesUpperBound = 1;
        nPrimes = 1;
        primeMultiples = new int[multiplesUpperBound + 1 + primes.length / 2];
        square = 9;
        primeMultiples[multiplesUpperBound] = square;
        return 2;
    }

    // Computes, stores, and returns the next odd prime.
    // The first time this is called, it will return 3,
    // then 5, 7, 11, and so on, up to the defined maximum
    // number of primes.  Attempts to invoke `next` beyond
    // the maximum will generate exceptions, as they try
    // to index beyond the end of the `primes` array.
    //
    // `reset` must be called before the first invocation
    // of `next`.
    private int next() {
        candidates: for (;;) {
            int candidate = nextCandidate;
            nextCandidate += 2;
            if (candidate == square) {
                multiplesUpperBound++;
                square = primes[multiplesUpperBound] * primes[multiplesUpperBound];
                primeMultiples[multiplesUpperBound] = square;
            }
            for (int i = 1; i < multiplesUpperBound; i++) {
                while (primeMultiples[i] < candidate) {
                    primeMultiples[i] += 2*primes[i];
                }
                if (primeMultiples[i] == candidate) {
                    continue candidates;
                }
            }
            primes[nPrimes] = candidate;
            nPrimes++;
            return candidate;
        }
    }

    /**
     * Returns an array of integers holding the first _n_ prime
     * numbers, in ascending order.  Returns null if n < 1.
     *
     * @param n
     *     The number of primes to return.
     */
    public static int[] getFirst(int n) {
        if (n < 1)
            return null;
        var primes = new int[n];
========== REMAINDER OF ARTICLE TRUNCATED ==========