From 718587cf098fd29d43102e15d986a627b10e09ca Mon Sep 17 00:00:00 2001 From: Peter O Date: Sun, 12 Jul 2020 09:24:52 -0400 Subject: [PATCH 01/16] Add overload to EInteger.FromBytes --- Numbers.nuspec | 2 +- Numbers/PeterO/Numbers/EInteger.cs | 145 ++++++++++++++--------------- Numbers/docs.xml | 71 +++++++++----- Numbers20/Numbers20.csproj | 2 +- Numbers40/Numbers40.csproj | 2 +- Test20/Test20.csproj | 3 +- Test40/Test40.csproj | 3 +- docs/PeterO.Numbers.EInteger.md | 41 ++++++-- 8 files changed, 153 insertions(+), 116 deletions(-) diff --git a/Numbers.nuspec b/Numbers.nuspec index 834552d..b4eaaaa 100644 --- a/Numbers.nuspec +++ b/Numbers.nuspec @@ -14,4 +14,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/EInteger.cs b/Numbers/PeterO/Numbers/EInteger.cs index 52a4bf2..84fc0c4 100644 --- a/Numbers/PeterO/Numbers/EInteger.cs +++ b/Numbers/PeterO/Numbers/EInteger.cs @@ -20,7 +20,7 @@ // to return MaxValue on overflow // TODO: In next major version, perhaps change GetLowBit/GetDigitCount // to return MaxValue on overflow -// TODO: Add overload to FromBytes to take a portion of a byte array +// TODO: Perhaps add overload to FromBytes to take a sign and magnitude // TODO: Add faster equivalent to And((1 << n)-1) namespace PeterO.Numbers { /// Represents an arbitrary-precision integer. (The "E" stands @@ -270,27 +270,8 @@ public sealed partial class EInteger : IComparable, /// form (see /// "Forms of numbers" ) of /// the arbitrary-precision integer to create. 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.. + /// 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. @@ -302,13 +283,64 @@ public sealed partial class EInteger : IComparable, if (bytes == null) { throw new ArgumentNullException(nameof(bytes)); } - if (bytes.Length == 0) { + return FromBytes(bytes, 0, bytes.Length, littleEndian); + } + + /// Initializes an arbitrary-precision integer from a portion + /// of an array of bytes. + /// An arbitrary-precision integer. Returns 0 if "length" is + /// 0. + /// The parameter is null. + /// Not documented yet. + /// Not documented yet. + /// 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. + /// 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. + public static EInteger FromBytes( + byte[] bytes, + int offset, + int length, + bool littleEndian) { + if (bytes == null) { + throw new ArgumentNullException(nameof(bytes)); + } + if (offset < 0) { + throw new ArgumentException("offset (" + offset + ") is not greater" + +"\u0020or equal to 0"); + } + if (offset > bytes.Length) { + throw new ArgumentException("offset (" + offset + ") is not less or" + +"\u0020equal to " + bytes.Length); + } + if (length < 0) { + throw new ArgumentException("length (" + length + ") is not greater or" + +"\u0020equal to 0"); + } + if (length > bytes.Length) { + throw new ArgumentException("length (" + length + ") is not less or" + +"\u0020equal to " + bytes.Length); + } + if (bytes.Length - offset < length) { + throw new ArgumentException("bytes's length minus " + offset + " (" + +(bytes.Length - offset) + ") is not greater or equal to " + length); + } + if (length == 0) { return EInteger.Zero; - } else if (bytes.Length == 1) { - return (((int)bytes[0] & 0x80) == 0) ? FromInt32((int)bytes[0]) : - FromInt32(-1 - ((~bytes[0]) & 0x7f)); + } else if (length == 1) { + return (((int)bytes[offset] & 0x80) == 0) ? +FromInt32((int)bytes[offset]) : + FromInt32(-1 - ((~bytes[offset]) & 0x7f)); } - int len = bytes.Length; + int len = length; int wordLength = (len >> 1) + (len & 1); var newreg = new short[wordLength]; int valueJIndex = littleEndian ? len - 1 : 0; @@ -319,27 +351,28 @@ public sealed partial class EInteger : IComparable, if (littleEndian) { for (var i = 0; i < evenedLen; i += 2, j++) { int index2 = i + 1; - int nrj = ((int)bytes[i]) & 0xff; - nrj |= ((int)bytes[i + 1]) << 8; + int nrj = ((int)bytes[offset + i]) & 0xff; + nrj |= ((int)bytes[offset + i + 1]) << 8; newreg[j] = unchecked((short)nrj); } if (odd) { newreg[evenedLen >> 1] = - unchecked((short)(((int)bytes[evenedLen]) & 0xff)); + unchecked((short)(((int)bytes[offset + evenedLen]) & 0xff)); } - numIsNegative = (bytes[len - 1] & 0x80) != 0; + numIsNegative = (bytes[offset + len - 1] & 0x80) != 0; } else { for (var i = 0; i < evenedLen; i += 2, j++) { int index = len - 1 - i; int index2 = len - 2 - i; - int nrj = ((int)bytes[index]) & 0xff; - nrj |= ((int)bytes[index2]) << 8; + int nrj = ((int)bytes[offset + index]) & 0xff; + nrj |= ((int)bytes[offset + index2]) << 8; newreg[j] = unchecked((short)nrj); } if (odd) { - newreg[evenedLen >> 1] = unchecked((short)(((int)bytes[0]) & 0xff)); + newreg[evenedLen >> 1] = unchecked((short)(((int)bytes[offset]) & +0xff)); } - numIsNegative = (bytes[0] & 0x80) != 0; + numIsNegative = (bytes[offset] & 0x80) != 0; } if (numIsNegative) { // Sign extension and two's-complement @@ -6186,48 +6219,6 @@ public sealed partial class EInteger : IComparable, } } - /* - // alt. implementation, but no performance advantage in testing - private static int AddInternalNew( - short[] c, - int cstart, - short[] words1, - int astart, - short[] words2, - int bstart, - int n) { - unchecked { - int carry; - const int SMask = ShortMask; - carry = 0; - long la, lb; - var i = 0; - while (n - i >= 3) { - la = (((long)words1[astart++]) & SMask); - la |= (((long)words1[astart++]) & SMask) << 16; - la |= (((long)words1[astart++]) & SMask) << 32; - lb = (((long)words2[bstart++]) & SMask); - lb |= (((long)words2[bstart++]) & SMask) << 16; - lb |= (((long)words2[bstart++]) & SMask) << 32; - la += lb + carry; - c[cstart++] = (short)la; - c[cstart++] = (short)(la >> 16); - c[cstart++] = (short)(la >> 32); - carry=(int)(la >> 48); - i+=3; - } - while (i < n) { - carry += (((int)words1[astart++]) & SMask) + - (((int)words2[bstart++]) & SMask); - c[cstart++] = (short)carry; - carry>>= 16; - ++i; - } - return carry; - } - } - */ - private static int AddUnevenSize( short[] c, int cstart, diff --git a/Numbers/docs.xml b/Numbers/docs.xml index 91dd1c1..b25ff12 100644 --- a/Numbers/docs.xml +++ b/Numbers/docs.xml @@ -10384,8 +10384,8 @@ Compares an arbitrary-precision integer with this instance. - The parameter is - a 64-bit signed integer. + The parameter + is a 64-bit signed integer. Zero if the values are equal; a negative number if this instance is less, or a positive number if this instance is greater. @@ -10631,6 +10631,23 @@ 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. + 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. + A portion of a byte array consisting of the two's-complement + form (see + "Forms of numbers" ) of + the arbitrary-precision integer to create. The byte array portion has to be encoded using the following rules: Positive numbers have the first byte's highest bit cleared, @@ -10655,10 +10672,8 @@ 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. + An arbitrary-precision integer. Returns 0 if "length" is 0. The parameter is null. - @@ -11013,11 +11028,15 @@ Returns the greatest common divisor of this integer and the given integer. The greatest common divisor (GCD) is also known - as the greatest common factor (GCF). - Another arbitrary-precision - integer. - An arbitrary-precision integer. + as the greatest common factor (GCF). This method works even if + either or both integers are negative. + Another arbitrary-precision integer. Can + be negative. + The greatest common divisor of this integer and the given + integer. The parameter is null. + Attempted to divide by + zero. @@ -11077,8 +11096,9 @@ lowest set bit in the number's two's-complement form (see "Forms of numbers" ).). - The bit position of the lowest bit set in the number, - starting at 0. Returns -1 if this value is 0. + The bit position of the lowest bit set in the number's + absolute value, starting at 0. Returns -1 if this value is + 0. @@ -11089,8 +11109,9 @@ the number's two's-complement form (see "Forms of numbers" ).). - The bit position of the lowest bit set in the number, - starting at 0. Returns -1 if this value is 0 or odd. + The bit position of the lowest bit set in the number's + absolute value, starting at 0. Returns -1 if this value is 0 or + odd. @@ -11101,13 +11122,13 @@ number's two's-complement form (see "Forms of numbers" ).). - The bit position of the lowest bit set in the number, - starting at 0. Returns -1 if this value is 0 or odd. Returns 2^63 - - 1 ( Int64.MaxValue in.NET or Long.MAX_VALUE in Java) - if this number is other than zero but the lowest set bit is at 2^63 - - 1 or greater. (Use GetLowBitAsEInteger instead if the - application relies on the exact value of the lowest set bit - position.). + The bit position of the lowest bit set in the number's + absolute value, starting at 0. Returns -1 if this value is 0 or + odd. Returns 2^63 - 1 ( Int64.MaxValue in.NET or + Long.MAX_VALUE in Java) if this number is other than zero + but the lowest set bit is at 2^63 - 1 or greater. (Use + GetLowBitAsEInteger instead if the application relies on the + exact value of the lowest set bit position.). @@ -11822,7 +11843,8 @@ significant bit of the number will be all ones. The resulting byte array can be passed to the FromBytes() method (with the same byte order) to reconstruct this integer's value. - Either true or false. + See the 'littleEndian' parameter of the + FromBytes() method. A byte array. If this value is 0, returns a byte array with the single element 0. @@ -11922,9 +11944,10 @@ Converts this object to a text string in base 10. - A string representation of this object. If negative, the - string will begin with a minus sign ("-", U+002D). The string will - use the basic digits 0 to 9 (U+0030 to U+0039). + A string representation of this object. If this value is + 0, returns "0". If negative, the string will begin with a minus + sign ("-", U+002D). The string will use the basic digits 0 to 9 + (U+0030 to U+0039). diff --git a/Numbers20/Numbers20.csproj b/Numbers20/Numbers20.csproj index 132c8a1..c54894f 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.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 diff --git a/Numbers40/Numbers40.csproj b/Numbers40/Numbers40.csproj index a769a2d..98af579 100644 --- a/Numbers40/Numbers40.csproj +++ b/Numbers40/Numbers40.csproj @@ -1 +1 @@ -winDebugAnyCPULibraryNumbersv4.0true..\Numbers\PeterO.snk{D7E09F55-3156-44B0-87D9-1BABCBB398D9}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 +winDebugAnyCPULibraryNumbersv4.0true..\Numbers\PeterO.snk{D7E09F55-3156-44B0-87D9-1BABCBB398D9}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 diff --git a/Test20/Test20.csproj b/Test20/Test20.csproj index 419c566..9c03ebb 100644 --- a/Test20/Test20.csproj +++ b/Test20/Test20.csproj @@ -1,2 +1 @@ -DebugAnyCPU{4CF0E5BA-CDE3-4DEA-B3F4-11EE544B3FB2}ExeTest20v2.0rules.rulesettruefullfalsebin\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.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 diff --git a/Test40/Test40.csproj b/Test40/Test40.csproj index 30adf8c..186b91a 100644 --- a/Test40/Test40.csproj +++ b/Test40/Test40.csproj @@ -1,2 +1 @@ -DebugAnyCPU{00EB31B6-A805-4EFB-A64B-9F8176B2A1CC}ExeTest40rules.rulesettruefullfalsebin\DebugDEBUG;NET40prompt4truerules.rulesettruebin\ReleasepromptNET404truerules.ruleset3.12.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{D7E09F55-3156-44B0-87D9-1BABCBB398D9}Test40v4.0 - +DebugAnyCPU{00EB31B6-A805-4EFB-A64B-9F8176B2A1CC}ExeTest40rules.rulesettruefullfalsebin\DebugDEBUG;NET40prompt4truerules.rulesettruebin\ReleasepromptNET404truerules.ruleset3.12.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{D7E09F55-3156-44B0-87D9-1BABCBB398D9}Test40v4.0win diff --git a/docs/PeterO.Numbers.EInteger.md b/docs/PeterO.Numbers.EInteger.md index bdb5e9b..d84b691 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. @@ -816,7 +817,34 @@ Initializes an arbitrary-precision integer from an array of bytes. 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 following rules: + * 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. + + * 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. + + +### 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. + +Parameters: + + * bytes: A portion of 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 portion has to be encoded using the following rules: * Positive numbers have the first byte's highest bit cleared, and negative numbers have the bit set. @@ -833,7 +861,7 @@ For little-endian, the byte order is reversed from the byte order just discussed Return Value: -An arbitrary-precision integer. Returns 0 if the byte array's length is 0. +An arbitrary-precision integer. Returns 0 if "length" is 0. Exceptions: @@ -1339,15 +1367,15 @@ The value of ulongValue public PeterO.Numbers.EInteger Gcd( PeterO.Numbers.EInteger bigintSecond); -Returns the greatest common divisor of this integer and the given integer. The greatest common divisor (GCD) is also known as the greatest common factor (GCF). +Returns the greatest common divisor of this integer and the given integer. The greatest common divisor (GCD) is also known as the greatest common factor (GCF). This method works even if either or both integers are negative. Parameters: - * bigintSecond: Another arbitrary-precision integer. + * bigintSecond: Another arbitrary-precision integer. Can be negative. Return Value: -An arbitrary-precision integer. +The greatest common divisor of this integer and the given integer. Exceptions: @@ -1355,9 +1383,6 @@ An arbitrary-precision integer. The parameter bigintSecond is null. - * System.ArgumentException: -bigPower is negative; doesn't satisfy shiftBits<16; doesn't satisfy sqroot.Sign>= 0 - * System.DivideByZeroException: Attempted to divide by zero. From 4eed293fddb86c710074b2410adebc2e0b2864a5 Mon Sep 17 00:00:00 2001 From: Peter O Date: Sun, 12 Jul 2020 17:38:20 -0400 Subject: [PATCH 02/16] code and style fixes; edit tests; etc. --- Numbers/PeterO/DebugUtility.cs | 5 +- Numbers/PeterO/Numbers/EDecimal.cs | 2 +- Numbers/PeterO/Numbers/EInteger.cs | 73 ++++++++++---- Test/EIntegerTest.cs | 38 +++++--- Test/Test.csproj | 4 +- Test/TestCommon.cs | 149 ++++++++++++++++++++++++++++- docs/PeterO.Numbers.EInteger.md | 32 +------ 7 files changed, 233 insertions(+), 70 deletions(-) diff --git a/Numbers/PeterO/DebugUtility.cs b/Numbers/PeterO/DebugUtility.cs index 9a33f54..9d8a478 100644 --- a/Numbers/PeterO/DebugUtility.cs +++ b/Numbers/PeterO/DebugUtility.cs @@ -7,7 +7,9 @@ */ using System; using System.Reflection; - +// Use directives rather than the Conditional attribute, +// to avoid the chance of logging statements leaking in release builds +#if DEBUG namespace PeterO { internal static class DebugUtility { private static readonly object WriterLock = new Object(); @@ -70,3 +72,4 @@ internal static class DebugUtility { } } } +#endif diff --git a/Numbers/PeterO/Numbers/EDecimal.cs b/Numbers/PeterO/Numbers/EDecimal.cs index 17db6ea..6c0e32f 100644 --- a/Numbers/PeterO/Numbers/EDecimal.cs +++ b/Numbers/PeterO/Numbers/EDecimal.cs @@ -1398,7 +1398,7 @@ 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 + /// The length, in bytes, of the desired /// portion of (but not more than 's length). /// An arbitrary-precision decimal number with the same value diff --git a/Numbers/PeterO/Numbers/EInteger.cs b/Numbers/PeterO/Numbers/EInteger.cs index 84fc0c4..a50051b 100644 --- a/Numbers/PeterO/Numbers/EInteger.cs +++ b/Numbers/PeterO/Numbers/EInteger.cs @@ -287,43 +287,70 @@ public sealed partial class EInteger : IComparable, } /// Initializes an arbitrary-precision integer from a portion - /// of an array of bytes. - /// An arbitrary-precision integer. Returns 0 if "length" is - /// 0. - /// The parameter is null. - /// Not documented yet. - /// Not documented yet. + /// 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, - bool littleEndian) { + int offset, + int length, + bool littleEndian) { if (bytes == null) { throw new ArgumentNullException(nameof(bytes)); } if (offset < 0) { throw new ArgumentException("offset (" + offset + ") is not greater" + -"\u0020or equal to 0"); + "\u0020or equal to 0"); } if (offset > bytes.Length) { throw new ArgumentException("offset (" + offset + ") is not less or" + -"\u0020equal to " + bytes.Length); + "\u0020equal to " + bytes.Length); } if (length < 0) { - throw new ArgumentException("length (" + length + ") is not greater or" + -"\u0020equal to 0"); + throw new ArgumentException("length (" + length + ") is not " + + "greater or equal to 0"); } if (length > bytes.Length) { throw new ArgumentException("length (" + length + ") is not less or" + @@ -331,7 +358,7 @@ public sealed partial class EInteger : IComparable, } if (bytes.Length - offset < length) { throw new ArgumentException("bytes's length minus " + offset + " (" + -(bytes.Length - offset) + ") is not greater or equal to " + length); + (bytes.Length - offset) + ") is not greater or equal to " + length); } if (length == 0) { return EInteger.Zero; @@ -1488,7 +1515,7 @@ public sealed partial class EInteger : IComparable, /// integer. /// /// EInteger result = EInteger.FromString("5").Multiply(200); - /// . + /// . /// public EInteger Multiply(int intValue) { return this.Multiply(EInteger.FromInt32(intValue)); @@ -2912,6 +2939,9 @@ public sealed partial class EInteger : IComparable, /// name='bigintSecond'/> is null. /// Attempted to divide by /// zero. + /// bigPower is negative; doesn't + /// satisfy shiftBits&lt;16; doesn't satisfy sqroot.Sign&gt;= + /// 0 public EInteger Gcd(EInteger bigintSecond) { if (bigintSecond == null) { throw new ArgumentNullException(nameof(bigintSecond)); @@ -2931,7 +2961,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); @@ -3414,10 +3445,14 @@ public sealed partial class EInteger : IComparable, // DebugUtility.Log("eia->" + eia.ToRadixString(16)); // DebugUtility.Log("eib->" + eib.ToRadixString(16)); if (eia.Sign < 0 || eib.Sign < 0) { + StringBuilder sb = new StringBuilder(); + sb.Append("eia="+ret[0] +"\n"); + sb.Append("eib="+ret[0] +"\n"); for (int k = 0; k < 6; ++k) { - DebugUtility.Log("hgcd[" + k + "]=" + hgcd[k].ToRadixString(16)); + sb.Append("hgcd_" + k + "=" + hgcd[k].ToRadixString(16)); + sb.Append("\n"); } - throw new InvalidOperationException("Internal error"); + throw new InvalidOperationException("Internal error\n" + sb); } ein = MaxBitLength(eia, eib); ret[0] = eia; diff --git a/Test/EIntegerTest.cs b/Test/EIntegerTest.cs index 00dd489..ba92dd1 100644 --- a/Test/EIntegerTest.cs +++ b/Test/EIntegerTest.cs @@ -1282,34 +1282,39 @@ public class EIntegerTest { } public static bool TestEIntegerFromBytes(byte[] bytes, bool littleEndian) { + 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 (bytes.Length == 0) { + if (length == 0) { return false; } if (littleEndian) { - if (!(bytes.Length == 1 || ( - !(bytes[bytes.Length - 1] == 0x00 && ((int)bytes[bytes.Length - - 2] & 0x80) == 0) && !(bytes[bytes.Length - 1] == (byte)0xff && - ((int)bytes[bytes.Length - 2] & 0x80) != 0)))) { + if (!(length == 1 || ( + !(bytes[offset + length - 1] == 0x00 && ((int)bytes[offset + length + - 2] & 0x80) == 0) && !(bytes[offset + length - 1] == (byte)0xff && + ((int)bytes[offset + length - 2] & 0x80) != 0)))) { return false; } } else { - if (!(bytes.Length == 1 || ( - !(bytes[0] == 0x00 && ((int)bytes[1] & 0x80) == 0) && - !(bytes[0] == (byte)0xff && ((int)bytes[1] & 0x80) != 0) -))) { + if (!(length == 1 || ( + !(bytes[offset] == 0x00 && ((int)bytes[offset + 1] & 0x80) == 0) && + !(bytes[offset] == (byte)0xff && ((int)bytes[offset + 1] & 0x80) != 0)))) { return false; } } var negative = false; - negative = (!littleEndian) ? ((bytes[0] & 0x80) != 0) : - ((bytes[bytes.Length - 1] & 0x80) != 0); - EInteger ei = EInteger.FromBytes(bytes, littleEndian); + negative = (!littleEndian) ? ((bytes[offset] & 0x80) != 0) : + ((bytes[offset + length - 1] & 0x80) != 0); + 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, ba); + TestCommon.AssertByteArraysEqual(bytes, offset, length, ba); return true; } @@ -1331,6 +1336,13 @@ public class EIntegerTest { for (var i = 0; i < 1000; ++i) { byte[] bytes = RandomObjects.RandomByteString(rg); TestEIntegerFromBytes(bytes, rg.UniformInt(2) == 0); + int offset1=rg.GetInt32(bytes.Length+1); + int offset2=rg.GetInt32(bytes.Length+1); + if (offset1!=offset2) { + int length=Math.Abs(offset1-offset2); + int offset=Math.Min(offset1, offset2); + TestEIntegerFromBytes(bytes, offset, length, rg.UniformInt(2) == 0); + } } } [Test] diff --git a/Test/Test.csproj b/Test/Test.csproj index 0b46345..6a62fb9 100644 --- a/Test/Test.csproj +++ b/Test/Test.csproj @@ -17,9 +17,9 @@ Resources.resources - + - + diff --git a/Test/TestCommon.cs b/Test/TestCommon.cs index 021165e..b69d17f 100644 --- a/Test/TestCommon.cs +++ b/Test/TestCommon.cs @@ -104,6 +104,48 @@ public static class TestCommon { } } + public static void AssertByteArraysEqual( + byte[] arr1, + int offset, + int length, + byte[] arr2) { + if (!ByteArraysEqual(arr1, offset, length, arr2, 0, arr2 == null ? 0 : +arr2.Length)) { + Assert.Fail("Expected " + ToByteArrayString(arr1) + ",\ngot..... " + + ToByteArrayString(arr2)); + } + } + + public static void AssertByteArraysEqual( + byte[] arr1, + byte[] arr2, + int offset2, + int length2) { + if (!ByteArraysEqual( + arr1, + 0, + arr1 == null ? 0 : arr1.Length, + arr2, + offset2, + length2)) { + Assert.Fail("Expected " + ToByteArrayString(arr1) + ",\ngot..... " + + ToByteArrayString(arr2)); + } + } + + public static void AssertByteArraysEqual( + byte[] arr1, + int offset, + int length, + byte[] arr2, + int offset2, + int length2) { + if (!ByteArraysEqual(arr1, offset, length, arr2, offset2, length2)) { + Assert.Fail("Expected " + ToByteArrayString(arr1) + ",\ngot..... " + + ToByteArrayString(arr2)); + } + } + public static void AssertNotEqual(object o, object o2, string msg) { if (o == null) { throw new ArgumentNullException(nameof(o)); @@ -588,27 +630,126 @@ public static void CompareTestLessEqual(T o1, T o2, string msg) } public static string ToByteArrayString(byte[] bytes) { + return (bytes == null) ? "null" : (ToByteArrayString(bytes, 0, + bytes.Length)); + } + + public static string ToByteArrayString(byte[] bytes, int offset, int +length) { if (bytes == null) { return "null"; } + if (bytes == null) { + throw new ArgumentNullException(nameof(bytes)); + } + if (offset < 0) { + throw new ArgumentException("\"offset\" (" + offset + ") is not" + +"\u0020greater or equal to 0"); + } + if (offset > bytes.Length) { + throw new ArgumentException("\"offset\" (" + offset + ") is not less" + +"\u0020or equal to " + bytes.Length); + } + if (length < 0) { + throw new ArgumentException(" (" + length + ") is not greater or" + +"\u0020equal to 0"); + } + if (length > bytes.Length) { + throw new ArgumentException(" (" + length + ") is not less or equal" + +"\u0020to " + bytes.Length); + } + if (bytes.Length - offset < length) { + throw new ArgumentException("\"bytes\" + \"'s length minus \" +" + +"\u0020offset (" + (bytes.Length - offset) + ") is not greater or equal to " + +length); + } var sb = new System.Text.StringBuilder(); const string ValueHex = "0123456789ABCDEF"; sb.Append("new byte[] { "); - for (var i = 0; i < bytes.Length; ++i) { + for (var i = 0; i < length; ++i) { if (i > 0) { sb.Append(","); } - if ((bytes[i] & 0x80) != 0) { + if ((bytes[offset + i] & 0x80) != 0) { sb.Append("(byte)0x"); } else { sb.Append("0x"); } - sb.Append(ValueHex[(bytes[i] >> 4) & 0xf]); - sb.Append(ValueHex[bytes[i] & 0xf]); + sb.Append(ValueHex[(bytes[offset + i] >> 4) & 0xf]); + sb.Append(ValueHex[bytes[offset + i] & 0xf]); } sb.Append("}"); return sb.ToString(); } + private static bool ByteArraysEqual( + byte[] arr1, + int offset, + int length, + byte[] arr2, + int offset2, + int length2) { + if (arr1 == null) { + return arr2 == null; + } + if (arr2 == null) { + return false; + } + if (offset < 0) { + throw new ArgumentException("\"offset\" (" + offset + ") is not" + +"\u0020greater or equal to 0"); + } + if (offset > arr1.Length) { + throw new ArgumentException("\"offset\" (" + offset + ") is not less" + +"\u0020or equal to " + arr1.Length); + } + if (length < 0) { + throw new ArgumentException(" (" + length + ") is not greater or" + +"\u0020equal to 0"); + } + if (length > arr1.Length) { + throw new ArgumentException(" (" + length + ") is not less or equal" + +"\u0020to " + arr1.Length); + } + if (arr1.Length - offset < length) { + throw new ArgumentException("\"arr1\" + \"'s length minus \" +" + +"\u0020offset (" + (arr1.Length - offset) + ") is not greater or equal to " + +length); + } + if (arr2 == null) { + throw new ArgumentNullException(nameof(arr2)); + } + if (offset2 < 0) { + throw new ArgumentException("\"offset2\" (" + offset2 + ") is not" + +"\u0020greater or equal to 0"); + } + if (offset2 > arr2.Length) { + throw new ArgumentException("\"offset2\" (" + offset2 + ") is not" + +"\u0020less or equal to " + arr2.Length); + } + if (length2 < 0) { + throw new ArgumentException(" (" + length2 + ") is not greater or" + +"\u0020equal to 0"); + } + if (length2 > arr2.Length) { + throw new ArgumentException(" (" + length2 + ") is not less or equal" + +"\u0020to " + arr2.Length); + } + if (arr2.Length - offset2 < length2) { + throw new ArgumentException("\"arr2\"'s length minus " + +"\u0020offset2 (" + (arr2.Length - offset2) + ") is not greater or equal to " + +length2); + } + if (length != length2) { + return false; + } + for (var i = 0; i < length; ++i) { + if (arr1[offset + i] != arr2[offset + i]) { + return false; + } + } + return true; + } + private static bool ByteArraysEqual(byte[] arr1, byte[] arr2) { if (arr1 == null) { return arr2 == null; diff --git a/docs/PeterO.Numbers.EInteger.md b/docs/PeterO.Numbers.EInteger.md index d84b691..39aa94e 100644 --- a/docs/PeterO.Numbers.EInteger.md +++ b/docs/PeterO.Numbers.EInteger.md @@ -56,7 +56,6 @@ 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. @@ -817,34 +816,7 @@ Initializes an arbitrary-precision integer from an array of bytes. 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. - - * 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. - - -### 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. - -Parameters: - - * bytes: A portion of 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 portion has to be encoded using the following rules: + * 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 following rules: * Positive numbers have the first byte's highest bit cleared, and negative numbers have the bit set. @@ -861,7 +833,7 @@ For little-endian, the byte order is reversed from the byte order just discussed Return Value: -An arbitrary-precision integer. Returns 0 if "length" is 0. +An arbitrary-precision integer. Returns 0 if the byte array's length is 0. Exceptions: From 8b10f26524e6633332447527d34ad1bc1af6f75a Mon Sep 17 00:00:00 2001 From: Peter O Date: Mon, 13 Jul 2020 00:33:04 -0400 Subject: [PATCH 03/16] Address issues with GCD --- Numbers/PeterO/DebugUtility.cs | 11 +- Numbers/PeterO/Numbers/EDecimal.cs | 4 +- Numbers/PeterO/Numbers/EInteger.cs | 251 +++++++++++++++++++++-------- Test/EIntegerTest.cs | 90 +++++++++-- Test/TestCommon.cs | 23 ++- 5 files changed, 286 insertions(+), 93 deletions(-) diff --git a/Numbers/PeterO/DebugUtility.cs b/Numbers/PeterO/DebugUtility.cs index 9d8a478..c4f7371 100644 --- a/Numbers/PeterO/DebugUtility.cs +++ b/Numbers/PeterO/DebugUtility.cs @@ -8,7 +8,7 @@ using System; using System.Reflection; // Use directives rather than the Conditional attribute, -// to avoid the chance of logging statements leaking in release builds + // to avoid the chance of logging statements leaking in release builds #if DEBUG namespace PeterO { internal static class DebugUtility { @@ -49,7 +49,14 @@ internal static class DebugUtility { wr(str); return; } else { - throw new NotSupportedException("System.Console not found"); + #if !NET20 && !NET40 + System.Diagnostics.Debug.WriteLine(str); + return; + #else +{ + throw new NotSupportedException("System.Console not found"); +} + #endif } } var types = new[] { typeof(string) }; diff --git a/Numbers/PeterO/Numbers/EDecimal.cs b/Numbers/PeterO/Numbers/EDecimal.cs index 6c0e32f..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 bytes, 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 a50051b..fba2b63 100644 --- a/Numbers/PeterO/Numbers/EInteger.cs +++ b/Numbers/PeterO/Numbers/EInteger.cs @@ -317,8 +317,8 @@ public sealed partial class EInteger : IComparable, /// 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 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 @@ -1515,7 +1515,7 @@ public sealed partial class EInteger : IComparable, /// integer. /// /// EInteger result = EInteger.FromString("5").Multiply(200); - /// . + /// . /// public EInteger Multiply(int intValue) { return this.Multiply(EInteger.FromInt32(intValue)); @@ -2893,7 +2893,7 @@ public sealed partial class EInteger : IComparable, return ei; } - private static EInteger GcdLong(long u, long v) { + private static long GcdLong(long u, long v) { // Adapted from Christian Stigen Larsen's // public domain GCD code #if DEBUG @@ -2922,9 +2922,7 @@ public sealed partial class EInteger : IComparable, v = tmp; } } - EInteger eret = (u == 0) ? - EInteger.FromInt64(v << shl) : EInteger.FromInt64(u << shl); - return eret; + return (u == 0) ? (v << shl) : (u << shl); } /// Returns the greatest common divisor of this integer and @@ -2973,7 +2971,7 @@ public sealed partial class EInteger : IComparable, if (thisValue.CanFitInInt64() && bigintSecond.CanFitInInt64()) { long u = thisValue.ToInt64Unchecked(); long v = bigintSecond.ToInt64Unchecked(); - return GcdLong(u, v); + return EInteger.FromInt64(GcdLong(u, v)); } else { bool bigger = thisValue.CompareTo(bigintSecond) >= 0; if (!bigger) { @@ -3056,7 +3054,8 @@ public sealed partial class EInteger : IComparable, } while (!eib.IsZero) { if (eia.wordCount <= 3 && eib.wordCount <= 3) { - return GcdLong(eia.ToInt64Checked(), eib.ToInt64Checked()); + return EInteger.FromInt64( + GcdLong(eia.ToInt64Checked(), eib.ToInt64Checked())); } EInteger ta = eib; eib = eia.Remainder(eib); @@ -3078,20 +3077,30 @@ public sealed partial class EInteger : IComparable, // a, b, m[0] ... m[3] if (eiam[0].CompareTo(eiam[1]) > 0) { // a > b - EInteger[] divrem = eiam[0].DivRem(eiam[1]); + EInteger eia = eiam[0]; + EInteger eib = eiam[1]; + EInteger[] divrem = eia.DivRem(eib); if (BL(divrem[1]).CompareTo(eis) <= 0) { divrem[0] = divrem[0].Subtract(1); - divrem[1] = divrem[1].Add(eiam[1]); + if (divrem[0].Sign < 0) { + throw new InvalidOperationException(); + } + divrem[1] = divrem[1].Add(eib); } eiam[3] = eiam[3].Add(eiam[2].Multiply(divrem[0])); eiam[5] = eiam[5].Add(eiam[4].Multiply(divrem[0])); eiam[0] = divrem[1]; } else { // a <= b - EInteger[] divrem = eiam[1].DivRem(eiam[0]); + EInteger eia = eiam[1]; + EInteger eib = eiam[0]; + EInteger[] divrem = eia.DivRem(eib); if (BL(divrem[1]).CompareTo(eis) <= 0) { divrem[0] = divrem[0].Subtract(1); - divrem[1] = divrem[1].Add(eiam[0]); + if (divrem[0].Sign < 0) { + throw new InvalidOperationException(); + } + divrem[1] = divrem[1].Add(eib); } eiam[2] = eiam[2].Add(eiam[3].Multiply(divrem[0])); eiam[4] = eiam[4].Add(eiam[5].Multiply(divrem[0])); @@ -3112,30 +3121,40 @@ public sealed partial class EInteger : IComparable, // a, b, m[0] ... m[3] if (longam[0] > longam[1]) { // a > b - long drem = longam[0] % longam[1]; - var divrem = new long[] { - longam[0] / longam[1], drem, + long a = longam[0]; + long b = longam[1]; + long ddiv = a / b; + var ldivrem = new long[] { + ddiv, a - (ddiv * b), }; - if (LBL(divrem[1]) <= ls) { - --divrem[0]; - divrem[1] += longam[1]; + if (LBL(ldivrem[1]) <= ls) { + --ldivrem[0]; + if (ldivrem[0] < 0) { + throw new InvalidOperationException(); + } + ldivrem[1] += b; } - longam[3] += longam[2] * divrem[0]; - longam[5] += longam[4] * divrem[0]; - longam[0] = divrem[1]; + longam[3] += longam[2] * ldivrem[0]; + longam[5] += longam[4] * ldivrem[0]; + longam[0] = ldivrem[1]; } else { // a <= b - long drem = longam[1] / longam[0]; - var divrem = new long[] { - longam[1] % longam[0], drem, + long a = longam[1]; + long b = longam[0]; + long ddiv = a / b; + var ldivrem = new long[] { + ddiv, a - (ddiv * b), }; - if (LBL(divrem[1]) <= ls) { - --divrem[0]; - divrem[1] += longam[0]; + if (LBL(ldivrem[1]) <= ls) { + --ldivrem[0]; + if (ldivrem[0] < 0) { + throw new InvalidOperationException(); + } + ldivrem[1] += b; } - longam[2] += longam[3] * divrem[0]; - longam[4] += longam[5] * divrem[0]; - longam[1] = divrem[1]; + longam[2] += longam[3] * ldivrem[0]; + longam[4] += longam[5] * ldivrem[0]; + longam[1] = ldivrem[1]; } } } @@ -3149,16 +3168,36 @@ 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" + +"\u0020greater or equal to " + Int64.MinValue + 1); + } +#endif + return (mantlong == 0) ? 0 : NumberUtility.BitLength(Math.Abs(mantlong)); } private static long[] LHalfGCD(long longa, long longb) { +#if DEBUG + if (longa < 0) { + throw new ArgumentException("\"longa\" (" + longa + ") is not" + +"\u0020greater or equal to 0"); + } + if (longb < 0) { + throw new ArgumentException("\"longb\" (" + longb + ") is not" + +"\u0020greater or equal to 0"); + } +#endif + if (longa == 0 || longb == 0) { // DebugUtility.Log("LHalfGCD failed"); return new long[] { longa, longb, 1, 0, 0, 1 }; } + long olonga = longa; + long olongb = longb; var ret = new long[6]; - // DebugUtility.Log("LHalfGCD "+longa+" "+longb); + // DebugUtility.Log("LHalfGCD " + longa + " " + longb); checked { int ln = Math.Max(LBL(longa), LBL(longb)); int lnmin = Math.Min(LBL(longa), LBL(longb)); @@ -3167,7 +3206,7 @@ public sealed partial class EInteger : IComparable, // DebugUtility.Log("LHalfGCD failed: nmin<= s"); return new long[] { longa, longb, 1, 0, 0, 1 }; } - if (Math.Min(LBL(longa), LBL(longb)) > ((ln * 3) >> 2) + 2) { + if (lnmin > ((ln * 3) >> 2) + 2) { int p1 = ln >> 1; long nhalfmask = (1L << p1) - 1; long longah = longa >> p1; @@ -3183,9 +3222,13 @@ public sealed partial class EInteger : IComparable, longb = (longbl * ret2[2]) - (longal * ret2[4]); longa += ret2[0] << p1; longb += ret2[1] << p1; + if (longa < 0 || longb < 0) { + throw new InvalidOperationException( + "Internal error: longa=" + olonga + " olongb=" + + olongb); + } } else { // Set M to identity - ret = new long[6]; ret[2] = 1; ret[3] = 0; ret[4] = 0; @@ -3193,14 +3236,12 @@ public sealed partial class EInteger : IComparable, } ret[0] = longa; ret[1] = longb; - for (int k = 0; k < 6; ++k) { - // DebugUtility.Log("ret_afterloop1 "+k+"=" + - // EInteger.FromInt64(ret[k]).ToRadixString(16)); - } while (Math.Max(LBL(ret[0]), LBL(ret[1])) > ((ln * 3) >> 2) + 1 && LBL(ret[0] - ret[1]) > ls) { if (ret[0] < 0 || ret[1] < 0) { - throw new InvalidOperationException("Internal error"); + throw new InvalidOperationException( + "Internal error: longa=" + olonga + " olongb=" + + olongb); } LSDivStep(ret, ls); } @@ -3247,11 +3288,24 @@ public sealed partial class EInteger : IComparable, throw new InvalidOperationException("Internal error"); } #if DEBUG + /* long[] lret3 = SlowSgcd(olonga, olongb); + if (ret[0] != lret3[0] || ret[1] != lret3[1] || + ret[2] != lret3[2] || ret[3] != lret3[3] || + ret[4] != lret3[4] || ret[5] != lret3[5]) { + var sb = new StringBuilder(); + sb.Append("eia1=" + olonga + "\n"); + sb.Append("eib1=" + olongb + "\n"); + for (int k = 0; k < 6; ++k) { + sb.Append("expected_" + k + "=" + lret3[k] + "\n"); + sb.Append("got______" + k + "=" + ret[k] + "\n"); + } + throw new InvalidOperationException("" + sb); + } + */ // Verify det(M) == 1 if (ret[2] < 0 || ret[3] < 0 || ret[4] < 0 || ret[5] < 0) { - { throw new InvalidOperationException("Internal error"); - } + throw new InvalidOperationException("Internal error"); } if ((ret[2] * ret[5]) - (ret[3] * ret[4]) != 1) { throw new InvalidOperationException("Internal error"); @@ -3264,8 +3318,42 @@ public sealed partial class EInteger : IComparable, return ret; } + private static long[] SlowSgcd(long longa, long longb) { + var ret = new long[] { longa, longb, 1, 0, 0, 1 }; + int ls = Math.Max(LBL(longa), LBL(longb)); + ls = (ls >> 1) + 1; + while (LBL(ret[0] - ret[1]) > ls) { + LSDivStep(ret, ls); + } + return ret; + } + + private static EInteger[] SlowSgcd(EInteger eia, EInteger eib) { + var ret = new EInteger[] { + eia, eib, EInteger.One, EInteger.Zero, + EInteger.Zero, EInteger.One, + }; + EInteger eis = EInteger.Max(BL(eia), BL(eib)); + eis = eis.ShiftRight(1).Add(1); + while (BL(ret[0].Subtract(ret[1])).CompareTo(eis) > 0) { + SDivStep(ret, eis); + } + return ret; + } + // 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"); + } + if (eib.Sign < 0) { + throw new ArgumentException("doesn't satisfy !eib.IsNegative"); + } +#endif + + EInteger oeia = eia; + EInteger oeib = eib; if (eia.IsZero || eib.IsZero) { // DebugUtility.Log("HalfGCD failed"); return new EInteger[] { @@ -3274,6 +3362,7 @@ public sealed partial class EInteger : IComparable, }; } var ret = new EInteger[6]; + // DebugUtility.Log("HalfGCD " + eia + " " + eib); if (eia.CanFitInInt64() && eib.CanFitInInt64()) { long[] lret = LHalfGCD(eia.ToInt64Checked(), eib.ToInt64Checked()); if (lret == null) { @@ -3288,16 +3377,15 @@ public sealed partial class EInteger : IComparable, EInteger einmin = MinBitLength(eia, eib); long ln = ein.CanFitInInt64() ? ein.ToInt64Checked() : -1; EInteger eis = ein.ShiftRight(1).Add(1); - /* // if (einmin.CompareTo(eis) <= 0) { - //DebugUtility.Log("HalfGCD failed: nmin<= s"); - //return new EInteger[] { + if (einmin.CompareTo(eis) <= 0) { + // DebugUtility.Log("HalfGCD failed: nmin<= s"); + return new EInteger[] { eia, eib, EInteger.One, EInteger.Zero, - //EInteger.Zero, EInteger.One + EInteger.Zero, EInteger.One, }; - //} */ + } EInteger eiah, eial, eibh, eibl; - if (MinBitLength(eia, - eib).CompareTo(ein.Multiply(3).ShiftRight(2).Add(2)) > 0) { + if (einmin.CompareTo(ein.Multiply(3).ShiftRight(2).Add(2)) > 0) { EInteger p1 = ein.ShiftRight(1); EInteger nhalfmask = EInteger.FromInt32(1).ShiftLeft(p1).Subtract(1); eiah = eia.ShiftRight(p1); @@ -3313,9 +3401,13 @@ public sealed partial class EInteger : IComparable, eib = eibl.Multiply(ret2[2]).Subtract(eial.Multiply(ret2[4])); eia = eia.Add(ret2[0].ShiftLeft(p1)); eib = eib.Add(ret2[1].ShiftLeft(p1)); + if (eia.Sign < 0 || eib.Sign < 0) { + throw new InvalidOperationException( + "Internal error: oeia=" + oeia + " oeib=" + + oeib + " eiah=" + eiah + " eibh=" + eibh); + } } else { // Set M to identity - ret = new EInteger[6]; ret[2] = EInteger.FromInt32(1); ret[3] = EInteger.FromInt32(0); ret[4] = EInteger.FromInt32(0); @@ -3323,23 +3415,28 @@ public sealed partial class EInteger : IComparable, } ret[0] = eia; ret[1] = eib; + /* for (int k = 0; k < 6; ++k) { - // DebugUtility.Log("ret_afterloop1["+k+"]=" + - // ret[k].ToRadixString(16)); + DebugUtility.Log("ret_afterloop1_"+ k + "=" + + ret[k].ToRadixString(16)); } - while (MaxBitLength(ret[0], ret[1]).CompareTo( + */ while (MaxBitLength(ret[0], ret[1]).CompareTo( ein.Multiply(3).ShiftRight(2).Add(1)) > 0 && - BL(ret[0].Subtract(ret[1])).CompareTo(eis) > 0 -) { + BL(ret[0].Subtract(ret[1])).CompareTo(eis) > 0) { if (ret[0].Sign < 0 || ret[1].Sign < 0) { - throw new InvalidOperationException("Internal error"); + throw new InvalidOperationException( + "Internal error: eia=" + oeia + " oeib=" + + oeib); } SDivStep(ret, eis); + // for (int k = 0; k < 6; ++k) { + // DebugUtility.Log("ret_loop2_"+ k + "=" + ret[k].ToRadixString(16)); + // } } - for (int k = 0; k < 6; ++k) { - // DebugUtility.Log("ret_afterloop2["+k+"]=" + - // ret[k].ToRadixString(16)); - } + // for (int k = 0; k < 6; ++k) { + // DebugUtility.Log("ret_afterloop2_"+ k + "=" + + // ret[k].ToRadixString(16)); + // } eia = ret[0]; eib = ret[1]; if (MinBitLength(eia, eib).CompareTo(eis.Add(2)) > 0) { @@ -3378,10 +3475,10 @@ public sealed partial class EInteger : IComparable, } ret[0] = eia; ret[1] = eib; - for (int k = 0; k < 6; ++k) { + // for (int k = 0; k < 6; ++k) { // DebugUtility.Log("ret_afterloop3["+k+"]=" + // ret[k].ToRadixString(16)); - } + // } while (BL(ret[0].Subtract(ret[1])).CompareTo(eis) > 0) { if (ret[0].Sign < 0 || ret[1].Sign < 0) { throw new InvalidOperationException("Internal error"); @@ -3389,19 +3486,31 @@ public sealed partial class EInteger : IComparable, SDivStep(ret, eis); // DebugUtility.Log("[sdiv2]ret="+Arrays.toString(ret)); } - for (int k = 0; k < 6; ++k) { - // DebugUtility.Log("lhgcd["+k+"]=" + ret[k].ToRadixString(16)); - } #if DEBUG + /* EInteger[] ret3 = SlowSgcd(oeia, oeib); + if (!ret[0].Equals(ret3[0]) || + !ret[1].Equals(ret3[1]) || + !ret[2].Equals(ret3[2]) || + !ret[3].Equals(ret3[3]) || + !ret[4].Equals(ret3[4]) || + !ret[5].Equals(ret3[5])) { + var sb = new StringBuilder(); + sb.Append("eia1=" + oeia + "\n"); + sb.Append("eib1=" + oeib + "\n"); + for (int k = 0; k < 6; ++k) { + sb.Append("expected_" + k + "=" + ret3[k] + "\n"); + sb.Append("got______" + k + "=" + ret[k] + "\n"); + } + throw new InvalidOperationException("" + sb); + } + */ if (ret[0].Sign < 0 || ret[1].Sign < 0) { - { throw new InvalidOperationException("Internal error"); - } + throw new InvalidOperationException("Internal error"); } // Verify det(M) == 1 if (ret[2].Sign < 0 || ret[3].Sign < 0 || ret[4].Sign < 0 || ret[5].Sign < 0) { - { throw new InvalidOperationException("Internal error"); - } + throw new InvalidOperationException("Internal error"); } if (ret[2].Multiply(ret[5]).Subtract(ret[3].Multiply(ret[4])).CompareTo(1) != @@ -3445,9 +3554,9 @@ public sealed partial class EInteger : IComparable, // DebugUtility.Log("eia->" + eia.ToRadixString(16)); // DebugUtility.Log("eib->" + eib.ToRadixString(16)); if (eia.Sign < 0 || eib.Sign < 0) { - StringBuilder sb = new StringBuilder(); - sb.Append("eia="+ret[0] +"\n"); - sb.Append("eib="+ret[0] +"\n"); + var sb = new StringBuilder(); + sb.Append("eia=" + ret[0] + "\n"); + sb.Append("eib=" + ret[1] + "\n"); for (int k = 0; k < 6; ++k) { sb.Append("hgcd_" + k + "=" + hgcd[k].ToRadixString(16)); sb.Append("\n"); diff --git a/Test/EIntegerTest.cs b/Test/EIntegerTest.cs index ba92dd1..94935ef 100644 --- a/Test/EIntegerTest.cs +++ b/Test/EIntegerTest.cs @@ -1282,10 +1282,17 @@ public class EIntegerTest { } public static bool TestEIntegerFromBytes(byte[] bytes, bool littleEndian) { + if (bytes == null) { + throw new ArgumentNullException(nameof(bytes)); + } return TestEIntegerFromBytes(bytes, 0, bytes.Length, littleEndian); } - public static bool TestEIntegerFromBytes(byte[] bytes, int offset, int length, bool littleEndian) { + public static bool TestEIntegerFromBytes( + byte[] bytes, + int offset, + int length, + bool littleEndian) { if (bytes == null) { throw new ArgumentNullException(nameof(bytes)); } @@ -1294,22 +1301,26 @@ public class EIntegerTest { } if (littleEndian) { if (!(length == 1 || ( - !(bytes[offset + length - 1] == 0x00 && ((int)bytes[offset + length - - 2] & 0x80) == 0) && !(bytes[offset + length - 1] == (byte)0xff && + !(bytes[offset + length - 1] == 0x00 && ((int)bytes[offset + +length + - 2] & 0x80) == 0) && !(bytes[offset + length - 1] == +(byte)0xff && ((int)bytes[offset + length - 2] & 0x80) != 0)))) { return false; } } else { if (!(length == 1 || ( - !(bytes[offset] == 0x00 && ((int)bytes[offset + 1] & 0x80) == 0) && - !(bytes[offset] == (byte)0xff && ((int)bytes[offset + 1] & 0x80) != 0)))) { + !(bytes[offset] == 0x00 && ((int)bytes[offset + 1] & 0x80) == +0) && + !(bytes[offset] == (byte)0xff && ((int)bytes[offset + 1] & +0x80) != 0)))) { return false; } } var negative = false; negative = (!littleEndian) ? ((bytes[offset] & 0x80) != 0) : ((bytes[offset + length - 1] & 0x80) != 0); - EInteger ei = (offset==0 && length == bytes.Length) ? + EInteger ei = (offset == 0 && length == bytes.Length) ? EInteger.FromBytes(bytes, littleEndian) : EInteger.FromBytes(bytes, offset, length, littleEndian); Assert.AreEqual(negative, ei.Sign < 0); @@ -1336,11 +1347,11 @@ public class EIntegerTest { for (var i = 0; i < 1000; ++i) { byte[] bytes = RandomObjects.RandomByteString(rg); TestEIntegerFromBytes(bytes, rg.UniformInt(2) == 0); - int offset1=rg.GetInt32(bytes.Length+1); - int offset2=rg.GetInt32(bytes.Length+1); - if (offset1!=offset2) { - int length=Math.Abs(offset1-offset2); - int offset=Math.Min(offset1, offset2); + int offset1 = rg.GetInt32(bytes.Length + 1); + int offset2 = rg.GetInt32(bytes.Length + 1); + if (offset1 != offset2) { + int length = Math.Abs(offset1 - offset2); + int offset = Math.Min(offset1, offset2); TestEIntegerFromBytes(bytes, offset, length, rg.UniformInt(2) == 0); } } @@ -2098,6 +2109,63 @@ public class EIntegerTest { } } + [Test] + public void TestGcdSpecific1() { + EInteger eia = + + EInteger.FromString("31087445093332925259488531187214798679962746631365434956607825050983640030004626432697"); + EInteger eib = + + EInteger.FromString("634110413245973045752985332739706355633747812352917054306813756224650904"); + EInteger gcd = EInteger.FromString("1"); + TestGcdPair(eia, eib, gcd); + } + + [Test] + public void TestGcdSpecific2() { + EInteger eia = + + EInteger.FromString("34919464185156438130737093950000449414901433260046574365653671833127498045928977578356713"); + EInteger eib = + + EInteger.FromString("164193664625099565521863251759922447177022769597753704347721217067439342602815077739234"); + EInteger gcd = EInteger.FromString("1"); + TestGcdPair(eia, eib, gcd); + } + [Test] + public void TestGcdSpecific3() { + EInteger eia = + + EInteger.FromString("103862788645466657156274316837043801135780275578563880187476945864288161266"); + EInteger eib = + + EInteger.FromString("49380347741774569630130462581871110923545066914152503189431047757"); + EInteger gcd = EInteger.FromString("1"); + TestGcdPair(eia, eib, gcd); + } + [Test] + public void TestGcdSpecific6() { + EInteger eia = + + EInteger.FromString("4478588462902174856284550822841587751257736243593417026536878393910594570150960"); + EInteger eib = + + EInteger.FromString("200436597645961750509884674543137682538095599306199896499547606239076266894278634228"); + EInteger gcd = EInteger.FromString("4"); + TestGcdPair(eia, eib, gcd); + } + [Test] + public void TestGcdSpecific4() { + EInteger eia = + + EInteger.FromString("479324527105721205395276387652685206399828597662080440776635747462472972671572622295"); + EInteger eib = + + EInteger.FromString("838212340549242323846978901107367041041509191230401720028242035196388222327176688904324510590144"); + EInteger gcd = EInteger.FromString("11"); + TestGcdPair(eia, eib, gcd); + } + [Test] public void TestGetBits() { // not implemented yet diff --git a/Test/TestCommon.cs b/Test/TestCommon.cs index b69d17f..7d647d2 100644 --- a/Test/TestCommon.cs +++ b/Test/TestCommon.cs @@ -109,8 +109,13 @@ public static class TestCommon { int offset, int length, byte[] arr2) { - if (!ByteArraysEqual(arr1, offset, length, arr2, 0, arr2 == null ? 0 : -arr2.Length)) { + if (!ByteArraysEqual( + arr1, + offset, + length, + arr2, + 0, + arr2 == null ? 0 : arr2.Length)) { Assert.Fail("Expected " + ToByteArrayString(arr1) + ",\ngot..... " + ToByteArrayString(arr2)); } @@ -630,12 +635,16 @@ public static void CompareTestLessEqual(T o1, T o2, string msg) } public static string ToByteArrayString(byte[] bytes) { - return (bytes == null) ? "null" : (ToByteArrayString(bytes, 0, - bytes.Length)); + return (bytes == null) ? "null" : ToByteArrayString( + bytes, + 0, + bytes.Length); } - public static string ToByteArrayString(byte[] bytes, int offset, int -length) { + public static string ToByteArrayString( + byte[] bytes, + int offset, + int length) { if (bytes == null) { return "null"; } @@ -743,7 +752,7 @@ public static void CompareTestLessEqual(T o1, T o2, string msg) return false; } for (var i = 0; i < length; ++i) { - if (arr1[offset + i] != arr2[offset + i]) { + if (arr1[offset + i] != arr2[offset2 + i]) { return false; } } From 98fbf165271fc4488483b8064804f5c7f2acbbc0 Mon Sep 17 00:00:00 2001 From: Peter O Date: Mon, 13 Jul 2020 09:14:23 -0400 Subject: [PATCH 04/16] edit tests --- Test/EIntegerTest.cs | 68 ++++++++++++++++--------------------------- Test/RandomObjects.cs | 26 ++++++++++++++++- 2 files changed, 50 insertions(+), 44 deletions(-) diff --git a/Test/EIntegerTest.cs b/Test/EIntegerTest.cs index 94935ef..11f46d7 100644 --- a/Test/EIntegerTest.cs +++ b/Test/EIntegerTest.cs @@ -363,27 +363,6 @@ public class EIntegerTest { return r; } - public static EInteger RandomBigInteger(RandomGenerator r) { - if (r == null) { - throw new ArgumentNullException(nameof(r)); - } - int selection = r.UniformInt(100); - int count = r.UniformInt(60) + 1; - if (selection < 40) { - count = r.UniformInt(7) + 1; - } - if (selection < 50) { - count = r.UniformInt(15) + 1; - } - if (selection < 3) { - count = r.UniformInt(250) + 1; - } - var bytes = new byte[count]; - for (var i = 0; i < count; ++i) { - bytes[i] = (byte)((int)r.UniformInt(256)); - } - return BigFromBytes(bytes); - } [Test] public void TestFromBoolean() { Assert.AreEqual(EInteger.One, EInteger.FromBoolean(true)); @@ -412,8 +391,8 @@ public class EIntegerTest { public void TestAddSubtract() { var r = new RandomGenerator(); for (var i = 0; i < 10000; ++i) { - EInteger bigintA = RandomBigInteger(r); - EInteger bigintB = RandomBigInteger(r); + EInteger bigintA = RandomObjects.RandomEInteger(r); + EInteger bigintB = RandomObjects.RandomEInteger(r); EInteger bigintC = bigintA + (EInteger)bigintB; EInteger bigintD = bigintC - (EInteger)bigintB; if (!bigintD.Equals(bigintA)) { @@ -439,7 +418,7 @@ public class EIntegerTest { } } for (var i = 0; i < 10000; ++i) { - EInteger bigintA = RandomBigInteger(r); + EInteger bigintA = RandomObjects.RandomEInteger(r); int smallIntB = r.UniformInt(0x7fffffff); EInteger bigintC = bigintA.Add(smallIntB); EInteger bigintD = bigintC.Subtract(smallIntB); @@ -847,7 +826,7 @@ public class EIntegerTest { public void TestCanFitInInt() { var r = new RandomGenerator(); for (var i = 0; i < 2000; ++i) { - EInteger bigintA = RandomBigInteger(r); + EInteger bigintA = RandomObjects.RandomEInteger(r); Assert.AreEqual( bigintA.CanFitInInt32(), bigintA.GetSignedBitLengthAsEInteger().CompareTo(31) <= 0); @@ -936,9 +915,9 @@ public class EIntegerTest { public void TestCompareTo() { var r = new RandomGenerator(); for (var i = 0; i < 500; ++i) { - EInteger bigintA = RandomBigInteger(r); - EInteger bigintB = RandomBigInteger(r); - EInteger bigintC = RandomBigInteger(r); + EInteger bigintA = RandomObjects.RandomEInteger(r); + EInteger bigintB = RandomObjects.RandomEInteger(r); + EInteger bigintC = RandomObjects.RandomEInteger(r); TestCommon.CompareTestRelations(bigintA, bigintB, bigintC); TestCommon.CompareTestConsistency(bigintA, bigintB, bigintC); } @@ -2012,7 +1991,7 @@ public class EIntegerTest { } } var bigprime = (EInteger)prime; - EInteger ba = RandomBigInteger(rand); + EInteger ba = RandomObjects.RandomEInteger(rand); if (ba.IsZero) { continue; } @@ -2181,7 +2160,7 @@ public class EIntegerTest { Assert.AreEqual(39, integerTemp2); } for (var i = 0; i < 1000; ++i) { - EInteger bigintA = RandomBigInteger(r); + EInteger bigintA = RandomObjects.RandomEInteger(r); String str = bigintA.Abs().ToString(); Assert.AreEqual( EInteger.FromInt32(str.Length), @@ -2587,7 +2566,7 @@ public class EIntegerTest { public void TestIsEven() { var r = new RandomGenerator(); for (var i = 0; i < 1000; ++i) { - EInteger bigintA = RandomBigInteger(r); + EInteger bigintA = RandomObjects.RandomEInteger(r); EInteger mod = bigintA.Remainder(EInteger.FromInt64(2)); Assert.AreEqual(mod.IsZero, bigintA.IsEven); if (bigintA.IsEven) { @@ -2810,7 +2789,7 @@ public class EIntegerTest { } var r = new RandomGenerator(); for (var i = 0; i < 10000; ++i) { - EInteger bigintA = RandomBigInteger(r); + EInteger bigintA = RandomObjects.RandomEInteger(r); EInteger bigintB = bigintA + EInteger.One; EInteger bigintC = bigintA * (EInteger)bigintB; // Test near-squaring @@ -3116,7 +3095,7 @@ public class EIntegerTest { var r = new RandomGenerator(); for (var i = 0; i < 200; ++i) { int power = 1 + r.UniformInt(8); - EInteger bigintA = RandomBigInteger(r); + EInteger bigintA = RandomObjects.RandomEInteger(r); EInteger bigintB = bigintA; for (int j = 1; j < power; ++j) { bigintB *= bigintA; @@ -3141,7 +3120,7 @@ public class EIntegerTest { TestCommon.CompareTestEqualAndConsistent(bigint << -12, bigint >> 12); var r = new RandomGenerator(); for (var i = 0; i < 1000; ++i) { - EInteger bigintA = RandomBigInteger(r); + EInteger bigintA = RandomObjects.RandomEInteger(r); EInteger bigintB = bigintA; for (int j = 0; j < 100; ++j) { EInteger ba = bigintA; @@ -3174,7 +3153,7 @@ public class EIntegerTest { } } for (var i = 0; i < 1000; ++i) { - EInteger bigintA = RandomBigInteger(r); + EInteger bigintA = RandomObjects.RandomEInteger(r); bigintA = bigintA.Abs(); EInteger bigintB = bigintA; for (int j = 0; j < 100; ++j) { @@ -3198,7 +3177,7 @@ public class EIntegerTest { public void TestRoot() { var r = new RandomGenerator(); for (var i = 0; i < 20; ++i) { - EInteger bigintA = RandomBigInteger(r); + EInteger bigintA = RandomObjects.RandomEInteger(r); if (bigintA.Sign < 0) { bigintA = -bigintA; } @@ -3210,7 +3189,10 @@ public class EIntegerTest { TestCommon.CompareTestEqual(bigintA, sr); } for (var i = 0; i < 10000; ++i) { - EInteger bigintA = RandomBigInteger(r); + EInteger bigintA = RandomObjects.RandomEInteger(r); + while (bigintA.GetUnsignedBitLengthAsInt64() > 16 * 1000) { + bigintA = RandomObjects.RandomEInteger(r); + } if (bigintA.Sign < 0) { bigintA = -bigintA; } @@ -3254,7 +3236,7 @@ public class EIntegerTest { public void TestSqrt() { var r = new RandomGenerator(); for (var i = 0; i < 20; ++i) { - EInteger bigintA = RandomBigInteger(r); + EInteger bigintA = RandomObjects.RandomEInteger(r); if (bigintA.Sign < 0) { bigintA = -bigintA; } @@ -3268,7 +3250,7 @@ public class EIntegerTest { TestCommon.CompareTestEqual(bigintA, sr); } for (var i = 0; i < 10000; ++i) { - EInteger bigintA = RandomBigInteger(r); + EInteger bigintA = RandomObjects.RandomEInteger(r); if (bigintA.Sign < 0) { bigintA = -bigintA; } @@ -3408,7 +3390,7 @@ public class EIntegerTest { var r = new RandomGenerator(); for (var radix = 2; radix < 36; ++radix) { for (var i = 0; i < 80; ++i) { - EInteger bigintA = RandomBigInteger(r); + EInteger bigintA = RandomObjects.RandomEInteger(r); String s = bigintA.ToRadixString(radix); EInteger big2 = EInteger.FromRadixString(s, radix); Assert.AreEqual(big2.ToRadixString(radix), s); @@ -3429,14 +3411,14 @@ public class EIntegerTest { AssertBigIntegersEqual("898989", other); var r = new RandomGenerator(); for (var i = 0; i < 1000; ++i) { - EInteger bigintA = RandomBigInteger(r); + EInteger bigintA = RandomObjects.RandomEInteger(r); ExtraTest.TestStringEqualRoundTrip(bigintA); } // Test serialization of relatively big numbers for (var i = 0; i < 20; ++i) { - EInteger bigintA = RandomBigInteger(r); + EInteger bigintA = RandomObjects.RandomEInteger(r); bigintA = bigintA.ShiftLeft(r.UniformInt(2000) + (16 * 500)); - bigintA = bigintA.Subtract(RandomBigInteger(r)); + bigintA = bigintA.Subtract(RandomObjects.RandomEInteger(r)); ExtraTest.TestStringEqualRoundTrip(bigintA); } } diff --git a/Test/RandomObjects.cs b/Test/RandomObjects.cs index 5b662f9..aff1d24 100644 --- a/Test/RandomObjects.cs +++ b/Test/RandomObjects.cs @@ -314,12 +314,36 @@ public static class RandomObjects { return ed; } + private static EInteger RandomEIntegerAlt(IRandomGenExtended r) { + if (r == null) { + throw new ArgumentNullException(nameof(r)); + } + int selection = r.GetInt32(100); + int count = r.GetInt32(60) + 1; + if (selection < 40) { + count = r.GetInt32(7) + 1; + } + if (selection < 50) { + count = r.GetInt32(15) + 1; + } + if (selection < 3) { + count = r.GetInt32(250) + 1; + } + var bytes = new byte[count]; + for (var i = 0; i < count; ++i) { + bytes[i] = (byte)((int)r.GetInt32(256)); + } + return EInteger.FromBytes(bytes, true); + } + public static EInteger RandomEInteger(IRandomGenExtended r) { if (r == null) { throw new ArgumentNullException(nameof(r)); } int selection = r.GetInt32(100); - if (selection < 10) { + if (selection == 0) { + return RandomEIntegerAlt(r); + } else if (selection < 10) { int count = r.GetInt32(MaxNumberLength); count = (int)(((long)count * r.GetInt32(MaxNumberLength)) / MaxNumberLength); From ff2f60a6d9601076a6c3a0d2718bcb8e36a4833c Mon Sep 17 00:00:00 2001 From: Peter O Date: Tue, 14 Jul 2020 02:35:35 -0400 Subject: [PATCH 05/16] reinstate public modifier on EInteger.FromBytes overload --- Numbers/PeterO/Numbers/EInteger.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Numbers/PeterO/Numbers/EInteger.cs b/Numbers/PeterO/Numbers/EInteger.cs index 95ac951..d696008 100644 --- a/Numbers/PeterO/Numbers/EInteger.cs +++ b/Numbers/PeterO/Numbers/EInteger.cs @@ -320,12 +320,19 @@ public sealed partial class EInteger : IComparable, /// 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 . - private static EInteger FromBytes( + public static EInteger FromBytes( byte[] bytes, int offset, int length, From a5fb3a7556b11c3d642943feaad78ce7759950ff Mon Sep 17 00:00:00 2001 From: Peter O Date: Tue, 14 Jul 2020 02:37:31 -0400 Subject: [PATCH 06/16] code fix in test project --- Test/EIntegerTest.cs | 57 -------------------------------------------- 1 file changed, 57 deletions(-) diff --git a/Test/EIntegerTest.cs b/Test/EIntegerTest.cs index bbd74b9..db3cb2c 100644 --- a/Test/EIntegerTest.cs +++ b/Test/EIntegerTest.cs @@ -2162,63 +2162,6 @@ public class EIntegerTest { TestGcdPair(eia, eib, gcd); } - [Test] - public void TestGcdSpecific1() { - EInteger eia = - - EInteger.FromString("31087445093332925259488531187214798679962746631365434956607825050983640030004626432697"); - EInteger eib = - - EInteger.FromString("634110413245973045752985332739706355633747812352917054306813756224650904"); - EInteger gcd = EInteger.FromString("1"); - TestGcdPair(eia, eib, gcd); - } - - [Test] - public void TestGcdSpecific2() { - EInteger eia = - - EInteger.FromString("34919464185156438130737093950000449414901433260046574365653671833127498045928977578356713"); - EInteger eib = - - EInteger.FromString("164193664625099565521863251759922447177022769597753704347721217067439342602815077739234"); - EInteger gcd = EInteger.FromString("1"); - TestGcdPair(eia, eib, gcd); - } - [Test] - public void TestGcdSpecific3() { - EInteger eia = - - EInteger.FromString("103862788645466657156274316837043801135780275578563880187476945864288161266"); - EInteger eib = - - EInteger.FromString("49380347741774569630130462581871110923545066914152503189431047757"); - EInteger gcd = EInteger.FromString("1"); - TestGcdPair(eia, eib, gcd); - } - [Test] - public void TestGcdSpecific6() { - EInteger eia = - - EInteger.FromString("4478588462902174856284550822841587751257736243593417026536878393910594570150960"); - EInteger eib = - - EInteger.FromString("200436597645961750509884674543137682538095599306199896499547606239076266894278634228"); - EInteger gcd = EInteger.FromString("4"); - TestGcdPair(eia, eib, gcd); - } - [Test] - public void TestGcdSpecific4() { - EInteger eia = - - EInteger.FromString("479324527105721205395276387652685206399828597662080440776635747462472972671572622295"); - EInteger eib = - - EInteger.FromString("838212340549242323846978901107367041041509191230401720028242035196388222327176688904324510590144"); - EInteger gcd = EInteger.FromString("11"); - TestGcdPair(eia, eib, gcd); - } - [Test] public void TestGetBits() { // not implemented yet From 958c6990f3a9c79faa092ca863715a230c3a6df7 Mon Sep 17 00:00:00 2001 From: Peter O Date: Wed, 15 Jul 2020 04:21:50 -0400 Subject: [PATCH 07/16] edit test project; etc. --- Numbers/PeterO/Numbers/EInteger.cs | 16 ++---- Test/EFloatTest.cs | 3 ++ Test/RandomObjects.cs | 81 ++++++++++++++++++++++-------- 3 files changed, 68 insertions(+), 32 deletions(-) diff --git a/Numbers/PeterO/Numbers/EInteger.cs b/Numbers/PeterO/Numbers/EInteger.cs index d696008..86e1fa4 100644 --- a/Numbers/PeterO/Numbers/EInteger.cs +++ b/Numbers/PeterO/Numbers/EInteger.cs @@ -2937,9 +2937,6 @@ public sealed partial class EInteger : IComparable, /// name='bigintSecond'/> is null. /// Attempted to divide by /// zero. - /// bigPower is negative; doesn't - /// satisfy shiftBits&lt;16; doesn't satisfy sqroot.Sign&gt;= - /// 0 public EInteger Gcd(EInteger bigintSecond) { if (bigintSecond == null) { throw new ArgumentNullException(nameof(bigintSecond)); @@ -3170,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 @@ -3181,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 @@ -3343,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/Test/EFloatTest.cs b/Test/EFloatTest.cs index 104a28d..b858a59 100644 --- a/Test/EFloatTest.cs +++ b/Test/EFloatTest.cs @@ -2028,6 +2028,9 @@ public class EFloatTest { } EInteger emant = efa.Mantissa; int mantBits = emant.GetUnsignedBitLengthAsEInteger().ToInt32Checked(); + if (mantBits > bitCount) { + throw new InvalidOperationException("Too many bits; expected double- or single-sized significand"); + } bool fullPrecision = mantBits == bitCount; bool isSubnormal = EFloats.IsSubnormal(efa, dbl ? EContext.Binary64 : EContext.Binary32); diff --git a/Test/RandomObjects.cs b/Test/RandomObjects.cs index aff1d24..c4f9424 100644 --- a/Test/RandomObjects.cs +++ b/Test/RandomObjects.cs @@ -12,7 +12,9 @@ using PeterO.Numbers; namespace Test { - /// Description of RandomObjects. + /// Generates random objects of various kinds for purposes of + /// testing code that uses them. The methods will not necessarily + /// sample uniformly from all objects of a particular kind. public static class RandomObjects { private const int MaxExclusiveStringLength = 0x2000; private const int MaxExclusiveShortStringLength = 50; @@ -314,26 +316,31 @@ public static class RandomObjects { return ed; } - private static EInteger RandomEIntegerAlt(IRandomGenExtended r) { - if (r == null) { - throw new ArgumentNullException(nameof(r)); - } - int selection = r.GetInt32(100); - int count = r.GetInt32(60) + 1; - if (selection < 40) { - count = r.GetInt32(7) + 1; - } - if (selection < 50) { - count = r.GetInt32(15) + 1; - } - if (selection < 3) { - count = r.GetInt32(250) + 1; + private static EInteger BitHeavyEInteger(IRandomGenExtended rg, int count) { + var sb = new StringBuilder(); + int[] oneChances = { + 999, 1, 980, 20, 750, 250, 980, + 20, 980, 20, 980, 20, 750, 250, + }; + int oneChance = oneChances[rg.GetInt32(oneChances.Length)]; + for (var i = 0; i < count; ++i) { + sb.Append((rg.GetInt32(1000) >= oneChance) ? '0' : '1'); } - var bytes = new byte[count]; + return EInteger.FromRadixString(sb.ToString(), 2); + } + + private static EInteger DigitHeavyEInteger(IRandomGenExtended rg, int +count) { + var sb = new StringBuilder(); + int[] oneChances = { + 999, 1, 980, 20, 750, 250, 980, + 20, 980, 20, 980, 20, 750, 250, + }; + int oneChance = oneChances[rg.GetInt32(oneChances.Length)]; for (var i = 0; i < count; ++i) { - bytes[i] = (byte)((int)r.GetInt32(256)); + sb.Append((rg.GetInt32(1000) >= oneChance) ? '0' : '9'); } - return EInteger.FromBytes(bytes, true); + return EInteger.FromRadixString(sb.ToString(), 10); } public static EInteger RandomEInteger(IRandomGenExtended r) { @@ -341,15 +348,18 @@ public static class RandomObjects { throw new ArgumentNullException(nameof(r)); } int selection = r.GetInt32(100); - if (selection == 0) { - return RandomEIntegerAlt(r); - } else if (selection < 10) { + if (selection < 10) { int count = r.GetInt32(MaxNumberLength); count = (int)(((long)count * r.GetInt32(MaxNumberLength)) / MaxNumberLength); count = (int)(((long)count * r.GetInt32(MaxNumberLength)) / MaxNumberLength); count = Math.Max(count, 1); + if (selection == 0 || selection == 1) { + return BitHeavyEInteger(r, count); + } else if ((selection == 2 || selection == 3) && count < 500) { + return DigitHeavyEInteger(r, count); + } byte[] bytes = RandomByteString(r, count); return EInteger.FromBytes(bytes, true); } else { @@ -370,6 +380,32 @@ public static class RandomObjects { return EInteger.FromBytes(bytes, true); } + private static int IntInRange(IRandomGenExtended rg, int minInc, int +maxExc) { + return minInc + rg.GetInt32(maxExc - minInc); + } + + public static EFloat CloseToPowerOfTwo(IRandomGenExtended rg) { + if (rg == null) { + throw new ArgumentNullException(nameof(rg)); + } + int pwr = (rg.GetInt32(100) < 80) ? IntInRange(rg, -20, 20) : +IntInRange(rg, -300, 300); + int pwr2 = pwr - (rg.GetInt32(100) < 80 ? IntInRange(rg, 51, 61) : +IntInRange(rg, 2, 300)); + EFloat ef = null; + ef = (rg.GetInt32(2) == 0) ? (EFloat.Create(1, + pwr).Add(EFloat.Create(1, pwr2))) : (EFloat.Create(1, + pwr).Subtract(EFloat.Create(1, pwr2))); + if (rg.GetInt32(10) == 0) { + pwr2 = pwr - (rg.GetInt32(100) < 80 ? IntInRange(rg, 51, 61) : +IntInRange(rg, 2, 300)); + ef = (rg.GetInt32(2) == 0) ? (ef.Add(EFloat.Create(1, pwr2))) : +(ef.Subtract(EFloat.Create(1, pwr2))); + } + return ef; + } + public static EFloat RandomEFloat(IRandomGenExtended r) { if (r == null) { throw new ArgumentNullException(nameof(r)); @@ -386,6 +422,9 @@ public static class RandomObjects { return EFloat.NaN; } } + if (r.GetInt32(100) == 3) { + return CloseToPowerOfTwo(r); + } return EFloat.Create( RandomEInteger(r), (EInteger)(r.GetInt32(400) - 200)); From 30823a08b56a3be8c5a729cffbf83233ab8999ce Mon Sep 17 00:00:00 2001 From: Hadrian Tang Date: Tue, 21 Jul 2020 19:13:19 +0800 Subject: [PATCH 08/16] Implement fix for #15 --- Numbers.sln | 104 ++++++---------- Numbers/Numbers.csproj | 2 +- Numbers/PeterO/Numbers/FastIntegerFixed.cs | 137 +++++++++++---------- Test/EDecimalTest.cs | 10 ++ Test/EFloatTest.cs | 10 ++ Test/EIntegerTest.cs | 6 + Test/ERationalTest.cs | 10 ++ 7 files changed, 148 insertions(+), 131 deletions(-) diff --git a/Numbers.sln b/Numbers.sln index 5b90b47..4837ae2 100644 --- a/Numbers.sln +++ b/Numbers.sln @@ -1,38 +1,14 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26430.15 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30204.135 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test.csproj", "{8FE63143-541E-448D-8337-A98D1FA51541}" - ProjectSection(ProjectDependencies) = postProject - {C6EF158C-6F4B-4280-A823-44C945469E39} = {C6EF158C-6F4B-4280-A823-44C945469E39} - EndProjectSection +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test", "Test\Test.csproj", "{8FE63143-541E-448D-8337-A98D1FA51541}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3F4A3741-A572-4B47-BEDA-24F7ADD1FBB2}" - ProjectSection(SolutionItems) = preProject - .gitattributes = .gitattributes - .gitignore = .gitignore - docs.xml = docs.xml - examples.md = examples.md - LICENSE.md = LICENSE.md - Numbers.nuspec = Numbers.nuspec - Numbers.ruleset = Numbers.ruleset - README.md = README.md - Settings.SourceAnalysis = Settings.SourceAnalysis - EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{53713F40-8C18-4478-8EA2-DD30E4C6BC38}" - ProjectSection(SolutionItems) = preProject - docs\APIDocs.md = docs\APIDocs.md - docs\PeterO.Numbers.EContext.md = docs\PeterO.Numbers.EContext.md - docs\PeterO.Numbers.EDecimal.md = docs\PeterO.Numbers.EDecimal.md - docs\PeterO.Numbers.EFloat.md = docs\PeterO.Numbers.EFloat.md - docs\PeterO.Numbers.EInteger.md = docs\PeterO.Numbers.EInteger.md - docs\PeterO.Numbers.ERational.md = docs\PeterO.Numbers.ERational.md - docs\PeterO.Numbers.ERounding.md = docs\PeterO.Numbers.ERounding.md - docs\PeterO.Numbers.ETrapException.md = docs\PeterO.Numbers.ETrapException.md - EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Numbers", "Numbers\Numbers.csproj", "{C6EF158C-6F4B-4280-A823-44C945469E39}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Numbers", "Numbers\Numbers.csproj", "{C6EF158C-6F4B-4280-A823-44C945469E39}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Numbers40", "Numbers40\Numbers40.csproj", "{D7E09F55-3156-44B0-87D9-1BABCBB398D9}" EndProject @@ -43,40 +19,40 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test40", "Test40\Test40.csproj", "{00EB31B6-A805-4EFB-A64B-9F8176B2A1CC}" EndProject Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {8FE63143-541E-448D-8337-A98D1FA51541}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8FE63143-541E-448D-8337-A98D1FA51541}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8FE63143-541E-448D-8337-A98D1FA51541}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8FE63143-541E-448D-8337-A98D1FA51541}.Release|Any CPU.Build.0 = Release|Any CPU - {C6EF158C-6F4B-4280-A823-44C945469E39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C6EF158C-6F4B-4280-A823-44C945469E39}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C6EF158C-6F4B-4280-A823-44C945469E39}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C6EF158C-6F4B-4280-A823-44C945469E39}.Release|Any CPU.Build.0 = Release|Any CPU - {D7E09F55-3156-44B0-87D9-1BABCBB398D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D7E09F55-3156-44B0-87D9-1BABCBB398D9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D7E09F55-3156-44B0-87D9-1BABCBB398D9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D7E09F55-3156-44B0-87D9-1BABCBB398D9}.Release|Any CPU.Build.0 = Release|Any CPU - {04A7B845-E447-4A46-ABB9-D195BDEDC735}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {04A7B845-E447-4A46-ABB9-D195BDEDC735}.Debug|Any CPU.Build.0 = Debug|Any CPU - {04A7B845-E447-4A46-ABB9-D195BDEDC735}.Release|Any CPU.ActiveCfg = Release|Any CPU - {04A7B845-E447-4A46-ABB9-D195BDEDC735}.Release|Any CPU.Build.0 = Release|Any CPU - {4CF0E5BA-CDE3-4DEA-B3F4-11EE544B3FB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4CF0E5BA-CDE3-4DEA-B3F4-11EE544B3FB2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4CF0E5BA-CDE3-4DEA-B3F4-11EE544B3FB2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4CF0E5BA-CDE3-4DEA-B3F4-11EE544B3FB2}.Release|Any CPU.Build.0 = Release|Any CPU - {00EB31B6-A805-4EFB-A64B-9F8176B2A1CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {00EB31B6-A805-4EFB-A64B-9F8176B2A1CC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {00EB31B6-A805-4EFB-A64B-9F8176B2A1CC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {00EB31B6-A805-4EFB-A64B-9F8176B2A1CC}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {53713F40-8C18-4478-8EA2-DD30E4C6BC38} = {3F4A3741-A572-4B47-BEDA-24F7ADD1FBB2} - EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8FE63143-541E-448D-8337-A98D1FA51541}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8FE63143-541E-448D-8337-A98D1FA51541}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8FE63143-541E-448D-8337-A98D1FA51541}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8FE63143-541E-448D-8337-A98D1FA51541}.Release|Any CPU.Build.0 = Release|Any CPU + {C6EF158C-6F4B-4280-A823-44C945469E39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C6EF158C-6F4B-4280-A823-44C945469E39}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C6EF158C-6F4B-4280-A823-44C945469E39}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C6EF158C-6F4B-4280-A823-44C945469E39}.Release|Any CPU.Build.0 = Release|Any CPU + {D7E09F55-3156-44B0-87D9-1BABCBB398D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D7E09F55-3156-44B0-87D9-1BABCBB398D9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D7E09F55-3156-44B0-87D9-1BABCBB398D9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D7E09F55-3156-44B0-87D9-1BABCBB398D9}.Release|Any CPU.Build.0 = Release|Any CPU + {04A7B845-E447-4A46-ABB9-D195BDEDC735}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {04A7B845-E447-4A46-ABB9-D195BDEDC735}.Debug|Any CPU.Build.0 = Debug|Any CPU + {04A7B845-E447-4A46-ABB9-D195BDEDC735}.Release|Any CPU.ActiveCfg = Release|Any CPU + {04A7B845-E447-4A46-ABB9-D195BDEDC735}.Release|Any CPU.Build.0 = Release|Any CPU + {4CF0E5BA-CDE3-4DEA-B3F4-11EE544B3FB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4CF0E5BA-CDE3-4DEA-B3F4-11EE544B3FB2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4CF0E5BA-CDE3-4DEA-B3F4-11EE544B3FB2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4CF0E5BA-CDE3-4DEA-B3F4-11EE544B3FB2}.Release|Any CPU.Build.0 = Release|Any CPU + {00EB31B6-A805-4EFB-A64B-9F8176B2A1CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {00EB31B6-A805-4EFB-A64B-9F8176B2A1CC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {00EB31B6-A805-4EFB-A64B-9F8176B2A1CC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {00EB31B6-A805-4EFB-A64B-9F8176B2A1CC}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {94BDE756-12C3-4E6C-9D44-C2D75EC0519A} + EndGlobalSection EndGlobal diff --git a/Numbers/Numbers.csproj b/Numbers/Numbers.csproj index d639c38..2fa31c3 100644 --- a/Numbers/Numbers.csproj +++ b/Numbers/Numbers.csproj @@ -1,4 +1,4 @@ - + netstandard1.0 diff --git a/Numbers/PeterO/Numbers/FastIntegerFixed.cs b/Numbers/PeterO/Numbers/FastIntegerFixed.cs index bbc4c44..ca5b2d7 100644 --- a/Numbers/PeterO/Numbers/FastIntegerFixed.cs +++ b/Numbers/PeterO/Numbers/FastIntegerFixed.cs @@ -9,19 +9,24 @@ namespace PeterO.Numbers { internal sealed class FastIntegerFixed : IComparable { + [Flags] + private enum IntegerMode : byte { + SmallValue = 0, + LargeValue = 2, + } private const int CacheFirst = -24; private const int CacheLast = 128; private readonly int smallValue; // if integerMode is 0 private readonly EInteger largeValue; // if integerMode is 2 - private readonly byte integerMode; + private readonly IntegerMode integerMode; public static readonly FastIntegerFixed Zero = new FastIntegerFixed( - (byte)0, + IntegerMode.SmallValue, 0, null); public static readonly FastIntegerFixed One = new FastIntegerFixed( - (byte)0, + IntegerMode.SmallValue, 1, null); @@ -64,7 +69,7 @@ internal sealed class FastIntegerFixed : IComparable { } private FastIntegerFixed( - byte integerMode, + IntegerMode integerMode, int smallValue, EInteger largeValue) { this.integerMode = integerMode; @@ -73,31 +78,31 @@ internal sealed class FastIntegerFixed : IComparable { } public override bool Equals(object obj) { - var fi = obj as FastIntegerFixed; - if (fi == null) { + if (!(obj is FastIntegerFixed fi)) { return false; } if (this.integerMode != fi.integerMode) { return false; } - if (this.integerMode == 0) { - if (this.smallValue != fi.smallValue) { - return false; - } - } else if (this.integerMode == 1) { - if (!this.largeValue.Equals(fi.largeValue)) { - return false; - } + switch (this.integerMode) { + case IntegerMode.SmallValue: + return this.smallValue == fi.smallValue; + case IntegerMode.LargeValue: + return this.largeValue.Equals(fi.smallValue); + default: + return true; } - return true; } public override int GetHashCode() { - int hash = unchecked(31 + this.integerMode); - if (this.integerMode == 0) { - hash = unchecked((hash * 31) + this.smallValue); - } else if (this.integerMode == 1) { - hash = unchecked((hash * 31) + this.largeValue.GetHashCode()); + int hash = unchecked(31 + (int)this.integerMode); + switch (this.integerMode) { + case IntegerMode.SmallValue: + hash = unchecked((hash * 31) + this.smallValue); + break; + case IntegerMode.LargeValue: + hash = unchecked((hash * 31) + this.largeValue.GetHashCode()); + break; } return hash; } @@ -111,7 +116,7 @@ internal sealed class FastIntegerFixed : IComparable { internal static FastIntegerFixed FromInt64(long longVal) { return (longVal >= Int32.MinValue && longVal <= Int32.MaxValue) ? FromInt32((int)longVal) : new FastIntegerFixed( - (byte)2, + IntegerMode.LargeValue, 0, EInteger.FromInt64(longVal)); } @@ -119,7 +124,7 @@ internal sealed class FastIntegerFixed : IComparable { internal static FastIntegerFixed FromBig(EInteger bigintVal) { return bigintVal.CanFitInInt32() ? FromInt32(bigintVal.ToInt32Unchecked()) : new - FastIntegerFixed((byte)2, 0, bigintVal); + FastIntegerFixed(IntegerMode.LargeValue, 0, bigintVal); } internal int ToInt32() { @@ -275,7 +280,7 @@ internal sealed class FastIntegerFixed : IComparable { public FastIntegerFixed Abs() { switch (this.integerMode) { - case 0: + case IntegerMode.SmallValue: if (this.smallValue == Int32.MinValue) { return FastIntegerFixed.FromInt32(Int32.MaxValue).Increment(); } else if (this.smallValue < 0) { @@ -283,9 +288,9 @@ internal sealed class FastIntegerFixed : IComparable { } else { return this; } - case 2: + case IntegerMode.LargeValue: return this.largeValue.Sign < 0 ? new - FastIntegerFixed((byte)2, 0, this.largeValue.Abs()) : + FastIntegerFixed(IntegerMode.LargeValue, 0, this.largeValue.Abs()) : this; default: throw new InvalidOperationException(); } @@ -293,23 +298,23 @@ internal sealed class FastIntegerFixed : IComparable { public FastIntegerFixed Negate() { switch (this.integerMode) { - case 0: + case IntegerMode.SmallValue: if (this.smallValue == Int32.MinValue) { return FastIntegerFixed.FromInt32(Int32.MaxValue).Increment(); } else { return FastIntegerFixed.FromInt32(-this.smallValue); } - case 2: - return new FastIntegerFixed((byte)2, 0, this.largeValue.Negate()); + case IntegerMode.LargeValue: + return new FastIntegerFixed(IntegerMode.LargeValue, 0, this.largeValue.Negate()); default: throw new InvalidOperationException(); } } public int CompareTo(EInteger evalue) { switch (this.integerMode) { - case 0: + case IntegerMode.SmallValue: return -evalue.CompareTo(this.smallValue); - case 2: + case IntegerMode.LargeValue: return this.largeValue.CompareTo(evalue); default: throw new InvalidOperationException(); } @@ -317,35 +322,37 @@ internal sealed class FastIntegerFixed : IComparable { public int CompareTo(FastInteger fint) { switch (this.integerMode) { - case 0: + case IntegerMode.SmallValue: return -fint.CompareToInt(this.smallValue); - case 2: + case IntegerMode.LargeValue: return -fint.CompareTo(this.largeValue); default: throw new InvalidOperationException(); } } public int CompareTo(FastIntegerFixed val) { - switch ((this.integerMode << 2) | val.integerMode) { - case (0 << 2) | 0: { - int vsv = val.smallValue; - return (this.smallValue == vsv) ? 0 : (this.smallValue < vsv ? -1 : - 1); - } - case (0 << 2) | 2: - return -val.largeValue.CompareTo(this.smallValue); - case (2 << 2) | 0: - case (2 << 2) | 2: + switch (this.integerMode) { + case IntegerMode.SmallValue: + switch (val.integerMode) { + case IntegerMode.SmallValue: + int vsv = val.smallValue; + return (this.smallValue == vsv) ? 0 : (this.smallValue < vsv ? -1 : + 1); + case IntegerMode.LargeValue: + return -val.largeValue.CompareTo(this.smallValue); + } + break; + case IntegerMode.LargeValue: return this.largeValue.CompareTo(val.ToEInteger()); - default: throw new InvalidOperationException(); } + throw new InvalidOperationException(); } internal FastIntegerFixed Copy() { switch (this.integerMode) { - case 0: + case IntegerMode.SmallValue: return FromInt32(this.smallValue); - case 2: + case IntegerMode.LargeValue: return FastIntegerFixed.FromBig(this.largeValue); default: throw new InvalidOperationException(); } @@ -354,9 +361,9 @@ internal sealed class FastIntegerFixed : IComparable { internal bool IsEvenNumber { get { switch (this.integerMode) { - case 0: + case IntegerMode.SmallValue: return (this.smallValue & 1) == 0; - case 2: + case IntegerMode.LargeValue: return this.largeValue.IsEven; default: throw new InvalidOperationException(); @@ -365,16 +372,16 @@ internal sealed class FastIntegerFixed : IComparable { } internal bool CanFitInInt32() { - return this.integerMode == 0 || this.largeValue.CanFitInInt32(); + return this.integerMode == IntegerMode.SmallValue || this.largeValue.CanFitInInt32(); } /// This is an internal API. /// A text string. public override string ToString() { switch (this.integerMode) { - case 0: + case IntegerMode.SmallValue: return FastInteger.IntToString(this.smallValue); - case 2: + case IntegerMode.LargeValue: return this.largeValue.ToString(); default: return String.Empty; } @@ -383,10 +390,10 @@ internal sealed class FastIntegerFixed : IComparable { internal int Sign { get { switch (this.integerMode) { - case 0: + case IntegerMode.SmallValue: return (this.smallValue == 0) ? 0 : ((this.smallValue < 0) ? -1 : 1); - case 2: + case IntegerMode.LargeValue: return this.largeValue.Sign; default: return 0; @@ -397,9 +404,9 @@ internal sealed class FastIntegerFixed : IComparable { internal bool IsValueZero { get { switch (this.integerMode) { - case 0: + case IntegerMode.SmallValue: return this.smallValue == 0; - case 2: + case IntegerMode.LargeValue: return this.largeValue.IsZero; default: return false; @@ -409,35 +416,33 @@ internal sealed class FastIntegerFixed : IComparable { internal bool CanFitInInt64() { switch (this.integerMode) { - case 0: + case IntegerMode.SmallValue: return true; - case 2: + case IntegerMode.LargeValue: return this.largeValue .CanFitInInt64(); - default: throw new InvalidOperationException(); } } internal long ToInt64() { switch (this.integerMode) { - case 0: + case IntegerMode.SmallValue: return (long)this.smallValue; - case 2: + case IntegerMode.LargeValue: return this.largeValue .ToInt64Unchecked(); - default: throw new InvalidOperationException(); } } internal int CompareToInt64(long valLong) { switch (this.integerMode) { - case 0: + case IntegerMode.SmallValue: return (valLong == this.smallValue) ? 0 : (this.smallValue < valLong ? -1 : 1); - case 2: + case IntegerMode.LargeValue: return this.largeValue.CompareTo(valLong); default: return 0; } @@ -445,10 +450,10 @@ internal sealed class FastIntegerFixed : IComparable { internal int CompareToInt(int val) { switch (this.integerMode) { - case 0: + case IntegerMode.SmallValue: return (val == this.smallValue) ? 0 : (this.smallValue < val ? -1 : 1); - case 2: + case IntegerMode.LargeValue: return this.largeValue.CompareTo((EInteger)val); default: return 0; } @@ -456,9 +461,9 @@ internal sealed class FastIntegerFixed : IComparable { internal EInteger ToEInteger() { switch (this.integerMode) { - case 0: + case IntegerMode.SmallValue: return EInteger.FromInt32(this.smallValue); - case 2: + case IntegerMode.LargeValue: return this.largeValue; default: throw new InvalidOperationException(); } diff --git a/Test/EDecimalTest.cs b/Test/EDecimalTest.cs index a2276bd..7420a10 100644 --- a/Test/EDecimalTest.cs +++ b/Test/EDecimalTest.cs @@ -1320,6 +1320,16 @@ public class EDecimalTest { } [Test] public void TestEquals() { + Assert.IsFalse(EDecimal.One.Equals(null)); + Assert.IsFalse(EDecimal.Zero.Equals(null)); + Assert.IsFalse(EDecimal.One.Equals(EDecimal.Zero)); + Assert.IsFalse(EDecimal.Zero.Equals(EDecimal.One)); + Assert.AreEqual( + EDecimal.FromString("0.009461540475412139260145553670698466186015902447450593622262751970123371581303298477485466592231565609"), + EDecimal.FromString("0.009461540475412139260145553670698466186015902447450593622262751970123371581303298477485466592231565609")); + Assert.AreNotEqual( + EDecimal.FromString("0.009461540475412139260145553670698466186015902447450593622262751970123371581303298477485466592231565609"), + EDecimal.FromString("0.001809476049361792727571247490438259768858020288404502743164967883090669271207537395819291033916115474")); var r = new RandomGenerator(); for (var i = 0; i < 500; ++i) { EDecimal bigintA = RandomObjects.RandomEDecimal(r); diff --git a/Test/EFloatTest.cs b/Test/EFloatTest.cs index b858a59..3f3e128 100644 --- a/Test/EFloatTest.cs +++ b/Test/EFloatTest.cs @@ -311,6 +311,16 @@ public class EFloatTest { } [Test] public void TestEquals() { + Assert.IsFalse(EFloat.One.Equals(null)); + Assert.IsFalse(EFloat.Zero.Equals(null)); + Assert.IsFalse(EFloat.One.Equals(EFloat.Zero)); + Assert.IsFalse(EFloat.Zero.Equals(EFloat.One)); + Assert.AreEqual( + EFloat.FromString("0.009461540475412139260145553670698466186015902447450593622262751970123371581303298477485466592231565609"), + EFloat.FromString("0.009461540475412139260145553670698466186015902447450593622262751970123371581303298477485466592231565609")); + Assert.AreNotEqual( + EFloat.FromString("0.009461540475412139260145553670698466186015902447450593622262751970123371581303298477485466592231565609"), + EFloat.FromString("0.001809476049361792727571247490438259768858020288404502743164967883090669271207537395819291033916115474")); var r = new RandomGenerator(); for (var i = 0; i < 500; ++i) { EFloat bigintA = RandomObjects.RandomEFloat(r); diff --git a/Test/EIntegerTest.cs b/Test/EIntegerTest.cs index db3cb2c..d67854a 100644 --- a/Test/EIntegerTest.cs +++ b/Test/EIntegerTest.cs @@ -1117,6 +1117,12 @@ public class EIntegerTest { Assert.IsFalse(EInteger.Zero.Equals(null)); Assert.IsFalse(EInteger.One.Equals(EInteger.Zero)); Assert.IsFalse(EInteger.Zero.Equals(EInteger.One)); + Assert.AreEqual( + EInteger.FromString("9461540475412139260145553670698466186015902447450593622262751970123371581303298477485466592231565609"), + EInteger.FromString("9461540475412139260145553670698466186015902447450593622262751970123371581303298477485466592231565609")); + Assert.AreNotEqual( + EInteger.FromString("9461540475412139260145553670698466186015902447450593622262751970123371581303298477485466592231565609"), + EInteger.FromString("1809476049361792727571247490438259768858020288404502743164967883090669271207537395819291033916115474")); TestCommon.AssertEqualsHashCode( EInteger.Zero, EInteger.FromString("-0")); diff --git a/Test/ERationalTest.cs b/Test/ERationalTest.cs index 4cd23b4..c62e28f 100644 --- a/Test/ERationalTest.cs +++ b/Test/ERationalTest.cs @@ -419,6 +419,16 @@ public class ERationalTest { } [Test] public void TestEquals() { + Assert.IsFalse(ERational.One.Equals(null)); + Assert.IsFalse(ERational.Zero.Equals(null)); + Assert.IsFalse(ERational.One.Equals(ERational.Zero)); + Assert.IsFalse(ERational.Zero.Equals(ERational.One)); + Assert.AreEqual( + ERational.FromString("12/24"), + ERational.FromString("12/24")); + Assert.AreNotEqual( + ERational.FromString("24/48"), + ERational.FromString("12/24")); ERational era = ERational.FromString("0/3920"); ERational erb = ERational.FromString("0/3920"); TestCommon.CompareTestEqualAndConsistent( From 4e21e1c242775eca60e58cfe5bff814b7222397e Mon Sep 17 00:00:00 2001 From: Hadrian Tang Date: Tue, 21 Jul 2020 19:15:54 +0800 Subject: [PATCH 09/16] Revert Visual Studio auto-changes --- Numbers.sln | 104 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 64 insertions(+), 40 deletions(-) diff --git a/Numbers.sln b/Numbers.sln index 4837ae2..5b90b47 100644 --- a/Numbers.sln +++ b/Numbers.sln @@ -1,14 +1,38 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30204.135 +# Visual Studio 15 +VisualStudioVersion = 15.0.26430.15 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test", "Test\Test.csproj", "{8FE63143-541E-448D-8337-A98D1FA51541}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test.csproj", "{8FE63143-541E-448D-8337-A98D1FA51541}" + ProjectSection(ProjectDependencies) = postProject + {C6EF158C-6F4B-4280-A823-44C945469E39} = {C6EF158C-6F4B-4280-A823-44C945469E39} + EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3F4A3741-A572-4B47-BEDA-24F7ADD1FBB2}" + ProjectSection(SolutionItems) = preProject + .gitattributes = .gitattributes + .gitignore = .gitignore + docs.xml = docs.xml + examples.md = examples.md + LICENSE.md = LICENSE.md + Numbers.nuspec = Numbers.nuspec + Numbers.ruleset = Numbers.ruleset + README.md = README.md + Settings.SourceAnalysis = Settings.SourceAnalysis + EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{53713F40-8C18-4478-8EA2-DD30E4C6BC38}" + ProjectSection(SolutionItems) = preProject + docs\APIDocs.md = docs\APIDocs.md + docs\PeterO.Numbers.EContext.md = docs\PeterO.Numbers.EContext.md + docs\PeterO.Numbers.EDecimal.md = docs\PeterO.Numbers.EDecimal.md + docs\PeterO.Numbers.EFloat.md = docs\PeterO.Numbers.EFloat.md + docs\PeterO.Numbers.EInteger.md = docs\PeterO.Numbers.EInteger.md + docs\PeterO.Numbers.ERational.md = docs\PeterO.Numbers.ERational.md + docs\PeterO.Numbers.ERounding.md = docs\PeterO.Numbers.ERounding.md + docs\PeterO.Numbers.ETrapException.md = docs\PeterO.Numbers.ETrapException.md + EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Numbers", "Numbers\Numbers.csproj", "{C6EF158C-6F4B-4280-A823-44C945469E39}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Numbers", "Numbers\Numbers.csproj", "{C6EF158C-6F4B-4280-A823-44C945469E39}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Numbers40", "Numbers40\Numbers40.csproj", "{D7E09F55-3156-44B0-87D9-1BABCBB398D9}" EndProject @@ -19,40 +43,40 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test40", "Test40\Test40.csproj", "{00EB31B6-A805-4EFB-A64B-9F8176B2A1CC}" EndProject Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {8FE63143-541E-448D-8337-A98D1FA51541}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8FE63143-541E-448D-8337-A98D1FA51541}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8FE63143-541E-448D-8337-A98D1FA51541}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8FE63143-541E-448D-8337-A98D1FA51541}.Release|Any CPU.Build.0 = Release|Any CPU - {C6EF158C-6F4B-4280-A823-44C945469E39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C6EF158C-6F4B-4280-A823-44C945469E39}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C6EF158C-6F4B-4280-A823-44C945469E39}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C6EF158C-6F4B-4280-A823-44C945469E39}.Release|Any CPU.Build.0 = Release|Any CPU - {D7E09F55-3156-44B0-87D9-1BABCBB398D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D7E09F55-3156-44B0-87D9-1BABCBB398D9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D7E09F55-3156-44B0-87D9-1BABCBB398D9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D7E09F55-3156-44B0-87D9-1BABCBB398D9}.Release|Any CPU.Build.0 = Release|Any CPU - {04A7B845-E447-4A46-ABB9-D195BDEDC735}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {04A7B845-E447-4A46-ABB9-D195BDEDC735}.Debug|Any CPU.Build.0 = Debug|Any CPU - {04A7B845-E447-4A46-ABB9-D195BDEDC735}.Release|Any CPU.ActiveCfg = Release|Any CPU - {04A7B845-E447-4A46-ABB9-D195BDEDC735}.Release|Any CPU.Build.0 = Release|Any CPU - {4CF0E5BA-CDE3-4DEA-B3F4-11EE544B3FB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4CF0E5BA-CDE3-4DEA-B3F4-11EE544B3FB2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4CF0E5BA-CDE3-4DEA-B3F4-11EE544B3FB2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4CF0E5BA-CDE3-4DEA-B3F4-11EE544B3FB2}.Release|Any CPU.Build.0 = Release|Any CPU - {00EB31B6-A805-4EFB-A64B-9F8176B2A1CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {00EB31B6-A805-4EFB-A64B-9F8176B2A1CC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {00EB31B6-A805-4EFB-A64B-9F8176B2A1CC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {00EB31B6-A805-4EFB-A64B-9F8176B2A1CC}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {94BDE756-12C3-4E6C-9D44-C2D75EC0519A} - EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8FE63143-541E-448D-8337-A98D1FA51541}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8FE63143-541E-448D-8337-A98D1FA51541}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8FE63143-541E-448D-8337-A98D1FA51541}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8FE63143-541E-448D-8337-A98D1FA51541}.Release|Any CPU.Build.0 = Release|Any CPU + {C6EF158C-6F4B-4280-A823-44C945469E39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C6EF158C-6F4B-4280-A823-44C945469E39}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C6EF158C-6F4B-4280-A823-44C945469E39}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C6EF158C-6F4B-4280-A823-44C945469E39}.Release|Any CPU.Build.0 = Release|Any CPU + {D7E09F55-3156-44B0-87D9-1BABCBB398D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D7E09F55-3156-44B0-87D9-1BABCBB398D9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D7E09F55-3156-44B0-87D9-1BABCBB398D9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D7E09F55-3156-44B0-87D9-1BABCBB398D9}.Release|Any CPU.Build.0 = Release|Any CPU + {04A7B845-E447-4A46-ABB9-D195BDEDC735}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {04A7B845-E447-4A46-ABB9-D195BDEDC735}.Debug|Any CPU.Build.0 = Debug|Any CPU + {04A7B845-E447-4A46-ABB9-D195BDEDC735}.Release|Any CPU.ActiveCfg = Release|Any CPU + {04A7B845-E447-4A46-ABB9-D195BDEDC735}.Release|Any CPU.Build.0 = Release|Any CPU + {4CF0E5BA-CDE3-4DEA-B3F4-11EE544B3FB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4CF0E5BA-CDE3-4DEA-B3F4-11EE544B3FB2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4CF0E5BA-CDE3-4DEA-B3F4-11EE544B3FB2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4CF0E5BA-CDE3-4DEA-B3F4-11EE544B3FB2}.Release|Any CPU.Build.0 = Release|Any CPU + {00EB31B6-A805-4EFB-A64B-9F8176B2A1CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {00EB31B6-A805-4EFB-A64B-9F8176B2A1CC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {00EB31B6-A805-4EFB-A64B-9F8176B2A1CC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {00EB31B6-A805-4EFB-A64B-9F8176B2A1CC}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {53713F40-8C18-4478-8EA2-DD30E4C6BC38} = {3F4A3741-A572-4B47-BEDA-24F7ADD1FBB2} + EndGlobalSection EndGlobal From fbb9f7d6bf1a138a3b4a32d0111d96365efea0ed Mon Sep 17 00:00:00 2001 From: Hadrian Tang Date: Tue, 21 Jul 2020 19:21:36 +0800 Subject: [PATCH 10/16] Quickfix --- Numbers/PeterO/Numbers/FastIntegerFixed.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Numbers/PeterO/Numbers/FastIntegerFixed.cs b/Numbers/PeterO/Numbers/FastIntegerFixed.cs index ca5b2d7..5076fad 100644 --- a/Numbers/PeterO/Numbers/FastIntegerFixed.cs +++ b/Numbers/PeterO/Numbers/FastIntegerFixed.cs @@ -88,7 +88,7 @@ private enum IntegerMode : byte { case IntegerMode.SmallValue: return this.smallValue == fi.smallValue; case IntegerMode.LargeValue: - return this.largeValue.Equals(fi.smallValue); + return this.largeValue.Equals(fi.largeValue); default: return true; } From 62d19483774b5684b9540250e5e0cacfe7ea3c9f Mon Sep 17 00:00:00 2001 From: Peter O Date: Tue, 21 Jul 2020 10:31:35 -0400 Subject: [PATCH 11/16] Edit implementation of Ln for large inputs --- Numbers/PeterO/Numbers/RadixMath.cs | 55 ++++++++++++++++++- Numbers/docs.xml | 38 ++++++++----- Numbers20/Numbers20.csproj | 2 +- Test/EFloatTest.cs | 85 ++++++++++++++++++++++++++--- Test/RandomObjects.cs | 16 +++--- Test20/Test20.csproj | 2 +- Test40/Test40.csproj | 2 +- docs/PeterO.Numbers.EDecimal.md | 2 +- docs/PeterO.Numbers.EInteger.md | 53 ++++++++++++++++++ 9 files changed, 222 insertions(+), 33 deletions(-) diff --git a/Numbers/PeterO/Numbers/RadixMath.cs b/Numbers/PeterO/Numbers/RadixMath.cs index 73b13cf..f2b307e 100644 --- a/Numbers/PeterO/Numbers/RadixMath.cs +++ b/Numbers/PeterO/Numbers/RadixMath.cs @@ -1274,8 +1274,61 @@ 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) { + if (this.CompareTo(thisValue, hundred) >= 0 && + this.helper.GetRadix() == 2) { + 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 (this.CompareTo(reduced, one) >= 0) { + throw new InvalidOperationException( + "thisValue = " + thisValue + "\n" + + "fexp = " + fexp + "\n" + + "fbits = " + fbits + "\n" + + "adjval = " + adjval + "\n" + + "reduced = " + reduced + "\n"); + } + DebugUtility.Log("thisValue = " + thisValue + "\n" + + "fexp = " + fexp + "\n" + + "fbits = " + fbits + "\n" + + "adjval = " + adjval + "\n" + + "reduced = " + reduced + "\n"); + reduced = this.Ln(reduced, ctxdiv); + thisValue = this.Add(this.Multiply(this.Ln(two, ctxdiv), addval, + null), + reduced, + ctxCopy); + } else if (this.CompareTo(thisValue, two) >= 0) { // 2 or greater var roots = new FastInteger(0); FastInteger error; diff --git a/Numbers/docs.xml b/Numbers/docs.xml index b25ff12..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,8 +10631,8 @@ 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. + 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. @@ -10642,13 +10642,10 @@ -Initializes an arbitrary-precision integer from a portion of an array - of bytes. - A portion of a byte array consisting of the two's-complement - form (see - "Forms of numbers" ) of - the arbitrary-precision integer to create. The byte array portion has to be - encoded using the following rules: + + 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. @@ -10668,12 +10665,27 @@ 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 "length" is 0. + 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 b858a59..c1391a4 100644 --- a/Test/EFloatTest.cs +++ b/Test/EFloatTest.cs @@ -909,7 +909,71 @@ public class EFloatTest { "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); +Assert.AreEqual(efb, efa); +} +[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); + TestCommon.CompareTestEqual(efb, efa, str); +} [Test] public void TestExpM1() { @@ -917,38 +981,45 @@ public class EFloatTest { EFloat efa = EFloat.Create(1007123499737607L, -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); 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); 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); 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); 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); EFloat efb = EFloat.Create(-740936470921891L, -85); - TestCommon.CompareTestEqual(efb, efa); + string str = OutputEF(efb) + "\n" + OutputEF(efa); + TestCommon.CompareTestEqual(efb, efa, str); } + } public static string DebugStringLog1P( diff --git a/Test/RandomObjects.cs b/Test/RandomObjects.cs index c4f9424..9e55c06 100644 --- a/Test/RandomObjects.cs +++ b/Test/RandomObjects.cs @@ -390,18 +390,18 @@ public static class RandomObjects { throw new ArgumentNullException(nameof(rg)); } int pwr = (rg.GetInt32(100) < 80) ? IntInRange(rg, -20, 20) : -IntInRange(rg, -300, 300); + IntInRange(rg, -300, 300); int pwr2 = pwr - (rg.GetInt32(100) < 80 ? IntInRange(rg, 51, 61) : -IntInRange(rg, 2, 300)); + IntInRange(rg, 2, 300)); EFloat ef = null; - ef = (rg.GetInt32(2) == 0) ? (EFloat.Create(1, - pwr).Add(EFloat.Create(1, pwr2))) : (EFloat.Create(1, - pwr).Subtract(EFloat.Create(1, pwr2))); + ef = (rg.GetInt32(2) == 0) ? EFloat.Create(1, + pwr).Add(EFloat.Create(1, pwr2)) : EFloat.Create(1, + pwr).Subtract(EFloat.Create(1, pwr2)); if (rg.GetInt32(10) == 0) { pwr2 = pwr - (rg.GetInt32(100) < 80 ? IntInRange(rg, 51, 61) : -IntInRange(rg, 2, 300)); - ef = (rg.GetInt32(2) == 0) ? (ef.Add(EFloat.Create(1, pwr2))) : -(ef.Subtract(EFloat.Create(1, pwr2))); + IntInRange(rg, 2, 300)); + ef = (rg.GetInt32(2) == 0) ? ef.Add(EFloat.Create(1, pwr2)) : + ef.Subtract(EFloat.Create(1, pwr2)); } return ef; } 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/Test40/Test40.csproj b/Test40/Test40.csproj index 186b91a..1729e68 100644 --- a/Test40/Test40.csproj +++ b/Test40/Test40.csproj @@ -1 +1 @@ -DebugAnyCPU{00EB31B6-A805-4EFB-A64B-9F8176B2A1CC}ExeTest40rules.rulesettruefullfalsebin\DebugDEBUG;NET40prompt4truerules.rulesettruebin\ReleasepromptNET404truerules.ruleset3.12.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{D7E09F55-3156-44B0-87D9-1BABCBB398D9}Test40v4.0win +DebugAnyCPU{00EB31B6-A805-4EFB-A64B-9F8176B2A1CC}ExeTest40rules.rulesettruefullfalsebin\DebugDEBUG;NET40prompt4truerules.rulesettruebin\ReleasepromptNET404truerules.ruleset3.12.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{D7E09F55-3156-44B0-87D9-1BABCBB398D9}Test40v4.0win 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 From 4de37d61a4afc65e53f44a724c291ab5ce6a4a04 Mon Sep 17 00:00:00 2001 From: Peter O Date: Wed, 22 Jul 2020 20:46:54 -0400 Subject: [PATCH 12/16] fix Log() a bit --- Numbers/PeterO/Numbers/RadixMath.cs | 33 +++++++++++++++++------------ Test/EFloatTest.cs | 27 +++++++++++++++-------- Test/EIntegerTest.cs | 13 +++++++++--- 3 files changed, 48 insertions(+), 25 deletions(-) diff --git a/Numbers/PeterO/Numbers/RadixMath.cs b/Numbers/PeterO/Numbers/RadixMath.cs index dbe3ce4..060d6c1 100644 --- a/Numbers/PeterO/Numbers/RadixMath.cs +++ b/Numbers/PeterO/Numbers/RadixMath.cs @@ -1274,17 +1274,21 @@ internal class RadixMath : IRadixMath { } } else { // Greater than 1 - T hundred = this.helper.ValueOf(100); + // T hundred = this.helper.ValueOf(100); T two = this.helper.ValueOf(2); - if (this.CompareTo(thisValue, hundred) >= 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); + this.helper.ValueOf(2), + EContext.Unlimited); FastIntegerFixed fmant = this.helper.GetMantissaFastInt(thisValue); EInteger fexp = -this.helper.GetExponentFastInt(thisValue).ToEInteger(); + this.helper.GetExponentFastInt(thisValue).ToEInteger(); EInteger fbits = -fmant.ToEInteger().GetUnsignedBitLengthAsEInteger(); + fmant.ToEInteger().GetUnsignedBitLengthAsEInteger(); EInteger adjval = EInteger.One; adjval = fbits.Negate(); // fexp.Subtract(fbits.Add(fexp)); EInteger adjbits = EInteger.Zero; @@ -1303,13 +1307,14 @@ internal class RadixMath : IRadixMath { T addval = adjbits.Sign < 0 ? this.helper.CreateNewWithFlags( adjbits.Abs(), EInteger.Zero, - BigNumberFlags.FlagNegative) : this.helper.CreateNewWithFlags( + 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( @@ -1317,14 +1322,16 @@ internal class RadixMath : IRadixMath { "fexp = " + fexp + "\n" + "fbits = " + fbits + "\n" + "adjval = " + adjval + "\n" + "reduced = " + reduced + "\n"); } - DebugUtility.Log("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.Add(this.Multiply(this.Ln(two, ctxdiv), addval, - null), - reduced, - ctxCopy); + 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); diff --git a/Test/EFloatTest.cs b/Test/EFloatTest.cs index 31ddc80..8cc9dca 100644 --- a/Test/EFloatTest.cs +++ b/Test/EFloatTest.cs @@ -317,15 +317,22 @@ public class EFloatTest { Assert.IsFalse(EFloat.Zero.Equals(EFloat.One)); { object objectTemp = + EFloat.FromString("0.009461540475412139260145553670698466186015902447450593622262751970123371581303298477485466592231565609"); object objectTemp2 = + EFloat.FromString("0.009461540475412139260145553670698466186015902447450593622262751970123371581303298477485466592231565609"); Assert.AreEqual(objectTemp, objectTemp2); } - Assert.AreNotEqual( - EFloat.FromString("0.009461540475412139260145553670698466186015902447450593622262751970123371581303298477485466592231565609"), + { + object objectTemp = + + EFloat.FromString("0.009461540475412139260145553670698466186015902447450593622262751970123371581303298477485466592231565609"); + object objectTemp2 = - EFloat.FromString("0.001809476049361792727571247490438259768858020288404502743164967883090669271207537395819291033916115474")); + EFloat.FromString("0.001809476049361792727571247490438259768858020288404502743164967883090669271207537395819291033916115474"); + Assert.AreNotEqual(objectTemp, objectTemp2); + } var r = new RandomGenerator(); for (var i = 0; i < 500; ++i) { EFloat bigintA = RandomObjects.RandomEFloat(r); @@ -963,15 +970,17 @@ public class EFloatTest { } [Test] public void TestLogExpSpecificF() { -EFloat efa = EFloat.Create(7894203448763243L, 790).Log(EContext.Binary64); -EFloat efb = EFloat.Create(642324992820697L, -40); -Assert.AreEqual(efb, efa); + 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); + string str = OutputEF(efb) + "\n" + OutputEF(efa) + "\nInput: " + + OutputEF(EFloat.Create(4939846268124649L, -48)) ; TestCommon.CompareTestEqual(efb, efa, str); } @@ -2099,8 +2108,8 @@ public class EFloatTest { EInteger emant = efa.Mantissa; int mantBits = emant.GetUnsignedBitLengthAsEInteger().ToInt32Checked(); if (mantBits > bitCount) { - throw new InvalidOperationException("Too many bits; expected double- -or single-sized significand"); + throw new InvalidOperationException("Too many bits; expected double-" + +"\u0020or single-sized significand"); } bool fullPrecision = mantBits == bitCount; bool isSubnormal = EFloats.IsSubnormal(efa, diff --git a/Test/EIntegerTest.cs b/Test/EIntegerTest.cs index 75464ee..7d99001 100644 --- a/Test/EIntegerTest.cs +++ b/Test/EIntegerTest.cs @@ -1119,15 +1119,22 @@ public class EIntegerTest { Assert.IsFalse(EInteger.Zero.Equals(EInteger.One)); { object objectTemp = + EInteger.FromString("9461540475412139260145553670698466186015902447450593622262751970123371581303298477485466592231565609"); object objectTemp2 = + EInteger.FromString("9461540475412139260145553670698466186015902447450593622262751970123371581303298477485466592231565609"); Assert.AreEqual(objectTemp, objectTemp2); } - Assert.AreNotEqual( - EInteger.FromString("9461540475412139260145553670698466186015902447450593622262751970123371581303298477485466592231565609"), + { + object objectTemp = - EInteger.FromString("1809476049361792727571247490438259768858020288404502743164967883090669271207537395819291033916115474")); + EInteger.FromString("9461540475412139260145553670698466186015902447450593622262751970123371581303298477485466592231565609"); + object objectTemp2 = + + EInteger.FromString("1809476049361792727571247490438259768858020288404502743164967883090669271207537395819291033916115474"); + Assert.AreNotEqual(objectTemp, objectTemp2); + } TestCommon.AssertEqualsHashCode( EInteger.Zero, EInteger.FromString("-0")); From b8ba8cd99f9c5e568a4fa66b0a268256bb6d1894 Mon Sep 17 00:00:00 2001 From: Peter O Date: Thu, 23 Jul 2020 21:26:00 -0400 Subject: [PATCH 13/16] Minor code edits --- Numbers/PeterO/Numbers/RadixMath.cs | 385 ++++++++++++++-------------- Test/EFloatTest.cs | 130 +++++----- Test/EIntegerTest.cs | 126 +++++---- 3 files changed, 321 insertions(+), 320 deletions(-) diff --git a/Numbers/PeterO/Numbers/RadixMath.cs b/Numbers/PeterO/Numbers/RadixMath.cs index 060d6c1..b15afc2 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 && @@ -1280,43 +1280,43 @@ internal class RadixMath : IRadixMath { // " hundredcmp=" + this.CompareTo(thisValue, hundred) + // " twocmp=" + this.CompareTo(thisValue, two)); if (this.CompareTo(thisValue, two) > 0 && - this.helper.GetRadix() == 2) { + this.helper.GetRadix() == 2) { T half = this.Divide(this.helper.ValueOf(1), - this.helper.ValueOf(2), - EContext.Unlimited); + this.helper.ValueOf(2), + EContext.Unlimited); FastIntegerFixed fmant = this.helper.GetMantissaFastInt(thisValue); EInteger fexp = - this.helper.GetExponentFastInt(thisValue).ToEInteger(); + this.helper.GetExponentFastInt(thisValue).ToEInteger(); EInteger fbits = - fmant.ToEInteger().GetUnsignedBitLengthAsEInteger(); + 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); + 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); + 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); + 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) { + this.CompareTo(reduced, half) < 0) { throw new InvalidOperationException( "thisValue = " + thisValue + "\n" + "fexp = " + fexp + "\n" + "fbits = " + fbits + "\n" + @@ -1328,10 +1328,10 @@ internal class RadixMath : IRadixMath { // "adjval = " + adjval + "\n" + "reduced = " + reduced + "\n"); reduced = this.Ln(reduced, ctxdiv); thisValue = this.MultiplyAndAdd( - this.Ln(two, ctxdiv), - addval, - reduced, - ctxCopy); + this.Ln(two, ctxdiv), + addval, + reduced, + ctxCopy); } else if (this.CompareTo(thisValue, two) >= 0) { // 2 or greater var roots = new FastInteger(0); @@ -1339,8 +1339,8 @@ internal class RadixMath : IRadixMath { 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); @@ -1353,7 +1353,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) ? @@ -2138,7 +2138,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)) ? @@ -2228,9 +2228,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(); @@ -3165,20 +3165,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); } @@ -3199,14 +3198,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); } @@ -3402,11 +3400,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( @@ -3419,15 +3417,14 @@ 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 @@ -3442,9 +3439,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) { @@ -3459,8 +3456,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 @@ -3468,15 +3465,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 @@ -3587,7 +3584,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 @@ -3706,7 +3703,7 @@ internal class RadixMath : IRadixMath { op2Exponent, this.helper); // DebugUtility.Log("op1m="+op1Mantissa+ - // " op2m="+op2Mantissa); + // " op2m="+op2Mantissa); if (op2Mantissa == null) { return this.SignalInvalidWithMessage( ctx, @@ -3723,9 +3720,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 : @@ -3909,7 +3906,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( @@ -4051,13 +4048,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; @@ -4084,13 +4081,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; @@ -4117,9 +4114,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); @@ -4148,29 +4145,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 @@ -4411,9 +4408,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; @@ -4458,7 +4455,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; } @@ -4482,9 +4479,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; @@ -4523,7 +4520,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); @@ -4897,8 +4894,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) @@ -5658,7 +5655,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 @@ -5771,57 +5768,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); @@ -6102,8 +6101,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(); @@ -6395,7 +6394,7 @@ internal class RadixMath : IRadixMath { return bi; } return this.helper.MultiplyByRadixPower(bi, - new FastInteger(radixPowerInt)); + new FastInteger(radixPowerInt)); } private EInteger TryMultiplyByRadixPower( diff --git a/Test/EFloatTest.cs b/Test/EFloatTest.cs index 8cc9dca..14a024a 100644 --- a/Test/EFloatTest.cs +++ b/Test/EFloatTest.cs @@ -924,106 +924,110 @@ 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] + [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] + 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] + 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] + 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] + 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] + 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] + 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: " + + 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); -} + 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); 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); 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); 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); 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); 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); string str = OutputEF(efb) + "\n" + OutputEF(efa); TestCommon.CompareTestEqual(efb, efa, str); @@ -1034,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)); @@ -2109,7 +2113,7 @@ public class EFloatTest { int mantBits = emant.GetUnsignedBitLengthAsEInteger().ToInt32Checked(); if (mantBits > bitCount) { throw new InvalidOperationException("Too many bits; expected double-" + -"\u0020or single-sized significand"); + "\u0020or single-sized significand"); } bool fullPrecision = mantBits == bitCount; bool isSubnormal = EFloats.IsSubnormal(efa, @@ -2870,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 7d99001..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) { @@ -1296,10 +1296,10 @@ public class EIntegerTest { } public static bool TestEIntegerFromBytes(byte[] bytes, bool littleEndian) { - if (bytes == null) { - throw new ArgumentNullException(nameof(bytes)); - } - return TestEIntegerFromBytes(bytes, 0, bytes.Length, littleEndian); + if (bytes == null) { + throw new ArgumentNullException(nameof(bytes)); + } + return TestEIntegerFromBytes(bytes, 0, bytes.Length, littleEndian); } public static bool TestEIntegerFromBytes( @@ -1316,18 +1316,16 @@ public class EIntegerTest { if (littleEndian) { if (!(length == 1 || ( !(bytes[offset + length - 1] == 0x00 && ((int)bytes[offset + -length - - 2] & 0x80) == 0) && !(bytes[offset + length - 1] == -(byte)0xff && + length - 2] & 0x80) == 0) && !(bytes[offset + length - 1] == + (byte)0xff && ((int)bytes[offset + length - 2] & 0x80) != 0)))) { return false; } } else { if (!(length == 1 || ( !(bytes[offset] == 0x00 && ((int)bytes[offset + 1] & 0x80) == -0) && - !(bytes[offset] == (byte)0xff && ((int)bytes[offset + 1] & -0x80) != 0)))) { + 0) && !(bytes[offset] == (byte)0xff && ((int)bytes[offset + 1] & + 0x80) != 0)))) { return false; } } @@ -1335,8 +1333,8 @@ public class EIntegerTest { negative = (!littleEndian) ? ((bytes[offset] & 0x80) != 0) : ((bytes[offset + length - 1] & 0x80) != 0); EInteger ei = (offset == 0 && length == bytes.Length) ? - EInteger.FromBytes(bytes, littleEndian) : - EInteger.FromBytes(bytes, offset, length, littleEndian); + 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); @@ -2123,62 +2121,62 @@ public class EIntegerTest { } } - [Test] - public void TestGcdSpecific1() { - EInteger eia = + [Test] + public void TestGcdSpecific1() { + EInteger eia = EInteger.FromString("31087445093332925259488531187214798679962746631365434956607825050983640030004626432697"); - EInteger eib = + EInteger eib = EInteger.FromString("634110413245973045752985332739706355633747812352917054306813756224650904"); - EInteger gcd = EInteger.FromString("1"); - TestGcdPair(eia, eib, gcd); - } + EInteger gcd = EInteger.FromString("1"); + TestGcdPair(eia, eib, gcd); + } - [Test] - public void TestGcdSpecific2() { - EInteger eia = + [Test] + public void TestGcdSpecific2() { + EInteger eia = EInteger.FromString("34919464185156438130737093950000449414901433260046574365653671833127498045928977578356713"); - EInteger eib = + EInteger eib = EInteger.FromString("164193664625099565521863251759922447177022769597753704347721217067439342602815077739234"); - EInteger gcd = EInteger.FromString("1"); - TestGcdPair(eia, eib, gcd); - } - [Test] - public void TestGcdSpecific3() { - EInteger eia = + EInteger gcd = EInteger.FromString("1"); + TestGcdPair(eia, eib, gcd); + } + [Test] + public void TestGcdSpecific3() { + EInteger eia = EInteger.FromString("103862788645466657156274316837043801135780275578563880187476945864288161266"); - EInteger eib = + EInteger eib = EInteger.FromString("49380347741774569630130462581871110923545066914152503189431047757"); - EInteger gcd = EInteger.FromString("1"); - TestGcdPair(eia, eib, gcd); - } - [Test] - public void TestGcdSpecific6() { - EInteger eia = + EInteger gcd = EInteger.FromString("1"); + TestGcdPair(eia, eib, gcd); + } + [Test] + public void TestGcdSpecific6() { + EInteger eia = EInteger.FromString("4478588462902174856284550822841587751257736243593417026536878393910594570150960"); - EInteger eib = + EInteger eib = EInteger.FromString("200436597645961750509884674543137682538095599306199896499547606239076266894278634228"); - EInteger gcd = EInteger.FromString("4"); - TestGcdPair(eia, eib, gcd); - } - [Test] - public void TestGcdSpecific4() { - EInteger eia = + EInteger gcd = EInteger.FromString("4"); + TestGcdPair(eia, eib, gcd); + } + [Test] + public void TestGcdSpecific4() { + EInteger eia = EInteger.FromString("479324527105721205395276387652685206399828597662080440776635747462472972671572622295"); - EInteger eib = + EInteger eib = EInteger.FromString("838212340549242323846978901107367041041509191230401720028242035196388222327176688904324510590144"); - EInteger gcd = EInteger.FromString("11"); - TestGcdPair(eia, eib, gcd); - } + EInteger gcd = EInteger.FromString("11"); + TestGcdPair(eia, eib, gcd); + } [Test] public void TestGetBits() { @@ -2813,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] @@ -3239,8 +3237,8 @@ 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) { EInteger bigintA = RandomManageableEInteger(r); @@ -3282,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 From e4cf19b22e5af783d2b661aba4524ceab7cd8d17 Mon Sep 17 00:00:00 2001 From: Peter O Date: Fri, 24 Jul 2020 18:11:06 -0400 Subject: [PATCH 14/16] add fast case for EFloat Log --- Numbers/PeterO/Numbers/RadixMath.cs | 141 +++++++++++++++++++++++++++- 1 file changed, 139 insertions(+), 2 deletions(-) diff --git a/Numbers/PeterO/Numbers/RadixMath.cs b/Numbers/PeterO/Numbers/RadixMath.cs index b15afc2..0626a98 100644 --- a/Numbers/PeterO/Numbers/RadixMath.cs +++ b/Numbers/PeterO/Numbers/RadixMath.cs @@ -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,23 @@ 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) ? @@ -3417,8 +3555,7 @@ internal class RadixMath : IRadixMath { EContext ctx, int expcmp, bool roundToOperandPrecision) { - /* #if DEBUG - (!(op1Mantissa.Sign >= 0)) { + /* #if DEBUG (!(op1Mantissa.Sign >= 0)) { throw new ArgumentException("doesn't satisfy op1Mantissa.Sign >= 0"); } if (!(op2Mantissa.Sign >= 0)) { From d23aec88e5e9c40d34f73fedeae3dbb0e94770e4 Mon Sep 17 00:00:00 2001 From: Peter O Date: Tue, 28 Jul 2020 22:05:58 -0400 Subject: [PATCH 15/16] Minor code edits; etc. --- Numbers/PeterO/Numbers/RadixMath.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Numbers/PeterO/Numbers/RadixMath.cs b/Numbers/PeterO/Numbers/RadixMath.cs index 0626a98..caee440 100644 --- a/Numbers/PeterO/Numbers/RadixMath.cs +++ b/Numbers/PeterO/Numbers/RadixMath.cs @@ -1324,9 +1324,8 @@ internal class RadixMath : IRadixMath { } 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 (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); From 5c5676ccf1807dff075fa9d7b2a7d19c18f19b00 Mon Sep 17 00:00:00 2001 From: Peter O Date: Fri, 31 Jul 2020 04:08:09 -0400 Subject: [PATCH 16/16] Address exp's accuracy issues --- Numbers/PeterO/Numbers/RadixMath.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Numbers/PeterO/Numbers/RadixMath.cs b/Numbers/PeterO/Numbers/RadixMath.cs index caee440..ab305d0 100644 --- a/Numbers/PeterO/Numbers/RadixMath.cs +++ b/Numbers/PeterO/Numbers/RadixMath.cs @@ -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);