diff --git a/Numbers.nuspec b/Numbers.nuspec index 0639aab..2d2f8a0 100644 --- a/Numbers.nuspec +++ b/Numbers.nuspec @@ -22,4 +22,4 @@ Version 1.7.0 - Added Log1P and ExpM1 methods to EDecimal and EFloat - Added 'long' overloads to several arithmetic methods - Added implication and equivalence (Imp/Eqv) methods and an nth-root method to EIntegerCC0-1.0https://github.com/peteroupc/NumbersPeter OccilA C# library that supports arbitrary-precision binary and decimal floating-point numbers and rational numbers with arbitrary-precision components, and supports arithmetic with these numbers.Peter OccilArbitrary-Precision Number Librarynumbers arithmetic decimal math \ No newline at end of file +> diff --git a/Numbers/PeterO/Numbers/EDecimal.cs b/Numbers/PeterO/Numbers/EDecimal.cs index 17db6ea..5ad3430 100644 --- a/Numbers/PeterO/Numbers/EDecimal.cs +++ b/Numbers/PeterO/Numbers/EDecimal.cs @@ -1398,8 +1398,8 @@ public sealed partial class EDecimal : IComparable, /// A sequence that represents a number. /// An index starting at 0 showing where the /// desired portion of begins. - /// The length, in code units, of the desired - /// portion of (but not more than The length, in bytes, of the desired portion + /// of (but not more than 's length). /// An arbitrary-precision decimal number with the same value /// as the given sequence of bytes (interpreted as text). diff --git a/Numbers/PeterO/Numbers/EInteger.cs b/Numbers/PeterO/Numbers/EInteger.cs index 57b99f7..86e1fa4 100644 --- a/Numbers/PeterO/Numbers/EInteger.cs +++ b/Numbers/PeterO/Numbers/EInteger.cs @@ -286,7 +286,53 @@ public sealed partial class EInteger : IComparable, return FromBytes(bytes, 0, bytes.Length, littleEndian); } - private static EInteger FromBytes( + /// Initializes an arbitrary-precision integer from a portion + /// of an array of bytes. The portion of the byte array is encoded + /// using the following rules: + /// + /// Positive numbers have the first byte's highest bit cleared, + /// and negative numbers have the bit set. + /// The last byte contains the lowest 8-bits, the next-to-last + /// contains the next lowest 8 bits, and so on. For example, the number + /// 300 can be encoded as 0x01, 0x2C and 200 as 0x00, + /// 0xC8. (Note that the second example contains a set high bit in + /// 0xC8, so an additional 0 is added at the start to ensure + /// it's interpreted as positive.) + /// To encode negative numbers, take the absolute value of the + /// number, subtract by 1, encode the number into bytes, and toggle + /// each bit of each byte. Any further bits that appear beyond the most + /// significant bit of the number will be all ones. For example, the + /// number -450 can be encoded as 0xfe, 0x70 and -52869 as + /// 0xff, 0x31, 0x7B. (Note that the second example contains a + /// cleared high bit in 0x31, 0x7B, so an additional 0xff is + /// added at the start to ensure it's interpreted as + /// negative.) + /// For little-endian, the byte order is reversed from the byte + /// order just discussed. + /// A byte array consisting of the two's-complement + /// form (see + /// "Forms of numbers" ) of + /// the arbitrary-precision integer to create. The byte array is + /// encoded using the rules given in the FromBytes(bytes, offset, + /// length, littleEndian) overload. + /// An index starting at 0 showing where the + /// desired portion of begins. + /// The length, in bytes, of the desired portion + /// of (but not more than 's length). + /// If true, the byte order is + /// little-endian, or least-significant-byte first. If false, the byte + /// order is big-endian, or most-significant-byte first. + /// An arbitrary-precision integer. Returns 0 if the byte + /// array's length is 0. + /// The parameter is null. + /// Either or is less than 0 or + /// greater than 's length, or 's length minus is less + /// than . + public static EInteger FromBytes( byte[] bytes, int offset, int length, @@ -2910,7 +2956,8 @@ public sealed partial class EInteger : IComparable, if (thisValue.Equals(EInteger.One)) { return thisValue; } - if (Math.Max(thisValue.wordCount, bigintSecond.wordCount) > 250) { + if (Math.Max(thisValue.wordCount, bigintSecond.wordCount) > 12) { + // if (Math.Max(thisValue.wordCount, bigintSecond.wordCount) > 250) { return SubquadraticGCD(thisValue, bigintSecond); } else { return BaseGcd(thisValue, bigintSecond); @@ -3120,7 +3167,7 @@ public sealed partial class EInteger : IComparable, private static int LBL(long mantlong) { #if DEBUG if (mantlong < Int64.MinValue + 1) { - throw new ArgumentException("\"mantlong\" (" + mantlong + ") is not" + + throw new InvalidOperationException("\"mantlong\" (" + mantlong + ") is not" + "\u0020greater or equal to " + Int64.MinValue + 1); } #endif @@ -3131,11 +3178,11 @@ public sealed partial class EInteger : IComparable, private static long[] LHalfGCD(long longa, long longb) { #if DEBUG if (longa < 0) { - throw new ArgumentException("\"longa\" (" + longa + ") is not" + + throw new InvalidOperationException("\"longa\" (" + longa + ") is not" + "\u0020greater or equal to 0"); } if (longb < 0) { - throw new ArgumentException("\"longb\" (" + longb + ") is not" + + throw new InvalidOperationException("\"longb\" (" + longb + ") is not" + "\u0020greater or equal to 0"); } #endif @@ -3293,15 +3340,12 @@ public sealed partial class EInteger : IComparable, // Implements Niels Moeller's Half-GCD algorithm from 2008 private static EInteger[] HalfGCD(EInteger eia, EInteger eib) { -#if DEBUG if (eia.Sign < 0) { - throw new ArgumentException("doesn't satisfy !eia.IsNegative"); + throw new InvalidOperationException("doesn't satisfy !eia.IsNegative"); } if (eib.Sign < 0) { - throw new ArgumentException("doesn't satisfy !eib.IsNegative"); + throw new InvalidOperationException("doesn't satisfy !eib.IsNegative"); } -#endif - EInteger oeia = eia; EInteger oeib = eib; if (eia.IsZero || eib.IsZero) { diff --git a/Numbers/PeterO/Numbers/FastIntegerFixed.cs b/Numbers/PeterO/Numbers/FastIntegerFixed.cs index d3f0361..241b080 100644 --- a/Numbers/PeterO/Numbers/FastIntegerFixed.cs +++ b/Numbers/PeterO/Numbers/FastIntegerFixed.cs @@ -89,7 +89,8 @@ private enum IntegerMode : byte { return this.smallValue == fi.smallValue; case IntegerMode.LargeValue: return this.largeValue.Equals(fi.largeValue); - default: return true; + default: + return true; } } @@ -148,8 +149,7 @@ private enum IntegerMode : byte { } public FastIntegerFixed Increment() { - if (this.integerMode == IntegerMode.SmallValue && this.smallValue != -Int32.MaxValue) { + if (this.integerMode == IntegerMode.SmallValue && this.smallValue != Int32.MaxValue) { return FromInt32(this.smallValue + 1); } else { return Add(this, FastIntegerFixed.One); diff --git a/Numbers/PeterO/Numbers/RadixMath.cs b/Numbers/PeterO/Numbers/RadixMath.cs index 73b13cf..ab305d0 100644 --- a/Numbers/PeterO/Numbers/RadixMath.cs +++ b/Numbers/PeterO/Numbers/RadixMath.cs @@ -126,7 +126,7 @@ internal class RadixMath : IRadixMath { result = new FastInteger(value); } else { return this.helper.GetDigitLength( - EInteger.One.ShiftLeft(prec.ToEInteger()).Subtract(1)); + EInteger.One.ShiftLeft(prec.ToEInteger()).Subtract(1)); } } return result; @@ -862,7 +862,7 @@ internal class RadixMath : IRadixMath { } private T SignalUnderflow(EContext ec, bool negative, bool - zeroSignificand) { + zeroSignificand) { EInteger eTiny = ec.EMin.Subtract(ec.Precision.Subtract(1)); eTiny = eTiny.Subtract(2); // subtract 2 from proper eTiny to // trigger underflow (2, rather than 1, because of HalfUp mode) @@ -908,9 +908,9 @@ internal class RadixMath : IRadixMath { private EInteger WorkingDigits(EInteger workingBits) { int radix = this.thisRadix; if (radix <= 2) { - { return workingBits; + { return workingBits; + } } -} int ibits = NumberUtility.BitLength(radix) - 1; return workingBits.Divide(ibits).Add(1); } @@ -959,7 +959,7 @@ internal class RadixMath : IRadixMath { int sign = this.helper.GetSign(thisValue); T one = this.helper.ValueOf(1); EInteger guardDigits = this.thisRadix == 2 ? - workingPrecision.Add(10) : (EInteger)10; + workingPrecision.Add(10) : (EInteger)10; EContext ctxdiv = SetPrecisionIfLimited( ctx, workingPrecision + guardDigits) @@ -968,52 +968,52 @@ internal class RadixMath : IRadixMath { thisValue = this.RoundToPrecision(one, ctxCopy); } else if (sign > 0 && this.CompareTo(thisValue, one) <= 0) { T closeToZero = this.Divide( - this.helper.ValueOf(1), - this.helper.ValueOf(0x800), - null); + this.helper.ValueOf(1), + this.helper.ValueOf(0x800), + null); if (this.IsFinite(closeToZero) && - this.CompareTo(thisValue, closeToZero) <= 0) { + this.CompareTo(thisValue, closeToZero) <= 0) { // Call ExpInternal for magnitudes close to 0, to avoid // issues when thisValue's magnitude is extremely // close to 0 thisValue = this.ExpInternalVeryCloseToZero( - thisValue, - ctxdiv.Precision, - ctxCopy); + thisValue, + ctxdiv.Precision, + ctxCopy); if (ctx.HasFlags) { - ctx.Flags |= EContext.FlagInexact | - EContext.FlagRounded | ctxCopy.Flags; + ctx.Flags |= EContext.FlagInexact | + EContext.FlagRounded | ctxCopy.Flags; } return thisValue; } thisValue = this.ExpInternal( - thisValue, - ctxdiv.Precision, - ctxCopy); + thisValue, + ctxdiv.Precision, + ctxCopy); if (ctx.HasFlags) { ctx.Flags |= EContext.FlagInexact | EContext.FlagRounded; } } else if (sign < 0) { T closeToZero = this.Divide( - this.helper.ValueOf(-1), - this.helper.ValueOf(0x800), - null); + this.helper.ValueOf(-1), + this.helper.ValueOf(0x800), + null); // DebugUtility.Log("ctz="+closeToZero+", wp="+ // workingPrecision+ // " ctxp="+ctx.Precision); if (this.IsFinite(closeToZero) && - this.CompareTo(thisValue, closeToZero) >= 0) { + this.CompareTo(thisValue, closeToZero) >= 0) { // Call ExpInternal for magnitudes close to 0, to avoid // issues when thisValue's magnitude is extremely // close to 0 // DebugUtility.Log("very ctx: thisValue="+thisValue); thisValue = this.ExpInternalVeryCloseToZero( - thisValue, - ctxdiv.Precision, - ctxCopy); + thisValue, + ctxdiv.Precision, + ctxCopy); if (ctx.HasFlags) { - ctx.Flags |= EContext.FlagInexact | - EContext.FlagRounded | ctxCopy.Flags; + ctx.Flags |= EContext.FlagInexact | + EContext.FlagRounded | ctxCopy.Flags; } return thisValue; } @@ -1039,7 +1039,7 @@ internal class RadixMath : IRadixMath { thisValue = val; } thisValue = this.Divide(one, thisValue, ctxCopy); - // DebugUtility.Log("end= " + thisValue); + // DebugUtility.Log("end= " + thisValue); if (ctx.HasFlags) { ctx.Flags |= EContext.FlagInexact | EContext.FlagRounded; @@ -1048,8 +1048,8 @@ internal class RadixMath : IRadixMath { T intpart = default(T); var haveIntPart = false; if (ctx.HasExponentRange && this.thisRadix >= 2 && - this.thisRadix <= 12 && - this.CompareTo(thisValue, this.helper.ValueOf(10)) > 0) { + this.thisRadix <= 12 && + this.CompareTo(thisValue, this.helper.ValueOf(10)) > 0) { // Calculated with ceil(ln(radix))+1 (radixes 0 and 1 are // not used and have entries of 1) int[] upperDivisors = { @@ -1062,13 +1062,13 @@ internal class RadixMath : IRadixMath { .Divide(100).Add(2); maxexp = EInteger.Max(EInteger.FromInt32(10), maxexp); T mxe = this.helper.CreateNewWithFlags( - maxexp, - EInteger.Zero, - 0); + maxexp, + EInteger.Zero, + 0); if (this.CompareTo(thisValue, mxe) > 0) { - // Greater than overflow bound, so this is an overflow - // DebugUtility.Log("thisValue > mxe: " + thisValue + " " + mxe); - return this.SignalOverflow(ctx, false); + // Greater than overflow bound, so this is an overflow + // DebugUtility.Log("thisValue > mxe: " + thisValue + " " + mxe); + return this.SignalOverflow(ctx, false); } } if (ctx.HasExponentRange && @@ -1128,7 +1128,7 @@ internal class RadixMath : IRadixMath { // DebugUtility.Log("fracpart1=" + fracpart); EInteger workingPrec = ctxdiv.Precision; workingPrec = workingPrec.Add( - this.WorkingDigits(EInteger.FromInt32(20))); + this.WorkingDigits(EInteger.FromInt32(40))); // DebugUtility.Log("intpart=" + intpart + " wp=" + workingPrec); thisValue = this.ExpInternal(fracpart, workingPrec, ctxdiv); // DebugUtility.Log("thisValue=" + thisValue); @@ -1157,6 +1157,127 @@ internal class RadixMath : IRadixMath { return this.helper; } +public static EFloat FastLn(EFloat x, EContext ctx) { + /* +#if DEBUG + if ((ef) == null) { + throw new ArgumentNullException(nameof(ef)); + } + if ((ctx) == null) { + throw new ArgumentNullException(nameof(ctx)); + } +#endif + + */ +// Fast log for contexts of precision 53 bits or less +if (x.CompareTo(EFloat.Create(32, -6)) >= 0 && + x.CompareTo(EFloat.Create(36, -6)) < 0) { + return EFloat.Create(-7918475170148451L, -47) + .MultiplyAndAdd(x, EFloat.Create(5842854079153127L, -44), ctx) + .MultiplyAndAdd(x, EFloat.Create(-7855987447712801L, -43), ctx) + .MultiplyAndAdd(x, EFloat.Create(3178826684731201L, -41), ctx) + .MultiplyAndAdd(x, EFloat.Create(-3446209805793071L, -41), ctx) + .MultiplyAndAdd(x, EFloat.Create(5269250416501899L, -42), ctx) + .MultiplyAndAdd(x, EFloat.Create(-1456756048094669L, -41), ctx) + .MultiplyAndAdd(x, EFloat.Create(589048828844673L, -41), ctx) + .MultiplyAndAdd(x, EFloat.Create(-5626160540257247L, -46), ctx) + .MultiplyAndAdd(x, EFloat.Create(5306429958415307L, -48), ctx) + .MultiplyAndAdd(x, EFloat.Create(-8023390364436687L, -51), ctx); +} +if (x.CompareTo(EFloat.Create(36, -6)) >= 0 && + x.CompareTo(EFloat.Create(40, -6)) < 0) { + return EFloat.Create(-649418159759275L, -45) + .MultiplyAndAdd(x, EFloat.Create(8569695812135613L, -46), ctx) + .MultiplyAndAdd(x, EFloat.Create(-3219836323271541L, -43), ctx) + .MultiplyAndAdd(x, EFloat.Create(1456356315564023L, -41), ctx) + .MultiplyAndAdd(x, EFloat.Create(-7059686721514865L, -43), ctx) + .MultiplyAndAdd(x, EFloat.Create(6033379619755303L, -43), ctx) + .MultiplyAndAdd(x, EFloat.Create(-7458850461699891L, -44), ctx) + .MultiplyAndAdd(x, EFloat.Create(6743646686636803L, -45), ctx) + .MultiplyAndAdd(x, EFloat.Create(-281293242157611L, -42), ctx) + .MultiplyAndAdd(x, EFloat.Create(4746007495118267L, -48), ctx) + .MultiplyAndAdd(x, EFloat.Create(-7772015102064253L, -51), ctx); +} +if (x.CompareTo(EFloat.Create(40, -6)) >= 0 && + x.CompareTo(EFloat.Create(44, -6)) < 0) { + return EFloat.Create(5559026033201687L, -50) + .MultiplyAndAdd(x, EFloat.Create(-4617856151292203L, -47), ctx) + .MultiplyAndAdd(x, EFloat.Create(54117074379353L, -39), ctx) + .MultiplyAndAdd(x, EFloat.Create(-6186785536082459L, -45), ctx) + .MultiplyAndAdd(x, EFloat.Create(7306510509645715L, -45), ctx) + .MultiplyAndAdd(x, EFloat.Create(-2995764726321697L, -44), ctx) + .MultiplyAndAdd(x, EFloat.Create(6986795845479189L, -46), ctx) + .MultiplyAndAdd(x, EFloat.Create(-5891564005530805L, -47), ctx) + .MultiplyAndAdd(x, EFloat.Create(15091899246223L, -40), ctx) + .MultiplyAndAdd(x, EFloat.Create(-7320823715054069L, -51), ctx); +} +if (x.CompareTo(EFloat.Create(44, -6)) >= 0 && + x.CompareTo(EFloat.Create(48, -6)) < 0) { + return EFloat.Create(612197579983455L, -48) + .MultiplyAndAdd(x, EFloat.Create(-1114006258063177L, -46), ctx) + .MultiplyAndAdd(x, EFloat.Create(457577809503393L, -43), ctx) + .MultiplyAndAdd(x, EFloat.Create(-1790557502154387L, -44), ctx) + .MultiplyAndAdd(x, EFloat.Create(4632494137994963L, -45), ctx) + .MultiplyAndAdd(x, EFloat.Create(-4161053891636247L, -45), ctx) + .MultiplyAndAdd(x, EFloat.Create(2657563185521199L, -45), ctx) + .MultiplyAndAdd(x, EFloat.Create(-4909589327505907L, -47), ctx) + .MultiplyAndAdd(x, EFloat.Create(7053693369648581L, -49), ctx) + .MultiplyAndAdd(x, EFloat.Create(-3557744849045649L, -50), ctx); +} +if (x.CompareTo(EFloat.Create(48, -6)) >= 0 && + x.CompareTo(EFloat.Create(52, -6)) < 0) { + return EFloat.Create(577499201531193L, -49) + .MultiplyAndAdd(x, EFloat.Create(-1142306702241897L, -47), ctx) + .MultiplyAndAdd(x, EFloat.Create(8160604872283537L, -48), ctx) + .MultiplyAndAdd(x, EFloat.Create(-4339153427527017L, -46), ctx) + .MultiplyAndAdd(x, EFloat.Create(6101799781923291L, -46), ctx) + .MultiplyAndAdd(x, EFloat.Create(-5958127120148891L, -46), ctx) + .MultiplyAndAdd(x, EFloat.Create(8273521206806363L, -47), ctx) + .MultiplyAndAdd(x, EFloat.Create(-4154027270256105L, -47), ctx) + .MultiplyAndAdd(x, EFloat.Create(3244106922381301L, -48), ctx) + .MultiplyAndAdd(x, EFloat.Create(-13529886537447L, -42), ctx); +} +if (x.CompareTo(EFloat.Create(52, -6)) >= 0 && + x.CompareTo(EFloat.Create(56, -6)) < 0) { + return EFloat.Create(1154075304800921L, -51) + .MultiplyAndAdd(x, EFloat.Create(-2465640916317121L, -49), ctx) + .MultiplyAndAdd(x, EFloat.Create(74318910129327L, -42), ctx) + .MultiplyAndAdd(x, EFloat.Create(-85366471369779L, -41), ctx) + .MultiplyAndAdd(x, EFloat.Create(259329022146413L, -42), ctx) + .MultiplyAndAdd(x, EFloat.Create(-4376322035869763L, -46), ctx) + .MultiplyAndAdd(x, EFloat.Create(3282099616186431L, -46), ctx) + .MultiplyAndAdd(x, EFloat.Create(-3560066267427385L, -47), ctx) + .MultiplyAndAdd(x, EFloat.Create(1501608713011209L, -47), ctx) + .MultiplyAndAdd(x, EFloat.Create(-26381046771207L, -43), ctx); +} +if (x.CompareTo(EFloat.Create(56, -6)) >= 0 && + x.CompareTo(EFloat.Create(60, -6)) < 0) { + return EFloat.Create(37824989738239L, -47) + .MultiplyAndAdd(x, EFloat.Create(-43408559199581L, -44), ctx) + .MultiplyAndAdd(x, EFloat.Create(2878790570900291L, -48), ctx) + .MultiplyAndAdd(x, EFloat.Create(-7105058961533699L, -48), ctx) + .MultiplyAndAdd(x, EFloat.Create(5797162642745407L, -47), ctx) + .MultiplyAndAdd(x, EFloat.Create(-6569041813188869L, -47), ctx) + .MultiplyAndAdd(x, EFloat.Create(661617942907567L, -44), ctx) + .MultiplyAndAdd(x, EFloat.Create(-6168232135736261L, -48), ctx) + .MultiplyAndAdd(x, EFloat.Create(43675806283161L, -42), ctx) + .MultiplyAndAdd(x, EFloat.Create(-6591942829339363L, -51), ctx); +} +if (x.CompareTo(EFloat.Create(60, -6)) >= 0 && + x.CompareTo(EFloat.Create(63, -6)) < 0) { + return EFloat.Create(-6156921697102261L, -55) + .MultiplyAndAdd(x, EFloat.Create(211488681190339L, -47), ctx) + .MultiplyAndAdd(x, EFloat.Create(-6644421976470021L, -50), ctx) + .MultiplyAndAdd(x, EFloat.Create(7668093965389463L, -49), ctx) + .MultiplyAndAdd(x, EFloat.Create(-5761162710156971L, -48), ctx) + .MultiplyAndAdd(x, EFloat.Create(369347589996043L, -44), ctx) + .MultiplyAndAdd(x, EFloat.Create(-8524061902531777L, -49), ctx) + .MultiplyAndAdd(x, EFloat.Create(4683735041389899L, -49), ctx) + .MultiplyAndAdd(x, EFloat.Create(-6208425595264589L, -51), ctx); +} +return null; +} + public T Ln(T thisValue, EContext ctx) { if (ctx == null) { return this.SignalInvalidWithMessage(ctx, "ctx is null"); @@ -1202,6 +1323,22 @@ internal class RadixMath : IRadixMath { ctxCopy); } else if (cmpOne < 0) { // Less than 1 + T half = this.Divide(one, this.helper.ValueOf(2), ctxCopy); + if (this.CompareTo(thisValue, half) >= 0 && + this.helper.GetRadix() == 2 && ctx.Precision.CompareTo(53) <= 0) { + if (thisValue is EFloat) { + var ef = thisValue as EFloat; + ef = FastLn(ef, ctxCopy); + if (ef != null) { + thisValue = (T)ef; + if (ctx.HasFlags) { + ctx.Flags |= EContext.FlagInexact; + ctx.Flags |= EContext.FlagRounded; + } + return thisValue; + } + } + } T quarter = this.Divide(one, this.helper.ValueOf(4), ctxCopy); FastInteger error; error = (this.CompareTo(thisValue, quarter) < 0) ? @@ -1274,16 +1411,73 @@ internal class RadixMath : IRadixMath { } } else { // Greater than 1 + // T hundred = this.helper.ValueOf(100); T two = this.helper.ValueOf(2); - if (this.CompareTo(thisValue, two) >= 0) { + // DebugUtility.Log("thisValue=" + thisValue + + // " hundredcmp=" + this.CompareTo(thisValue, hundred) + + // " twocmp=" + this.CompareTo(thisValue, two)); + if (this.CompareTo(thisValue, two) > 0 && + this.helper.GetRadix() == 2) { + T half = this.Divide(this.helper.ValueOf(1), + this.helper.ValueOf(2), + EContext.Unlimited); + FastIntegerFixed fmant = this.helper.GetMantissaFastInt(thisValue); + EInteger fexp = + this.helper.GetExponentFastInt(thisValue).ToEInteger(); + EInteger fbits = + fmant.ToEInteger().GetUnsignedBitLengthAsEInteger(); + EInteger adjval = EInteger.One; + adjval = fbits.Negate(); // fexp.Subtract(fbits.Add(fexp)); + EInteger adjbits = EInteger.Zero; + T reduced = default(T); + if (fexp.Sign > 0) { + reduced = this.helper.CreateNewWithFlags(fmant.ToEInteger(), + adjval, + 0); + adjbits = fexp.Add(fbits); + } else { + reduced = this.helper.CreateNewWithFlags(fmant.ToEInteger(), + adjval, + 0); + adjbits = fexp.Add(fbits); + } + T addval = adjbits.Sign < 0 ? this.helper.CreateNewWithFlags( + adjbits.Abs(), + EInteger.Zero, + BigNumberFlags.FlagNegative) : this.helper.CreateNewWithFlags( + adjbits.Abs(), + EInteger.Zero, + 0); + EInteger cprec = ctx.Precision.Add(10); + ctxdiv = SetPrecisionIfLimited(ctx, cprec) + .WithRounding(intermedRounding).WithBlankFlags(); + #if DEBUG + if (this.CompareTo(reduced, one) >= 0 || + this.CompareTo(reduced, half) < 0) { + throw new InvalidOperationException( + "thisValue = " + thisValue + "\n" + + "fexp = " + fexp + "\n" + "fbits = " + fbits + "\n" + + "adjval = " + adjval + "\n" + "reduced = " + reduced + "\n"); + } + #endif + // DebugUtility.Log("thisValue = " + thisValue + "\n" + + // "fexp = " + fexp + "\n" + "fbits = " + fbits + "\n" + + // "adjval = " + adjval + "\n" + "reduced = " + reduced + "\n"); + reduced = this.Ln(reduced, ctxdiv); + thisValue = this.MultiplyAndAdd( + this.Ln(two, ctxdiv), + addval, + reduced, + ctxCopy); + } else if (this.CompareTo(thisValue, two) >= 0) { // 2 or greater var roots = new FastInteger(0); FastInteger error; EInteger bigError; FastIntegerFixed fmant = this.helper.GetMantissaFastInt(thisValue); FastIntegerFixed[] bounds = NumberUtility.DigitLengthBoundsFixed( - this.helper, - fmant); + this.helper, + fmant); // DebugUtility.Log("thisValue "+thisValue); // DebugUtility.Log("bounds "+bounds[1]+" ctxprec="+ctx.Precision); error = new FastInteger(10); @@ -1296,7 +1490,7 @@ internal class RadixMath : IRadixMath { } bigError = error.ToEInteger(); EInteger cprec = EInteger.Max(bounds[1].ToEInteger(), ctx.Precision) - .Add(bigError); + .Add(bigError); ctxdiv = SetPrecisionIfLimited(ctx, cprec) .WithRounding(intermedRounding).WithBlankFlags(); T smallfrac = (ctxdiv.Precision.CompareTo(400) > 0) ? @@ -2081,7 +2275,7 @@ internal class RadixMath : IRadixMath { EInteger signedMant; // Special case for 1 in certain cases if (this.CompareTo(thisValue, this.helper.ValueOf(1)) == 0 && - isPowIntegral) { + isPowIntegral) { EInteger thisExponent = this.helper.GetExponent(thisValue); if (thisExponent.Sign == 0) { return (!this.IsWithinExponentRangeForPow(pow, ctx)) ? @@ -2171,9 +2365,9 @@ internal class RadixMath : IRadixMath { ctx, ctx.Precision + guardDigits); if (ctx.Rounding != ERounding.Ceiling && - ctx.Rounding != ERounding.Floor) { + ctx.Rounding != ERounding.Floor) { ctxdiv = ctxdiv.WithRounding(ctx.Rounding) - .WithBlankFlags(); + .WithBlankFlags(); } else { ctxdiv = ctxdiv.WithRounding(ERounding.Up) .WithBlankFlags(); @@ -3108,20 +3302,19 @@ internal class RadixMath : IRadixMath { // DebugUtility.Log("RescaleByExponentDiff "+fe1+" "+fe2); FastIntegerFixed eidiff = fe1.Subtract(fe2).Abs(); EInteger eiBitCount = -mantissa.ToEInteger().GetUnsignedBitLengthAsEInteger(); + mantissa.ToEInteger().GetUnsignedBitLengthAsEInteger(); EInteger eidiffBigInt = eidiff.ToEInteger(); // NOTE: For radix 10, each digit fits less than 1 byte; the // supported byte length is thus less than the maximum value // of a 32-bit integer (2GB). if (helper.GetRadix() <= 10) { - int radix = helper.GetRadix(); - eiBitCount = -eiBitCount.Add(eidiffBigInt.Multiply(BitsPerDigit[radix]) - .Divide(100)); - // DebugUtility.Log(""+eiBitCount); - if (eiBitCount.CompareTo(Int32.MaxValue) > 0) { - return null; - } + int radix = helper.GetRadix(); + eiBitCount = eiBitCount.Add(eidiffBigInt.Multiply(BitsPerDigit[radix]) + .Divide(100)); + // DebugUtility.Log(""+eiBitCount); + if (eiBitCount.CompareTo(Int32.MaxValue) > 0) { + return null; + } } return helper.MultiplyByRadixPowerFastInt(mantissa, eidiff); } @@ -3142,14 +3335,13 @@ internal class RadixMath : IRadixMath { // supported byte length is thus less than the maximum value // of a 32-bit integer (2GB). if (helper.GetRadix() <= 10) { - int radix = helper.GetRadix(); - eiBitCount = -eiBitCount.Add(eidiffBigInt.Multiply(BitsPerDigit[radix]) - .Divide(100)); - // DebugUtility.Log(""+eiBitCount); - if (eiBitCount.CompareTo(Int32.MaxValue) > 0) { - return null; - } + int radix = helper.GetRadix(); + eiBitCount = eiBitCount.Add(eidiffBigInt.Multiply(BitsPerDigit[radix]) + .Divide(100)); + // DebugUtility.Log(""+eiBitCount); + if (eiBitCount.CompareTo(Int32.MaxValue) > 0) { + return null; + } } return helper.MultiplyByRadixPower(mantissa, diff); } @@ -3345,11 +3537,11 @@ internal class RadixMath : IRadixMath { } private static FastInteger ToFastInteger(FastIntegerFixed fif) { - if (fif.CanFitInInt32()) { - return new FastInteger(fif.ToInt32()); - } else { - return FastInteger.FromBig(fif.ToEInteger()); - } + if (fif.CanFitInInt32()) { + return new FastInteger(fif.ToInt32()); + } else { + return FastInteger.FromBig(fif.ToEInteger()); + } } private T AddExDiffExp( @@ -3362,15 +3554,13 @@ internal class RadixMath : IRadixMath { EContext ctx, int expcmp, bool roundToOperandPrecision) { - /* -#if DEBUG - if (!(op1Mantissa.Sign >= 0)) { + /* #if DEBUG (!(op1Mantissa.Sign >= 0)) { throw new ArgumentException("doesn't satisfy op1Mantissa.Sign >= 0"); } if (!(op2Mantissa.Sign >= 0)) { throw new ArgumentException("doesn't satisfy op2Mantissa.Sign >= 0"); } -#endif + #endif */ T retval = default(T); // choose the minimum exponent @@ -3385,9 +3575,9 @@ internal class RadixMath : IRadixMath { bool op2IsZero = op2Mantissa.IsValueZero; bool op1IsZero = op1Mantissa.IsValueZero; int thisSign = op1IsZero ? 0 : (((thisFlags & - BigNumberFlags.FlagNegative) != 0) ? -1 : 1); + BigNumberFlags.FlagNegative) != 0) ? -1 : 1); int otherSign = op2IsZero ? 0 : (((otherFlags & - BigNumberFlags.FlagNegative) != 0) ? -1 : 1); + BigNumberFlags.FlagNegative) != 0) ? -1 : 1); bool moreDistantThanPrecision = expdiff.CompareTo(ctx.Precision) > 0; // If exponent difference is greater than the precision if (moreDistantThanPrecision) { @@ -3402,8 +3592,8 @@ internal class RadixMath : IRadixMath { // ___222222222222222|____________________ FastIntegerFixed digitLength1 = NumberUtility.DigitLengthBoundsFixed(this.helper, - op1Mantissa)[1]; -// DebugUtility.Log("dl1="+digitLength1); + op1Mantissa)[1]; + // DebugUtility.Log("dl1="+digitLength1); if (op1Exponent.Add(digitLength1).Add(2) .CompareTo(op2Exponent) < 0) { // first operand's mantissa can't reach the @@ -3411,15 +3601,15 @@ internal class RadixMath : IRadixMath { // raised without affecting the result FastIntegerFixed tmp = op2Exponent.Subtract(4) .Subtract(digitLength1).Subtract(ctx.Precision); -// DebugUtility.Log("tmp="+tmp); + // DebugUtility.Log("tmp="+tmp); FastIntegerFixed newDiff = tmp.Subtract(op2Exponent).Abs(); -// DebugUtility.Log("newdiff="+newDiff + " expdiff="+expdiff); + // DebugUtility.Log("newdiff="+newDiff + " expdiff="+expdiff); if (newDiff.CompareTo(expdiff) < 0) { // First operand can be treated as almost zero bool sameSign = thisSign == otherSign; FastIntegerFixed digitLength2 = NumberUtility.DigitLengthFixed(this.helper, op2Mantissa); -// DebugUtility.Log("dl2="+digitLength2); + // DebugUtility.Log("dl2="+digitLength2); if (digitLength2.CompareTo(ctx.Precision) < 0) { // Second operand's precision too short, extend // it to the full precision @@ -3530,7 +3720,7 @@ internal class RadixMath : IRadixMath { // Second operand can be treated as almost zero bool sameSign = thisSign == otherSign; digitLength2 = NumberUtility.DigitLengthFixed(this.helper, - op1Mantissa); + op1Mantissa); if (digitLength2.CompareTo(ctx.Precision) < 0) { // First operand's precision too short; extend it // to the full precision @@ -3649,7 +3839,7 @@ internal class RadixMath : IRadixMath { op2Exponent, this.helper); // DebugUtility.Log("op1m="+op1Mantissa+ - // " op2m="+op2Mantissa); + // " op2m="+op2Mantissa); if (op2Mantissa == null) { return this.SignalInvalidWithMessage( ctx, @@ -3666,9 +3856,9 @@ internal class RadixMath : IRadixMath { } if (roundToOperandPrecision && ctx != null && ctx.HasMaxPrecision) { FastInteger digitLength1 = this.helper.GetDigitLength( - op1Mantissa.ToEInteger()); + op1Mantissa.ToEInteger()); FastInteger digitLength2 = -this.helper.GetDigitLength(op2Mantissa.ToEInteger()); + this.helper.GetDigitLength(op2Mantissa.ToEInteger()); FastInteger maxDigitLength = (digitLength1.CompareTo(digitLength2) > 0) ? digitLength1 : @@ -3852,7 +4042,7 @@ internal class RadixMath : IRadixMath { } private static string Chop(string str) { - return (str.Length < 100) ? str : (str.Substring(0, 100) + "..."); + return (str.Length < 100) ? str : (str.Substring(0, 100) + "..."); } private T DivideInternal( @@ -3994,13 +4184,13 @@ internal class RadixMath : IRadixMath { var divsCount = (int)mantissaDivisor.GetUnsignedBitLengthAsInt64(); int dividendShift = (divdCount <= divsCount) ? ((divsCount - divdCount) + maxprec + 1) : Math.Max(0, - (maxprec + 1) - (divdCount - divsCount)); + (maxprec + 1) - (divdCount - divsCount)); absdivd = absdivd.ShiftLeft(dividendShift); EInteger[] divrem3 = absdivd.DivRem(absdivs); quo = divrem3[0]; rem = divrem3[1]; if (ctx == EContext.Binary64 && quo.CanFitInInt64() && - rem.CanFitInInt64()) { + rem.CanFitInInt64()) { long lquo = quo.ToInt64Checked(); long lrem = rem.ToInt64Checked(); int nexp = -dividendShift; @@ -4027,13 +4217,13 @@ internal class RadixMath : IRadixMath { ++nexp; } return this.helper.CreateNewWithFlags( - EInteger.FromInt64(lquo), - EInteger.FromInt64(nexp), - resultNeg ? BigNumberFlags.FlagNegative : 0); + EInteger.FromInt64(lquo), + EInteger.FromInt64(nexp), + resultNeg ? BigNumberFlags.FlagNegative : 0); } } if (ctx == EContext.Binary32 && quo.CanFitInInt64() && - rem.CanFitInInt64()) { + rem.CanFitInInt64()) { long lquo = quo.ToInt64Checked(); long lrem = rem.ToInt64Checked(); int nexp = -dividendShift; @@ -4060,9 +4250,9 @@ internal class RadixMath : IRadixMath { ++nexp; } return this.helper.CreateNewWithFlags( - EInteger.FromInt64(lquo), - EInteger.FromInt64(nexp), - resultNeg ? BigNumberFlags.FlagNegative : 0); + EInteger.FromInt64(lquo), + EInteger.FromInt64(nexp), + resultNeg ? BigNumberFlags.FlagNegative : 0); } } natexp = new FastInteger(-dividendShift); @@ -4091,29 +4281,29 @@ internal class RadixMath : IRadixMath { EInteger divid = mantissaDividend; FastInteger shift = FastInteger.FromBig(ctx.Precision); FastInteger[] dividBounds = - NumberUtility.DigitLengthBounds(this.helper, mantissaDividend); + NumberUtility.DigitLengthBounds(this.helper, mantissaDividend); FastInteger[] divisBounds = - NumberUtility.DigitLengthBounds(this.helper, mantissaDivisor); + NumberUtility.DigitLengthBounds(this.helper, mantissaDivisor); if (dividBounds[0].Copy().Subtract(divisBounds[1]) - .CompareTo(shift) > 0) { - // Dividend is already bigger than divisor by at least - // shift digits, so no need to shift - shift.SetInt(0); + .CompareTo(shift) > 0) { + // Dividend is already bigger than divisor by at least + // shift digits, so no need to shift + shift.SetInt(0); } else { - FastInteger shiftCalc = divisBounds[0].Copy().Subtract( - dividBounds[1]).AddInt(2).Add(shift); - if (shiftCalc.CompareToInt(0) <= 0) { - // No need to shift - shift.SetInt(0); - } else { - shift = shiftCalc; - divid = this.TryMultiplyByRadixPower(divid, shift); - if (divid == null) { - return this.SignalInvalidWithMessage( - ctx, - "Result requires too much memory"); - } - } + FastInteger shiftCalc = divisBounds[0].Copy().Subtract( + dividBounds[1]).AddInt(2).Add(shift); + if (shiftCalc.CompareToInt(0) <= 0) { + // No need to shift + shift.SetInt(0); + } else { + shift = shiftCalc; + divid = this.TryMultiplyByRadixPower(divid, shift); + if (divid == null) { + return this.SignalInvalidWithMessage( + ctx, + "Result requires too much memory"); + } + } } if (shift.Sign != 0 || quo == null) { // if shift isn't zero, recalculate the quotient @@ -4354,9 +4544,9 @@ internal class RadixMath : IRadixMath { T zero = this.helper.ValueOf(0); int cmpZero = this.CompareTo(thisValue, zero); if (cmpZero == 0) { - // NOTE: Should not happen here, because - // the check for zero should have happened earlier - throw new InvalidOperationException(); + // NOTE: Should not happen here, because + // the check for zero should have happened earlier + throw new InvalidOperationException(); } T one = this.helper.ValueOf(1); int precisionAdd = this.thisRadix == 2 ? 18 : 12; @@ -4401,7 +4591,7 @@ internal class RadixMath : IRadixMath { // Guesses are vacillating ++vacillations; more &= vacillations <= maxvac || - (cmpZero < 0 ? guessCmp >= 0 : guessCmp <= 0); + (cmpZero < 0 ? guessCmp >= 0 : guessCmp <= 0); } lastCompare = guessCmp; } @@ -4425,9 +4615,9 @@ internal class RadixMath : IRadixMath { // EDecimal)?.ToDouble()+", wp=" +workingPrecision); T zero = this.helper.ValueOf(0); if (this.CompareTo(thisValue, zero) == 0) { - // NOTE: Should not happen here, because - // the check for zero should have happened earlier - throw new InvalidOperationException(); + // NOTE: Should not happen here, because + // the check for zero should have happened earlier + throw new InvalidOperationException(); } T one = this.helper.ValueOf(1); int precisionAdd = this.thisRadix == 2 ? 18 : 12; @@ -4466,7 +4656,7 @@ internal class RadixMath : IRadixMath { ctxdiv); T newGuess = this.Add(guess, tmp, ctxdiv); // DebugUtility.Log("newguess " + - // this.helper.GetMantissa(newGuess)); + // this.helper.GetMantissa(newGuess)); // DebugUtility.Log("newguessN " + NextPlus(newGuess,ctxdiv)); { int guessCmp = this.CompareTo(lastGuess, newGuess); @@ -4840,8 +5030,8 @@ internal class RadixMath : IRadixMath { error = error.Copy(); error.AddInt(18); EInteger bigError = error.ToEInteger(); - /*DUL("thisValue=" + thisValue + - " powInt=" + powIntBig);*/ + /*DUL("thisValue=" + thisValue + + " powInt=" + powIntBig);*/ EContext ctxdiv = ctx == null ? ctx : SetPrecisionIfLimited( ctx, ctx.Precision + (EInteger)bigError) @@ -5601,7 +5791,7 @@ internal class RadixMath : IRadixMath { // NOTE: At this point, the number won't be infinity or NaN if (!unlimitedPrec && (shift == null || shift.IsValueZero)) { FastIntegerFixed mantabs = this.helper.GetMantissaFastInt( - thisValue); + thisValue); if (adjustNegativeZero && (thisFlags & BigNumberFlags.FlagNegative) != 0 && mantabs.IsValueZero && (ctx.Rounding != ERounding.Floor)) { // Change negative zero to positive zero @@ -5714,57 +5904,59 @@ internal class RadixMath : IRadixMath { FastInteger bitLength = fastPrecision; if (binaryPrec) { fastPrecision = -this.DigitLengthUpperBoundForBitPrecision(fastPrecision); + this.DigitLengthUpperBoundForBitPrecision(fastPrecision); } nonHalfRounding = rounding != ERounding.HalfEven && rounding != ERounding.HalfUp && rounding != ERounding.HalfDown; if (ctx != null && ctx.HasMaxPrecision && - ctx.HasExponentRange) { - long estMantDigits = bigmantissa.CanFitInInt32() ? - 10 : bigmantissa.ToEInteger().GetUnsignedBitLengthAsInt64(); - if (estMantDigits > 128) { - // Get bounds on stored precision - FastIntegerFixed[] bounds = NumberUtility.DigitLengthBoundsFixed( - this.helper, - bigmantissa); - FastIntegerFixed lowExpBound = expfixed; - if (ctx.AdjustExponent) { - lowExpBound = lowExpBound.Add(bounds[0]).Subtract(2); - } - FastIntegerFixed highExpBound = expfixed; - highExpBound = highExpBound.Add(bounds[1]); - FastIntegerFixed fpf = FastIntegerFixed.FromFastInteger(fastPrecision); - /* - string ch1=""+lowExpBound;ch1=ch1.Substring(0,Math.Min(12,ch1.Length)); - string ch2=""+highExpBound;ch2=ch2.Substring(0,Math.Min(12,ch2.Length)); - DebugUtility.Log("exp="+expfixed); - DebugUtility.Log("bounds="+ch1+"/"+ch2+"/"+fastEMax+ - " fpf="+fastPrecision + " highexp=" +highExpBound.Add(fpf).Add(4)); - */ if (lowExpBound.CompareTo(fastEMax) > 0) { - // Overflow. - return this.SignalOverflow(ctx, neg); - } - FastIntegerFixed underflowBound = highExpBound.Add(fpf).Add(4); - // FastIntegerFixed underflowBound2 = highExpBound.Add(bounds[1]).Add(4); - // if (underflowBound2.CompareTo(underflowBound) > 0) { - // underflowBound = underflowBound2; - // } - // DebugUtility.Log("underflowBound="+underflowBound); - if (underflowBound.CompareTo(fastEMin) < 0) { - // Underflow. - // NOTE: Due to estMantDigits check - // above, we know significand is neither zero nor 1( - // SignalUnderflow will pass significands of 0 or 1 to - // RoundToPrecision). - return this.SignalUnderflow(ctx, neg, false); - } - /* - DebugUtility.Log("mantbits=" + - bigmantissa.ToEInteger().GetUnsignedBitLengthAsInt64() + - " shift=" + shift + " fastprec=" + fastPrecision + - " expbits=" + exp.ToEInteger().GetUnsignedBitLengthAsInt64() + - " expsign=" + exp.ToEInteger().CompareTo(0)); */ - } + ctx.HasExponentRange) { + long estMantDigits = bigmantissa.CanFitInInt32() ? + 10 : bigmantissa.ToEInteger().GetUnsignedBitLengthAsInt64(); + if (estMantDigits > 128) { + // Get bounds on stored precision + FastIntegerFixed[] bounds = NumberUtility.DigitLengthBoundsFixed( + this.helper, + bigmantissa); + FastIntegerFixed lowExpBound = expfixed; + if (ctx.AdjustExponent) { + lowExpBound = lowExpBound.Add(bounds[0]).Subtract(2); + } + FastIntegerFixed highExpBound = expfixed; + highExpBound = highExpBound.Add(bounds[1]); + FastIntegerFixed fpf = +FastIntegerFixed.FromFastInteger(fastPrecision); + /* string +ch1=""+lowExpBound;ch1=ch1.Substring(0,Math.Min(12,ch1.Length)); + string +ch2=""+highExpBound;ch2=ch2.Substring(0,Math.Min(12,ch2.Length)); + DebugUtility.Log("exp="+expfixed); + DebugUtility.Log("bounds="+ch1+"/"+ch2+"/"+fastEMax+ + " fpf="+fastPrecision + " highexp=" +highExpBound.Add(fpf).Add(4)); + */ if (lowExpBound.CompareTo(fastEMax) > 0) { + // Overflow. + return this.SignalOverflow(ctx, neg); + } + FastIntegerFixed underflowBound = highExpBound.Add(fpf).Add(4); + // FastIntegerFixed underflowBound2 = highExpBound.Add(bounds[1]).Add(4); + // if (underflowBound2.CompareTo(underflowBound) > 0) { + // underflowBound = underflowBound2; + // } + // DebugUtility.Log("underflowBound="+underflowBound); + if (underflowBound.CompareTo(fastEMin) < 0) { + // Underflow. + // NOTE: Due to estMantDigits check + // above, we know significand is neither zero nor 1( + // SignalUnderflow will pass significands of 0 or 1 to + // RoundToPrecision). + return this.SignalUnderflow(ctx, neg, false); + } + /* + DebugUtility.Log("mantbits=" + + bigmantissa.ToEInteger().GetUnsignedBitLengthAsInt64() + + " shift=" + shift + " fastprec=" + fastPrecision + + " expbits=" + exp.ToEInteger().GetUnsignedBitLengthAsInt64() + + " expsign=" + exp.ToEInteger().CompareTo(0)); */ + } } if (!unlimitedPrec) { accum.ShiftToDigits(fastPrecision, shift, nonHalfRounding); @@ -6045,8 +6237,8 @@ internal class RadixMath : IRadixMath { private static int CompareToHalf(EInteger bigLeft, EInteger toCompareWith) { #if DEBUG if (!(bigLeft.Sign > 0 && toCompareWith.Sign > 0)) { - throw new ArgumentException("doesn't satisfy bigLeft.Sign > 0 && " + - "toCompareWith.Sign > 0"); + throw new ArgumentException("doesn't satisfy bigLeft.Sign > 0 && " + + "toCompareWith.Sign > 0"); } #endif long a = bigLeft.GetUnsignedBitLengthAsInt64(); @@ -6338,7 +6530,7 @@ internal class RadixMath : IRadixMath { return bi; } return this.helper.MultiplyByRadixPower(bi, - new FastInteger(radixPowerInt)); + new FastInteger(radixPowerInt)); } private EInteger TryMultiplyByRadixPower( diff --git a/Numbers/docs.xml b/Numbers/docs.xml index b0bcccf..c949303 100644 --- a/Numbers/docs.xml +++ b/Numbers/docs.xml @@ -2242,8 +2242,8 @@ A sequence that represents a number. An index starting at 0 showing where the desired portion of begins. - The length, in code units, of the desired - portion of (but not more than 's length). + The length, in bytes, of the desired portion + of (but not more than 's length). An arbitrary-precision decimal number with the same value as the given sequence of bytes (interpreted as text). The parameter is not a correctly formatted number @@ -10631,7 +10631,21 @@ form (see "Forms of numbers" ) of the arbitrary-precision integer to create. The byte array is - encoded using the following rules: + encoded using the rules given in the FromBytes(bytes, offset, + length, littleEndian) overload. + If true, the byte order is + little-endian, or least-significant-byte first. If false, the byte + order is big-endian, or most-significant-byte first. + An arbitrary-precision integer. Returns 0 if the byte + array's length is 0. + The parameter is null. + + + + + Initializes an arbitrary-precision integer from a portion + of an array of bytes. The portion of the byte array is encoded + using the following rules: Positive numbers have the first byte's highest bit cleared, and negative numbers have the bit set. @@ -10651,13 +10665,26 @@ added at the start to ensure it's interpreted as negative.) For little-endian, the byte order is reversed from the byte - order just discussed.. + order just discussed. + A byte array consisting of the two's-complement + form (see + "Forms of numbers" ) of + the arbitrary-precision integer to create. The byte array is + encoded using the rules given in the FromBytes(bytes, offset, + length, littleEndian) overload. + An index starting at 0 showing where the + desired portion of begins. + The length, in bytes, of the desired portion + of (but not more than 's length). If true, the byte order is little-endian, or least-significant-byte first. If false, the byte order is big-endian, or most-significant-byte first. An arbitrary-precision integer. Returns 0 if the byte array's length is 0. The parameter is null. + Either or is less than 0 or + greater than 's length, or 's length minus is less + than . diff --git a/Numbers20/Numbers20.csproj b/Numbers20/Numbers20.csproj index c54894f..02c465c 100644 --- a/Numbers20/Numbers20.csproj +++ b/Numbers20/Numbers20.csproj @@ -1 +1 @@ -winDebugAnyCPULibraryNumbersv2.0true..\Numbers\PeterO.snk{04A7B845-E447-4A46-ABB9-D195BDEDC735}rules.rulesettruefullfalsebin\DebugDEBUG;NET40prompt4bin\Debug\Numbers.xmlrules.rulesettruebin\ReleaseNET40prompt4bin\Release\Numbers.xmlrules.ruleset1.1.1183.0.0docs.xmlstylecop.jsonPeterO/Numbers/EDecimal.csPeterO/Numbers/EFloatCharArrayString.csPeterO/Numbers/IRadixMath.csPeterO/Numbers/RadixMath.csPeterO/Numbers/ERounding.csPeterO/Numbers/FastIntegerFixed.csPeterO/Numbers/EIntegerCharArrayString.csPeterO/Numbers/EContext.csPeterO/Numbers/BigNumberFlags.csPeterO/Numbers/SimpleRadixMath.csPeterO/Numbers/Extras.csPeterO/Numbers/NumberUtility.csPeterO/Numbers/ERationalCharArrayString.csPeterO/Numbers/ExtendedOrSimpleRadixMath.csPeterO/Numbers/EDecimalTextString.csPeterO/Numbers/EInteger.csPeterO/Numbers/EFloatByteArrayString.csPeterO/Numbers/ERationalExtra.csPeterO/Numbers/ERationalTextString.csPeterO/Numbers/EFloatExtra.csPeterO/Numbers/FastInteger.csPeterO/Numbers/EDecimalByteArrayString.csPeterO/Numbers/EIntegerTextString.csPeterO/Numbers/IShiftAccumulator.csPeterO/Numbers/EFloats.csPeterO/Numbers/ERational.csPeterO/Numbers/TrappableRadixMath.csPeterO/Numbers/BitShiftAccumulator.csPeterO/Numbers/EIntegerByteArrayString.csPeterO/Numbers/ERationalByteArrayString.csPeterO/Numbers/EIntegerExtra.csPeterO/Numbers/EDecimals.csPeterO/Numbers/EDecimalExtra.csPeterO/Numbers/EDecimalCharArrayString.csPeterO/Numbers/EFloatTextString.csPeterO/Numbers/DigitShiftAccumulator.csPeterO/Numbers/EFloat.csPeterO/Numbers/IRadixMathHelper.csPeterO/Numbers/ETrapException.csPeterO/DebugUtility.cs +winDebugAnyCPULibraryNumbersv2.0true..\Numbers\PeterO.snk{04A7B845-E447-4A46-ABB9-D195BDEDC735}rules.rulesettruetruefullfalsebin\DebugDEBUG;NET40prompt4bin\Debug\Numbers.xmlrules.rulesettruebin\ReleaseNET40prompt4bin\Release\Numbers.xmlrules.ruleset1.1.1183.0.0docs.xmlstylecop.jsonPeterO/Numbers/EDecimal.csPeterO/Numbers/EFloatCharArrayString.csPeterO/Numbers/IRadixMath.csPeterO/Numbers/RadixMath.csPeterO/Numbers/ERounding.csPeterO/Numbers/FastIntegerFixed.csPeterO/Numbers/EIntegerCharArrayString.csPeterO/Numbers/EContext.csPeterO/Numbers/BigNumberFlags.csPeterO/Numbers/SimpleRadixMath.csPeterO/Numbers/Extras.csPeterO/Numbers/NumberUtility.csPeterO/Numbers/ERationalCharArrayString.csPeterO/Numbers/ExtendedOrSimpleRadixMath.csPeterO/Numbers/EDecimalTextString.csPeterO/Numbers/EInteger.csPeterO/Numbers/EFloatByteArrayString.csPeterO/Numbers/ERationalExtra.csPeterO/Numbers/ERationalTextString.csPeterO/Numbers/EFloatExtra.csPeterO/Numbers/FastInteger.csPeterO/Numbers/EDecimalByteArrayString.csPeterO/Numbers/EIntegerTextString.csPeterO/Numbers/IShiftAccumulator.csPeterO/Numbers/EFloats.csPeterO/Numbers/ERational.csPeterO/Numbers/TrappableRadixMath.csPeterO/Numbers/BitShiftAccumulator.csPeterO/Numbers/EIntegerByteArrayString.csPeterO/Numbers/ERationalByteArrayString.csPeterO/Numbers/EIntegerExtra.csPeterO/Numbers/EDecimals.csPeterO/Numbers/EDecimalExtra.csPeterO/Numbers/EDecimalCharArrayString.csPeterO/Numbers/EFloatTextString.csPeterO/Numbers/DigitShiftAccumulator.csPeterO/Numbers/EFloat.csPeterO/Numbers/IRadixMathHelper.csPeterO/Numbers/ETrapException.csPeterO/DebugUtility.cs diff --git a/Test/EFloatTest.cs b/Test/EFloatTest.cs index 3b29f35..14a024a 100644 --- a/Test/EFloatTest.cs +++ b/Test/EFloatTest.cs @@ -924,52 +924,113 @@ public class EFloatTest { TestCommon.CompareTestEqual(efb, efa, str); } { - EFloat ef = EFloat.FromString( - "49565911.77858351171016693115234375") - .Log(EContext.Binary64); - EFloat ef2 = EFloat.FromString( - "17.718813892893447103915605111978948116302490234375"); - TestCommon.CompareTestEqual(ef2, ef); + EFloat ef = EFloat.FromString( + "49565911.77858351171016693115234375") + .Log(EContext.Binary64); + EFloat ef2 = EFloat.FromString( + "17.718813892893447103915605111978948116302490234375"); + TestCommon.CompareTestEqual(ef2, ef); } } + [Test] + public void TestLogExpSpecificA() { + EFloat efa = EFloat.Create(5094638944929121L, + -43).ExpM1(EContext.Binary64); + EFloat efb = EFloat.Create(3411748882100003L, 784); + string str = OutputEF(efb) + "\n" + OutputEF(efa); + TestCommon.CompareTestEqual(efb, efa, str); + } + [Test] + public void TestLogExpSpecificB() { + EFloat efa = EFloat.Create(1168389840651401L, 526).Log(EContext.Binary64); + EFloat efb = EFloat.Create(1756095199620111L, -42); + string str = OutputEF(efb) + "\n" + OutputEF(efa); + TestCommon.CompareTestEqual(efb, efa, str); + } + [Test] + public void TestLogExpSpecificC() { + EFloat efa = EFloat.Create(-1184982539430741L, + -52).Exp(EContext.Binary64); + EFloat efb = EFloat.Create(3461693826094423L, -52); + string str = OutputEF(efb) + "\n" + OutputEF(efa); + TestCommon.CompareTestEqual(efb, efa, str); + } + [Test] + public void TestLogExpSpecificD() { + EFloat efa = EFloat.Create(6832986215039611L, + -38).Log1P(EContext.Binary64); + EFloat efb = EFloat.Create(1424402087294909L, -47); + string str = OutputEF(efb) + "\n" + OutputEF(efa); + TestCommon.CompareTestEqual(efb, efa, str); + } + [Test] + public void TestLogExpSpecificE() { + EFloat efa = EFloat.Create(5615046595603761L, + -44).ExpM1(EContext.Binary64); + EFloat efb = EFloat.Create(195906767427969L, 413); + string str = OutputEF(efb) + "\n" + OutputEF(efa); + TestCommon.CompareTestEqual(efb, efa, str); + } + [Test] + public void TestLogExpSpecificF() { + EFloat efa = EFloat.Create(7894203448763243L, 790).Log(EContext.Binary64); + EFloat efb = EFloat.Create(642324992820697L, -40); + String str = OutputEF(efb) + "\n" + OutputEF(efa); + TestCommon.CompareTestEqual(efb, efa, str); + } + [Test] + public void TestLogExpSpecificG() { + EFloat efa = EFloat.Create(4939846268124649L, -48).Log(EContext.Binary64); + EFloat efb = EFloat.Create(6451509911495955L, -51); + string str = OutputEF(efb) + "\n" + OutputEF(efa) + "\nInput: " + + OutputEF(EFloat.Create(4939846268124649L, -48)) ; + TestCommon.CompareTestEqual(efb, efa, str); + } + [Test] public void TestExpM1() { { EFloat efa = EFloat.Create(1007123499737607L, - -522).ExpM1(EContext.Binary64); + -522).ExpM1(EContext.Binary64); EFloat efb = EFloat.Create(1007123499737607L, -522); - TestCommon.CompareTestEqual(efb, efa); + string str = OutputEF(efb) + "\n" + OutputEF(efa); + TestCommon.CompareTestEqual(efb, efa, str); } { EFloat efa = EFloat.Create(6580149561684505L, - -1071).ExpM1(EContext.Binary64); + -1071).ExpM1(EContext.Binary64); EFloat efb = EFloat.Create(6580149561684505L, -1071); - TestCommon.CompareTestEqual(efb, efa); + string str = OutputEF(efb) + "\n" + OutputEF(efa); + TestCommon.CompareTestEqual(efb, efa, str); } { EFloat efa = EFloat.Create(-3676681081736271L, - -81).ExpM1(EContext.Binary64); + -81).ExpM1(EContext.Binary64); EFloat efb = EFloat.Create(-7353362157881635L, -82); - TestCommon.CompareTestEqual(efb, efa); + string str = OutputEF(efb) + "\n" + OutputEF(efa); + TestCommon.CompareTestEqual(efb, efa, str); } { EFloat efa = EFloat.Create(-969434867059159L, - -66).ExpM1(EContext.Binary64); + -66).ExpM1(EContext.Binary64); EFloat efb = EFloat.Create(-7755427989821553L, -69); - TestCommon.CompareTestEqual(efb, efa); + string str = OutputEF(efb) + "\n" + OutputEF(efa); + TestCommon.CompareTestEqual(efb, efa, str); } { EFloat efa = EFloat.Create(3153411279369011L, - -70).ExpM1(EContext.Binary64); + -70).ExpM1(EContext.Binary64); EFloat efb = EFloat.Create(6306830981643433L, -71); - TestCommon.CompareTestEqual(efb, efa); + string str = OutputEF(efb) + "\n" + OutputEF(efa); + TestCommon.CompareTestEqual(efb, efa, str); } { EFloat efa = EFloat.Create(-1481872941857973L, - -86).ExpM1(EContext.Binary64); + -86).ExpM1(EContext.Binary64); EFloat efb = EFloat.Create(-740936470921891L, -85); - TestCommon.CompareTestEqual(efb, efa); + string str = OutputEF(efb) + "\n" + OutputEF(efa); + TestCommon.CompareTestEqual(efb, efa, str); } } @@ -977,42 +1038,42 @@ public class EFloatTest { EFloat expec, EFloat actual, EFloat inp) { - return OutputEF(expec) + "\n" + OutputEF(actual) + "\n" + OutputEF(inp); + return OutputEF(expec) + "\n" + OutputEF(actual) + "\n" + OutputEF(inp); } [Test] public void TestLog1P() { { EFloat efa = EFloat.Create(3326311965476095L, - -26); + -26); EFloat efl = efa.Log1P(EContext.Binary64); EFloat efb = EFloat.Create(4987402727842631L, -48); TestCommon.CompareTestEqual(efb, efl, DebugStringLog1P(efb, efl, efa)); } { EFloat efa = EFloat.Create(-5934733692758989L, - -166); + -166); EFloat efl = efa.Log1P(EContext.Binary64); EFloat efb = EFloat.Create(-5934733692758989L, -166); TestCommon.CompareTestEqual(efb, efl, DebugStringLog1P(efb, efl, efa)); } { EFloat efa = EFloat.Create(7028563965745449L, - -26); + -26); EFloat efl = efa.Log1P(EContext.Binary64); EFloat efb = EFloat.Create(2598989644557185L, -47); TestCommon.CompareTestEqual(efb, efl, DebugStringLog1P(efb, efl, efa)); } { EFloat efa = EFloat.Create(6661843800332999L, - -311); + -311); EFloat efl = efa.Log1P(EContext.Binary64); EFloat efb = EFloat.Create(6661843800332999L, -311); TestCommon.CompareTestEqual(efb, efl, DebugStringLog1P(efb, efl, efa)); } { EFloat efa = EFloat.Create(2966802219632029L, - -588); + -588); EFloat efl = efa.Log1P(EContext.Binary64); EFloat efb = EFloat.Create(2966802219632029L, -588); TestCommon.CompareTestEqual(efb, efl, DebugStringLog1P(efb, efl, efa)); @@ -2050,6 +2111,10 @@ public class EFloatTest { } EInteger emant = efa.Mantissa; int mantBits = emant.GetUnsignedBitLengthAsEInteger().ToInt32Checked(); + if (mantBits > bitCount) { + throw new InvalidOperationException("Too many bits; expected double-" + + "\u0020or single-sized significand"); + } bool fullPrecision = mantBits == bitCount; bool isSubnormal = EFloats.IsSubnormal(efa, dbl ? EContext.Binary64 : EContext.Binary32); @@ -2809,7 +2874,7 @@ public class EFloatTest { TestToFloatRoundingOne(objectTemp, true); objectTemp = EFloat.Create( EInteger.FromRadixString("100110100000000011000010111000111111101", 2), - EInteger.FromInt32(-1073)); + EInteger.FromInt32(-1073)); TestToFloatRoundingOne(objectTemp, true); } } diff --git a/Test/EIntegerTest.cs b/Test/EIntegerTest.cs index 44ce7c2..394a0e7 100644 --- a/Test/EIntegerTest.cs +++ b/Test/EIntegerTest.cs @@ -111,13 +111,13 @@ public class EIntegerTest { // Generates an EInteger of manageable size private static EInteger RandomManageableEInteger(IRandomGenExtended rg) { - EInteger ei; - while (true) { - ei = RandomObjects.RandomEInteger(rg); - if (ei.GetUnsignedBitLengthAsInt64() <= 16 * 3000) { - return ei; - } - } + EInteger ei; + while (true) { + ei = RandomObjects.RandomEInteger(rg); + if (ei.GetUnsignedBitLengthAsInt64() <= 16 * 3000) { + return ei; + } + } } public static void AssertAdd(EInteger bi, EInteger bi2, string s) { @@ -1299,8 +1299,17 @@ public class EIntegerTest { if (bytes == null) { throw new ArgumentNullException(nameof(bytes)); } - var offset = 0; - int length = bytes.Length; + return TestEIntegerFromBytes(bytes, 0, bytes.Length, littleEndian); + } + + public static bool TestEIntegerFromBytes( + byte[] bytes, + int offset, + int length, + bool littleEndian) { + if (bytes == null) { + throw new ArgumentNullException(nameof(bytes)); + } if (length == 0) { return false; } @@ -1323,7 +1332,9 @@ public class EIntegerTest { var negative = false; negative = (!littleEndian) ? ((bytes[offset] & 0x80) != 0) : ((bytes[offset + length - 1] & 0x80) != 0); - EInteger ei = EInteger.FromBytes(bytes, littleEndian); + EInteger ei = (offset == 0 && length == bytes.Length) ? + EInteger.FromBytes(bytes, littleEndian) : + EInteger.FromBytes(bytes, offset, length, littleEndian); Assert.AreEqual(negative, ei.Sign < 0); byte[] ba = ei.ToBytes(littleEndian); TestCommon.AssertByteArraysEqual(bytes, offset, length, ba); @@ -1350,12 +1361,11 @@ public class EIntegerTest { TestEIntegerFromBytes(bytes, rg.UniformInt(2) == 0); int offset1 = rg.GetInt32(bytes.Length + 1); int offset2 = rg.GetInt32(bytes.Length + 1); - /* if (offset1 != offset2) { + if (offset1 != offset2) { int length = Math.Abs(offset1 - offset2); int offset = Math.Min(offset1, offset2); TestEIntegerFromBytes(bytes, offset, length, rg.UniformInt(2) == 0); } - */ } } [Test] @@ -2801,12 +2811,12 @@ public class EIntegerTest { } public static void TestSimpleMultiply(int inta, int intb, int intresult) { - TestCommon.CompareTestEqual( - EInteger.FromInt32(intresult), - EInteger.FromInt32(inta).Multiply(EInteger.FromInt32(intb))); - TestCommon.CompareTestEqual( - EInteger.FromInt32(intresult), - EInteger.FromInt32(inta).Multiply(intb)); + TestCommon.CompareTestEqual( + EInteger.FromInt32(intresult), + EInteger.FromInt32(inta).Multiply(EInteger.FromInt32(intb))); + TestCommon.CompareTestEqual( + EInteger.FromInt32(intresult), + EInteger.FromInt32(inta).Multiply(intb)); } [Test] @@ -3227,15 +3237,10 @@ public class EIntegerTest { [Test] public void TestRootRem() { TestCommon.CompareTestEqual( - EInteger.FromInt32(2), - EInteger.FromInt32(26).RootRem(3)[0]); + EInteger.FromInt32(2), + EInteger.FromInt32(26).RootRem(3)[0]); var r = new RandomGenerator(); for (var i = 0; i < 500; ++i) { - #if DEBUG - // if (i % 50 == 0) { - // Console.WriteLine("i=" + i + " " + DateTime.UtcNow); - // } - #endif EInteger bigintA = RandomManageableEInteger(r); if (bigintA.Sign < 0) { bigintA = -bigintA; @@ -3275,8 +3280,8 @@ public class EIntegerTest { [Test] public void TestRoot() { TestCommon.CompareTestEqual( - EInteger.FromInt32(2), - EInteger.FromInt32(26).Root(3)); + EInteger.FromInt32(2), + EInteger.FromInt32(26).Root(3)); var r = new RandomGenerator(); for (var i = 0; i < 1000; ++i) { #if DEBUG diff --git a/Test20/Test20.csproj b/Test20/Test20.csproj index 9c03ebb..46a2c26 100644 --- a/Test20/Test20.csproj +++ b/Test20/Test20.csproj @@ -1 +1 @@ -DebugAnyCPU{4CF0E5BA-CDE3-4DEA-B3F4-11EE544B3FB2}ExeTest20v2.0rules.rulesetwintruefullfalsebin\DebugDEBUG;NET20prompt4truerules.rulesettruebin\ReleasepromptNET204truerules.ruleset2.0.01.1.1183.0.0EDecimalTest.csEContextTest.csIRandomGenExtended.csXorShift128Plus.csstylecop.jsonRandomObjects.csAppResources.csTestCommon.csETrapExceptionTest.csSevenBitEncoded.csEIntegerTest.csRandomGenerator.csExtraTest.csStringAndBigInt.csDecTestUtil.csResources.restextResources.resourcesDecimalTest.csRunner.csExtensiveTest.csERationalTest.csIRandomGen.csEFloatTest.cs{04A7B845-E447-4A46-ABB9-D195BDEDC735}Test20 +DebugAnyCPU{4CF0E5BA-CDE3-4DEA-B3F4-11EE544B3FB2}ExeTest20v2.0rules.rulesetwintruetruefullfalsebin\DebugDEBUG;NET20prompt4truerules.rulesettruebin\ReleasepromptNET204truerules.ruleset2.0.01.1.1183.0.0EDecimalTest.csEContextTest.csIRandomGenExtended.csXorShift128Plus.csstylecop.jsonRandomObjects.csAppResources.csTestCommon.csETrapExceptionTest.csSevenBitEncoded.csEIntegerTest.csRandomGenerator.csExtraTest.csStringAndBigInt.csDecTestUtil.csResources.restextResources.resourcesDecimalTest.csRunner.csExtensiveTest.csERationalTest.csIRandomGen.csEFloatTest.cs{04A7B845-E447-4A46-ABB9-D195BDEDC735}Test20 diff --git a/docs/PeterO.Numbers.EDecimal.md b/docs/PeterO.Numbers.EDecimal.md index 50532d1..bd1e229 100644 --- a/docs/PeterO.Numbers.EDecimal.md +++ b/docs/PeterO.Numbers.EDecimal.md @@ -1933,7 +1933,7 @@ Creates an arbitrary-precision decimal number from a sequence of bytes (interpre * offset: An index starting at 0 showing where the desired portion of bytes begins. - * length: The length, in code units, of the desired portion of bytes + * length: The length, in bytes, of the desired portion of bytes (but not more than bytes 's length). diff --git a/docs/PeterO.Numbers.EInteger.md b/docs/PeterO.Numbers.EInteger.md index 1da019e..93ade8c 100644 --- a/docs/PeterO.Numbers.EInteger.md +++ b/docs/PeterO.Numbers.EInteger.md @@ -56,6 +56,7 @@ Applications should instead use dedicated security libraries to handle big numbe * [FromBoolean(bool)](#FromBoolean_bool) - Converts a boolean value (true or false) to an arbitrary-precision integer. * [FromByte(byte)](#FromByte_byte) - Converts a byte (from 0 to 255) to an arbitrary-precision integer. * [FromBytes(byte[], bool)](#FromBytes_byte_bool) - Initializes an arbitrary-precision integer from an array of bytes. +* [FromBytes(byte[], int, int, bool)](#FromBytes_byte_int_int_bool) - Initializes an arbitrary-precision integer from a portion of an array of bytes. * [FromInt16(short)](#FromInt16_short) - Converts a 16-bit signed integer to an arbitrary-precision integer. * [FromInt32(int)](#FromInt32_int) - Converts a 32-bit signed integer to an arbitrary-precision integer. * [FromInt64(long)](#FromInt64_long) - Converts a 64-bit signed integer to an arbitrary-precision integer. @@ -830,6 +831,58 @@ An arbitrary-precision integer. Returns 0 if the byte array's length is 0. The parameter bytes is null. + +### FromBytes + + public static PeterO.Numbers.EInteger FromBytes( + byte[] bytes, + int offset, + int length, + bool littleEndian); + +Initializes an arbitrary-precision integer from a portion of an array of bytes. The portion of the byte array is encoded using the following rules: + + * Positive numbers have the first byte's highest bit cleared, and negative numbers have the bit set. + + * The last byte contains the lowest 8-bits, the next-to-last contains the next lowest 8 bits, and so on. For example, the number 300 can be encoded as `0x01, 0x2C` and 200 as `0x00, + 0xC8` . (Note that the second example contains a set high bit in `0xC8` , so an additional 0 is added at the start to ensure it's interpreted as positive.) + + * To encode negative numbers, take the absolute value of the number, subtract by 1, encode the number into bytes, and toggle each bit of each byte. Any further bits that appear beyond the most significant bit of the number will be all ones. For example, the number -450 can be encoded as `0xfe, 0x70` and -52869 as `0xff, 0x31, 0x7B` . (Note that the second example contains a cleared high bit in `0x31, 0x7B` , so an additional 0xff is added at the start to ensure it's interpreted as negative.) + +For little-endian, the byte order is reversed from the byte order just discussed. + +Parameters: + + * bytes: A byte array consisting of the two's-complement form (see ["Forms of numbers"](PeterO.Numbers.EDecimal.md)"Forms of numbers" ) of the arbitrary-precision integer to create. The byte array is encoded using the rules given in the FromBytes(bytes, offset, length, littleEndian) overload. + + * offset: An index starting at 0 showing where the desired portion of bytes + begins. + + * length: The length, in bytes, of the desired portion of bytes + (but not more than bytes + 's length). + + * littleEndian: If true, the byte order is little-endian, or least-significant-byte first. If false, the byte order is big-endian, or most-significant-byte first. + +Return Value: + +An arbitrary-precision integer. Returns 0 if the byte array's length is 0. + +Exceptions: + + * System.ArgumentNullException: +The parameter bytes + is null. + + * System.ArgumentException: +Either offset + or length + is less than 0 or greater than bytes + 's length, or bytes + 's length minus offset + is less than length +. + ### FromInt16