Beispiel #1
0
        /// <summary>
        /// Computes the natural logarithm of a double double value.
        /// </summary>
        /// <param name="x">The argument of the logarithm.</param>
        /// <returns>The value of ln(x).</returns>
        public static DoubleDouble Log(DoubleDouble x)
        {
            double logHi = Math.Log(x.hi);

            if (ExtendedMath.IsNotFinite(logHi))
            {
                return((DoubleDouble)logHi);
            }

            int e = (int)Math.Round(logHi / Global.LogTwo);

            if (e < 0)
            {
                x *= DoubleDouble.Pow(2.0, -e);
            }
            else if (e > 0)
            {
                x /= DoubleDouble.Pow(2.0, e);
            }
            // At this point 1/\sqrt{2} <= r <= \sqrt{2},
            // i.e.  0.707 <= r <= 1.414
            x -= DoubleDouble.One;
            // Now -0.293 <= r - 1 <= 0.414.
            // We have lost some accuracy if r ~ 1, i.e. x was very close
            // to an exact power of 2.

            return(e * log2 + Log1P(x));
        }
Beispiel #2
0
        /// <summary>
        /// Computes the square root of a double double value.
        /// </summary>
        /// <param name="x">The value of which the square root will be computed.</param>
        /// <returns>The value of the square root of x.</returns>
        public static DoubleDouble Sqrt(DoubleDouble x)
        {
            if (Double.IsNaN(x.hi))
            {
                return(x);
            }

            if (x.hi < 0.0)
            {
                return(Double.NaN);
            }

            if (x.hi == 0.0)
            {
                return(0.0);
            }

            double yHi = Math.Sqrt(x.hi);

            double uHi, uLo;

            ExtendedMath.TwoProduct(yHi, yHi, out uHi, out uLo);

            double yLo = (((x.hi - uHi) - uLo) + x.lo) / (2.0 * yHi);

            return(new DoubleDouble(yHi, yLo));
        }
Beispiel #3
0
        /// <summary>
        /// Computes the product of two double double numbers.
        /// </summary>
        /// <param name="x">The first number.</param>
        /// <param name="y">The second number.</param>
        /// <returns>The product of <paramref name="x"/> and <paramref name="y"/>.</returns>
        public static DoubleDouble operator *(DoubleDouble x, DoubleDouble y)
        {
            ExtendedMath.TwoProduct(x.hi, y.hi, out double p0, out double p1);

            if (p0 == 0.0 || ExtendedMath.IsNotFinite(p0))
            {
                return((DoubleDouble)p0);
            }

            ExtendedMath.TwoProduct(x.hi, y.lo, out double p2, out double p4);

            ExtendedMath.TwoProduct(x.lo, y.hi, out double p3, out double p5);

            double p6 = x.lo * y.lo;

            ExtendedMath.ThreeSum(p1, p2, p3, out double t1, out double t2);

            t2 += p4 + p5 + p6;

            ExtendedMath.ThreeSum(p0, t1, t2, out double pHi, out double pLo);

            return(new DoubleDouble(pHi, pLo));

            /*
             * double zHi, zLo;
             * ExtendedMath.TwoProduct(a.hi, b.hi, out zHi, out zLo);
             * zLo = (zLo + a.hi * b.lo) + a.lo * b.hi;
             * //zLo = (a.hi * b.lo + a.lo * b.hi) + zLo;
             *
             * return new DoubleDouble(zHi, zLo);
             */
        }
Beispiel #4
0
        /// <summary>
        /// Computes the quotient of two double double numbers.
        /// </summary>
        /// <param name="a">The dividend.</param>
        /// <param name="b">The divisor.</param>
        /// <returns>The value of <paramref name="a"/> / <paramref name="b"/>.</returns>
        public static DoubleDouble operator /(DoubleDouble a, DoubleDouble b)
        {
            double       q1 = a.hi / b.hi;
            DoubleDouble r  = a - q1 * b;
            double       q2 = r.hi / b.hi;

            r = r - q2 * b;
            double q3 = r.hi / b.hi;

            double qHi, qLo;

            double t1, t2, t3;

            ExtendedMath.TwoSum(q1, q2, out t1, out t2);
            ExtendedMath.TwoSum(q3, t1, out qHi, out t3);
            ExtendedMath.TwoSum(t2, t3, out qLo, out t1);

            return(new DoubleDouble(qHi, qLo));

            /*
             * // Compute an initial approximation by dividing hi parts.
             * double qHi = a.hi / b.hi;
             *
             * // Compute the product of qHi and bHi to full precision.
             * // Ideally this would be exactly aHi but it won't be.
             * double uHi, uLo;
             * ExtendedMath.TwoProduct(qHi, b.hi, out uHi, out uLo);
             *
             * // Now compute the correction and but it in qLo.
             * double qLo = ((((a.hi - uHi) - uLo) + a.lo) - qHi * b.lo) / b.hi;
             *
             * return new DoubleDouble(qHi, qLo);
             */
        }
        public static void ThreeSum(double a, double b, double c, out double sum, out double err)
        {
            double t1, t2, t3;

            ExtendedMath.TwoSum(a, b, out t1, out t2);
            ExtendedMath.TwoSum(c, t1, out sum, out t3);
            ExtendedMath.TwoSum(t2, t3, out err, out t1);
        }
