/// <summary>
        /// Run a test on the rand generators, return true on success
        /// </summary>
        /// <param type="outputAction"></param>
        /// <returns></returns>
        public static bool Test64(Action <string> outputAction)
        {
            TestRand01(outputAction);

            // local testing helper
            Func <Action <string>, bool, ulong[], bool> RunTest = (printf, use128Bit, vals) =>
            {
                var rand = new LocalRandom(use128Bit, 0, 0);
                rand.SetSeed(42, 0);     // seed from paper

                var success1 = true;
                foreach (var correctValue in vals)
                {
                    var randValue = rand.Next64();
                    printf($"0x{randValue:X16}=0x{correctValue:X16}, {randValue == correctValue} ");
                    success1 &= randValue == correctValue;
                }
                return(success1);
            };

            var success = true;

            outputAction("Testing rand 64");
            success &= RunTest(outputAction, false, new ulong[]
            {
                0x27a53829edf003a9,
                0xdf28458e5c04c31c,
                0x2756dc550bc36037,
                0xa10325553eb09ee9,
                0x40a0fccb8d9df09f,
                0x5c2047cfefb5e9ca
            });
            outputAction("Testing rand 128");
            success &= RunTest(outputAction, true, new ulong[]
            {
                0x287472e87ff5705a,
                0xbbd190b04ed0b545,
                0xb6cee3580db14880,
                0xbf5f7d7e4c3d1864,
                0x734eedbe7e50bbc5,
                0xa5b6b5f867691c77
            });
            outputAction(success ? "Rand test succeeded." : "Rand test failed.");
            return(success);
        }
        public static double Sample(LocalRandom random, double mean, double standardDeviation)
        {
            const double epsilon = Double.Epsilon;

            // note: could get two for the price of one if not static
            //generate = !generate;
            //if (!generate)
            //    return z1 * Parameter + Mean;

            double u1, u2;

            do
            {
                u1 = random.NextDouble();
                u2 = random.NextDouble();
            }while (u1 <= epsilon);

            var z0 = Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Cos(2 * Math.PI * u2);

            // var z1 = Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Sin(2*Math.PI * u2);
            return(z0 * standardDeviation + mean);
        }
        public static double Sample(LocalRandom random, double mean = 0, double parameter = 1)
        {
            var u = random.NextDouble() - 0.5;

            return(mean - parameter * Math.Sign(u) * Math.Log(1 - 2 * Math.Abs(u)));
        }