Esempio n. 1
0
        // this = this * other.
        void Multiply(DiyFp other)
        {
            // Simply "emulates" a 128 bit multiplication.
            // However: the resulting number only contains 64 bits. The least
            // significant 64 bits are only used for rounding the most significant 64
            // bits.
            const ulong kM32 = 0xFFFFFFFFU;
            ulong       a    = F >> 32;
            ulong       b    = F & kM32;
            ulong       c    = other.F >> 32;
            ulong       d    = other.F & kM32;
            ulong       ac   = a * c;
            ulong       bc   = b * c;
            ulong       ad   = a * d;
            ulong       bd   = b * d;
            ulong       tmp  = (bd >> 32) + (ad & kM32) + (bc & kM32);

            // By adding 1U << 31 to tmp we round the final result.
            // Halfway cases will be round up.
            tmp += 1U << 31;
            ulong result_f = ac + (ad >> 32) + (bc >> 32) + (tmp >> 32);

            E += other.E + 64;
            F  = result_f;
        }
Esempio n. 2
0
        // returns a * b;
        public static DiyFp operator *(DiyFp a, DiyFp b)
        {
            DiyFp result = a;

            result.Multiply(b);
            return(result);
        }
Esempio n. 3
0
        // Returns a - b.
        // The exponents of both numbers must be the same and this must be bigger
        // than other. The result will not be normalized.
        public static DiyFp operator -(DiyFp a, DiyFp b)
        {
            DiyFp result = a;

            result.Subtract(b);
            return(result);
        }
Esempio n. 4
0
        public static DiyFp Normalize(DiyFp a)
        {
            DiyFp result = a;

            result.Normalize();
            return(result);
        }
Esempio n. 5
0
        public static bool ToString(
            double v,
            bool isSinglePrecision,
            Span <byte> buffer,
            out int length,
            out int decimal_exponent)
        {
            DiyFp w = new DoubleView(v).AsNormalizedDiyFp();

            DiyFp boundary_minus, boundary_plus;

            if (!isSinglePrecision)
            {
                new DoubleView(v).NormalizedBoundaries(out boundary_minus, out boundary_plus);
            }
            else
            {
                new SingleView((float)v).NormalizedBoundaries(out boundary_minus, out boundary_plus);
            }
            Debug.Assert(boundary_plus.E == w.E);
            int ten_mk_minimal_binary_exponent = kMinimalTargetExponent - (w.E + DiyFp.SignificandSize);
            int ten_mk_maximal_binary_exponent = kMaximalTargetExponent - (w.E + DiyFp.SignificandSize);

            PowersOfTenCache.GetCachedPowerForBinaryExponentRange(
                ten_mk_minimal_binary_exponent,
                ten_mk_maximal_binary_exponent,
                out var ten_mk, out var mk);
            Debug.Assert((kMinimalTargetExponent <= w.E + ten_mk.E +
                          DiyFp.SignificandSize) &&
                         (kMaximalTargetExponent >= w.E + ten_mk.E +
                          DiyFp.SignificandSize));

            DiyFp scaled_w = (w * ten_mk);

            Debug.Assert(scaled_w.E ==
                         boundary_plus.E + ten_mk.E + DiyFp.SignificandSize);

            DiyFp scaled_boundary_minus = (boundary_minus * ten_mk);
            DiyFp scaled_boundary_plus  = (boundary_plus * ten_mk);

            bool result = DigitGen(scaled_boundary_minus, scaled_w, scaled_boundary_plus,
                                   buffer, out length, out var kappa);

            decimal_exponent = -mk + kappa;
            return(result);
        }
Esempio n. 6
0
        public void NormalizedBoundaries(out DiyFp out_m_minus, out DiyFp out_m_plus)
        {
            Debug.Assert(Value > 0.0);
            DiyFp v      = AsDiyFp();
            DiyFp m_plus = DiyFp.Normalize(new DiyFp((v.F << 1) + 1, v.E - 1));
            DiyFp m_minus;

            if (LowerBoundaryIsCloser())
            {
                m_minus = new DiyFp((v.F << 2) - 1, v.E - 2);
            }
            else
            {
                m_minus = new DiyFp((v.F << 1) - 1, v.E - 1);
            }

            m_minus.F = m_minus.F << (m_minus.E - m_plus.E);
            m_minus.E = m_plus.E;

            out_m_plus  = m_plus;
            out_m_minus = m_minus;
        }
Esempio n. 7
0
 // this = this - other.
 // The exponents of both numbers must be the same and the significand of this
 // must be bigger than the significand of other.
 // The result will not be normalized.
 void Subtract(DiyFp other)
 {
     Debug.Assert(E == other.E);
     Debug.Assert(F >= other.F);
     F -= other.F;
 }
Esempio n. 8
0
        private static bool DigitGen(
            DiyFp low,
            DiyFp w,
            DiyFp high,
            Span <byte> buffer,
            out int length,
            out int kappa)
        {
            Debug.Assert(low.E == w.E && w.E == high.E);
            Debug.Assert(low.F + 1 <= high.F - 1);
            Debug.Assert(kMinimalTargetExponent <= w.E && w.E <= kMaximalTargetExponent);

            ulong unit            = 1;
            DiyFp too_low         = new DiyFp(low.F - unit, low.E);
            DiyFp too_high        = new DiyFp(high.F + unit, high.E);
            DiyFp unsafe_interval = too_high - too_low;
            DiyFp one             = new DiyFp(1UL << -w.E, w.E);
            uint  integrals       = unchecked ((uint)(too_high.F >> -one.E));
            ulong fractionals     = too_high.F & (one.F - 1);

            BiggestPowerTen(integrals, DiyFp.SignificandSize - (-one.E),
                            out var divisor, out var divisor_exponent_plus_one);
            kappa  = divisor_exponent_plus_one;
            length = 0;
            while (kappa > 0)
            {
                int digit = unchecked ((int)(integrals / divisor));
                Debug.Assert(digit <= 9);
                buffer[length] = (byte)('0' + digit);
                length++;
                integrals %= divisor;
                kappa--;
                ulong rest =
                    ((ulong)(integrals) << -one.E) + fractionals;
                if (rest < unsafe_interval.F)
                {
                    return(RoundWeed(buffer, length, (too_high - w).F,
                                     unsafe_interval.F, rest,
                                     (ulong)(divisor) << -one.E, unit));
                }
                divisor /= 10;
            }

            Debug.Assert(one.E >= -60);
            Debug.Assert(fractionals < one.F);
            Debug.Assert(0xFFFFFFFF_FFFFFFFFUL / 10 >= one.F);
            for (; ;)
            {
                fractionals      *= 10;
                unit             *= 10;
                unsafe_interval.F = (unsafe_interval.F * 10);
                int digit = unchecked ((int)(fractionals >> -one.E));
                Debug.Assert(digit <= 9);
                buffer[length] = (byte)('0' + digit);
                (length)++;
                fractionals &= one.F - 1;  // Modulo by one.
                (kappa)--;
                if (fractionals < unsafe_interval.F)
                {
                    return(RoundWeed(buffer, length, (too_high - w).F * unit,
                                     unsafe_interval.F, fractionals, one.F, unit));
                }
            }
        }