Beispiel #6
0
        /// <summary>
        /// Computes the sum of two double double numbers.
        /// </summary>
        /// <param name="x">The first number.</param>
        /// <param name="y">The second number.</param>
        /// <returns>The value of <paramref name="x"/> + <paramref name="y"/>.</returns>
        public static DoubleDouble operator +(DoubleDouble x, DoubleDouble y)
        {
            // Add high components
            ExtendedMath.TwoSum(x.hi, y.hi, out double sHi, out double sLo);

            if (ExtendedMath.IsNotFinite(sHi))
            {
                return((DoubleDouble)sHi);
            }

            // Add low components
            ExtendedMath.TwoSum(x.lo, y.lo, out double tHi, out double tLo);
            ExtendedMath.TwoSum(sHi, sLo + tHi, out double vHi, out double vLo);
            ExtendedMath.FastTwoSum(vHi, tLo + vLo, out double zHi, out double zLo);

            return(new DoubleDouble(zHi, zLo));
        }
Beispiel #7
0
        /// <summary>
        /// Computes the quotient of two double double numbers.
        /// </summary>
        /// <param name="x">The dividend.</param>
        /// <param name="y">The divisor.</param>
        /// <returns>The value of <paramref name="x"/> / <paramref name="y"/>.</returns>
        public static DoubleDouble operator /(DoubleDouble x, DoubleDouble y)
        {
            double q1 = x.hi / y.hi;

            // If leading order result is NaN or infinity or zero, we are done.
            // To continue would introduce NaNs even if result is infinite, so this early return is necessary.
            if (q1 == 0.0 || ExtendedMath.IsNotFinite(q1))
            {
                return((DoubleDouble)q1);
            }

            DoubleDouble r  = x - q1 * y;
            double       q2 = r.hi / y.hi;

            r = r - q2 * y;
            double q3 = r.hi / y.hi;

            double qHi, qLo;

            double t1, t2, t3;

            ExtendedMath.TwoSum(q1, q2, out t1, out t2);
            ExtendedMath.TwoSum(q3, t1, out qHi, out t3);
            ExtendedMath.TwoSum(t2, t3, out qLo, out t1);

            return(new DoubleDouble(qHi, qLo));

            /*
             * // Compute an initial approximation by dividing hi parts.
             * double qHi = a.hi / b.hi;
             *
             * // Compute the product of qHi and bHi to full precision.
             * // Ideally this would be exactly aHi but it won't be.
             * double uHi, uLo;
             * ExtendedMath.TwoProduct(qHi, b.hi, out uHi, out uLo);
             *
             * // Now compute the correction and but it in qLo.
             * double qLo = ((((a.hi - uHi) - uLo) + a.lo) - qHi * b.lo) / b.hi;
             *
             * return new DoubleDouble(qHi, qLo);
             */
        }
Beispiel #8
0
        /// <summary>
        /// Computes the square root of a double double value.
        /// </summary>
        /// <param name="x">The value of which the square root will be computed.</param>
        /// <returns>The value of the square root of x.</returns>
        public static DoubleDouble Sqrt(DoubleDouble x)
        {
            if (x.hi == 0.0)
            {
                return(0.0);
            }

            double yHi = Math.Sqrt(x.hi);

            if (ExtendedMath.IsNotFinite(yHi))
            {
                return((DoubleDouble)yHi);
            }

            ExtendedMath.TwoProduct(yHi, yHi, out double uHi, out double uLo);

            double yLo = (((x.hi - uHi) - uLo) + x.lo) / (2.0 * yHi);

            return(new DoubleDouble(yHi, yLo));
        }
Beispiel #9
0
        /// <summary>
        /// Computes the sum of two double double numbers.
        /// </summary>
        /// <param name="a">The first number.</param>
        /// <param name="b">The second number.</param>
        /// <returns>The value of <paramref name="a"/> + <paramref name="b"/>.</returns>
        public static DoubleDouble operator +(DoubleDouble a, DoubleDouble b)
        {
            // Add high components
            double sHi, sLo;

            ExtendedMath.TwoSum(a.hi, b.hi, out sHi, out sLo);

            // Add low components
            double tHi, tLo;

            ExtendedMath.TwoSum(a.lo, b.lo, out tHi, out tLo);

            double vHi, vLo;

            ExtendedMath.TwoSum(sHi, sLo + tHi, out vHi, out vLo);

            double zHi, zLo;

            ExtendedMath.FastTwoSum(vHi, tLo + vLo, out zHi, out zLo);

            return(new DoubleDouble(zHi, zLo));
        }
Beispiel #10
0
        /// <summary>
        /// Computes the product of two double double numbers.
        /// </summary>
        /// <param name="a">The first number.</param>
        /// <param name="b">The second number.</param>
        /// <returns>The product of <paramref name="a"/> and <paramref name="b"/>.</returns>
        public static DoubleDouble operator *(DoubleDouble a, DoubleDouble b)
        {
            double p0, p1;

            ExtendedMath.TwoProduct(a.hi, b.hi, out p0, out p1);

            double p2, p4;

            ExtendedMath.TwoProduct(a.hi, b.lo, out p2, out p4);

            double p3, p5;

            ExtendedMath.TwoProduct(a.lo, b.hi, out p3, out p5);

            double p6 = a.lo * b.lo;

            double t1, t2;

            ExtendedMath.ThreeSum(p1, p2, p3, out t1, out t2);

            t2 += p4 + p5 + p6;

            double pHi, pLo;

            ExtendedMath.ThreeSum(p0, t1, t2, out pHi, out pLo);

            return(new DoubleDouble(pHi, pLo));

            /*
             * double zHi, zLo;
             * ExtendedMath.TwoProduct(a.hi, b.hi, out zHi, out zLo);
             * zLo = (zLo + a.hi * b.lo) + a.lo * b.hi;
             * //zLo = (a.hi * b.lo + a.lo * b.hi) + zLo;
             *
             * return new DoubleDouble(zHi, zLo);
             */
        }
Beispiel #11
0
        /// <summary>
        /// Produces a text representation of the double double value using the given format provider.
        /// </summary>
        /// <param name="format">The format provider.</param>
        /// <returns>A text representation of the value.</returns>
        private string ToString(IFormatProvider format)
        {
            // This algorithm doesn't handle infinities, NaNs, and zeros, but writing them is trivial.
            if (ExtendedMath.IsNotFinite(hi) || hi == 0.0)
            {
                return(hi.ToString(format));
            }

            // Multiply by a power of 10 to put leading digit in the ones place
            Debug.Assert(hi != 0.0);
            int          e = (int)Math.Floor(Math.Log10(Math.Abs(hi)));
            DoubleDouble r = Abs(this);

            if (e > 0)
            {
                r /= Pow(ten, e);
            }
            else if (e < 0)
            {
                r *= Pow(ten, -e);
            }

            // If scaling has screwed us up because of overflow, exit. Fix this.
            if (Double.IsNaN(r.hi) || Double.IsNaN(r.lo))
            {
                return("X");
            }

            // Spit out up to 32 digits
            StringBuilder s = new StringBuilder();
            int           z = 0;

            for (int i = 0; i < 32; i++)
            {
                if (r.hi == 0.0)
                {
                    break;
                }
                double t = Math.Floor(r.hi); /* If nothing left, we can stop early */
                if (t < 0)
                {
                    t = 0.0;        /* if we subtract to zero, sometimes the result can be a very tiny negative number that floors to -1 */
                }
                int d = (int)t;
                Debug.Assert((0 <= d) && (d < 10));
                s.Append(d);
                if (d == 0)
                {
                    z++;
                }
                else
                {
                    z = 0;
                }                                    /* Keep track of number of trailing zeros for later truncation */
                r -= t;
                r *= ten;
            }

            // Remove trailing zeros (which are all after the decimal point)
            if (z > 0)
            {
                s.Remove(s.Length - z, z);
            }

            // Express in scientific notation for large exponents,
            // or by filling in zeros for small exponents.
            if (e >= 6)
            {
                if (s.Length > 1)
                {
                    s.Insert(1, '.');
                }
                s.Append($"E{e}");
            }
            else if (e >= 0)
            {
                if (s.Length > e + 1)
                {
                    s.Insert(e + 1, '.');
                }
                else
                {
                    s.Append("000000", 0, e - s.Length + 1);
                }
            }
            else if (e >= -4)
            {
                s.Insert(0, "0.00000".Substring(0, 1 - e)); /* StringBuilder.Append has a substring overload, but StringBuilder.Insert doesn't */
            }
            else
            {
                if (s.Length > 1)
                {
                    s.Insert(1, '.');
                }
                s.Append($"E{e}");
            }

            // Add a negative sign if necessary
            if (hi < 0.0)
            {
                s.Insert(0, '-');
            }

            return(s.ToString());
        }