├── .editorconfig ├── .gitattributes ├── .github └── workflows │ └── Test.yml ├── .gitignore ├── History.md ├── LICENSE.md ├── Numbers.nuspec ├── Numbers.sln ├── Numbers ├── Numbers.csproj ├── PeterO.snk ├── PeterO │ ├── DebugUtility.cs │ └── Numbers │ │ ├── BigNumberFlags.cs │ │ ├── BitShiftAccumulator.cs │ │ ├── DigitShiftAccumulator.cs │ │ ├── EContext.cs │ │ ├── EDecimal.cs │ │ ├── EDecimalByteArrayString.cs │ │ ├── EDecimalCharArrayString.cs │ │ ├── EDecimalExtra.cs │ │ ├── EDecimalTextString.cs │ │ ├── EDecimals.cs │ │ ├── EFloat.cs │ │ ├── EFloatByteArrayString.cs │ │ ├── EFloatCharArrayString.cs │ │ ├── EFloatExtra.cs │ │ ├── EFloatTextString.cs │ │ ├── EFloats.cs │ │ ├── EInteger.cs │ │ ├── EIntegerByteArrayString.cs │ │ ├── EIntegerCharArrayString.cs │ │ ├── EIntegerExtra.cs │ │ ├── EIntegerTextString.cs │ │ ├── ERational.cs │ │ ├── ERationalByteArrayString.cs │ │ ├── ERationalCharArrayString.cs │ │ ├── ERationalExtra.cs │ │ ├── ERationalTextString.cs │ │ ├── ERounding.cs │ │ ├── ETrapException.cs │ │ ├── ExtendedOrSimpleRadixMath.cs │ │ ├── Extras.cs │ │ ├── FastInteger.cs │ │ ├── FastIntegerFixed.cs │ │ ├── IRadixMath.cs │ │ ├── IRadixMathHelper.cs │ │ ├── IShiftAccumulator.cs │ │ ├── NumberUtility.cs │ │ ├── RadixMath.cs │ │ ├── SimpleRadixMath.cs │ │ └── TrappableRadixMath.cs ├── Properties │ └── AssemblyInfo.cs ├── docs.xml ├── rules.ruleset └── stylecop.json ├── Numbers20 ├── Numbers20.csproj ├── Properties │ └── AssemblyInfo.cs ├── packages.config ├── rules.ruleset └── stylecop.json ├── Numbers40 ├── Numbers40.csproj ├── Properties │ └── AssemblyInfo.cs ├── packages.config ├── rules.ruleset └── stylecop.json ├── README.md ├── Test ├── AppResources.cs ├── DecTestUtil.cs ├── DecimalTest.cs ├── DelayingStream.cs ├── EContextTest.cs ├── EDecimalTest.cs ├── EFloatTest.cs ├── EIntegerTest.cs ├── ERationalTest.cs ├── ETrapExceptionTest.cs ├── ExtensiveTest.cs ├── ExtraTest.cs ├── IRandomGen.cs ├── IRandomGenExtended.cs ├── README.md ├── RandomGenerator.cs ├── RandomNumerics.cs ├── RandomObjects.cs ├── Resources.restext ├── Runner.cs ├── SevenBitEncoded.cs ├── StringAndBigInt.cs ├── Test.csproj ├── TestCommon.cs ├── XorShift128Plus.cs ├── rules.ruleset └── stylecop.json ├── Test20 ├── Properties │ └── AssemblyInfo.cs ├── Test20.csproj ├── packages.config ├── rules.ruleset └── stylecop.json ├── Test40 ├── Properties │ └── AssemblyInfo.cs ├── Test40.csproj ├── packages.config ├── rules.ruleset └── stylecop.json ├── docs ├── APIDocs.md ├── PeterO.Numbers.EContext.md ├── PeterO.Numbers.EDecimal.md ├── PeterO.Numbers.EDecimalExtras.md ├── PeterO.Numbers.EDecimals.md ├── PeterO.Numbers.EFloat.md ├── PeterO.Numbers.EFloatExtras.md ├── PeterO.Numbers.EFloats.md ├── PeterO.Numbers.EInteger.md ├── PeterO.Numbers.ERational.md ├── PeterO.Numbers.ERounding.md └── PeterO.Numbers.ETrapException.md └── examples.md /.editorconfig: -------------------------------------------------------------------------------- 1 | # Remove the line below if you want to inherit .editorconfig settings from higher directories 2 | root = true 3 | 4 | # C# files 5 | [*.cs] 6 | 7 | #### Core EditorConfig Options #### 8 | 9 | # Indentation and spacing 10 | indent_size = 2 11 | indent_style = space 12 | tab_width = 2 13 | 14 | # New line preferences 15 | end_of_line = crlf 16 | insert_final_newline = true 17 | 18 | #### .NET Coding Conventions #### 19 | 20 | # Organize usings 21 | dotnet_separate_import_directive_groups = false 22 | dotnet_sort_system_directives_first = false 23 | file_header_template = unset 24 | 25 | # this. and Me. preferences 26 | dotnet_style_qualification_for_event = false 27 | dotnet_style_qualification_for_field = false 28 | dotnet_style_qualification_for_method = false 29 | dotnet_style_qualification_for_property = false 30 | 31 | # Language keywords vs BCL types preferences 32 | dotnet_style_predefined_type_for_locals_parameters_members = true 33 | dotnet_style_predefined_type_for_member_access = false 34 | 35 | # Parentheses preferences 36 | dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity 37 | dotnet_style_parentheses_in_other_binary_operators = always_for_clarity 38 | dotnet_style_parentheses_in_other_operators = never_if_unnecessary 39 | dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity 40 | 41 | # Modifier preferences 42 | dotnet_style_require_accessibility_modifiers = for_non_interface_members 43 | 44 | # Expression-level preferences 45 | dotnet_style_coalesce_expression = true 46 | dotnet_style_collection_initializer = true 47 | dotnet_style_explicit_tuple_names = true 48 | dotnet_style_namespace_match_folder = false 49 | dotnet_style_null_propagation = true 50 | dotnet_style_object_initializer = true 51 | dotnet_style_operator_placement_when_wrapping = beginning_of_line 52 | dotnet_style_prefer_auto_properties = true 53 | dotnet_style_prefer_compound_assignment = true 54 | dotnet_style_prefer_conditional_expression_over_assignment = true 55 | dotnet_style_prefer_conditional_expression_over_return = true 56 | dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed 57 | dotnet_style_prefer_inferred_anonymous_type_member_names = true 58 | dotnet_style_prefer_inferred_tuple_names = true 59 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true 60 | dotnet_style_prefer_simplified_boolean_expressions = true 61 | dotnet_style_prefer_simplified_interpolation = true 62 | 63 | # Field preferences 64 | dotnet_style_readonly_field = true 65 | 66 | # Parameter preferences 67 | dotnet_code_quality_unused_parameters = all 68 | 69 | # Suppression preferences 70 | dotnet_remove_unnecessary_suppression_exclusions = none 71 | 72 | # New line preferences 73 | dotnet_style_allow_multiple_blank_lines_experimental = true 74 | dotnet_style_allow_statement_immediately_after_block_experimental = true 75 | 76 | #### C# Coding Conventions #### 77 | 78 | dotnet_diagnostic.SA1210.severity = none 79 | 80 | # "... where T : ..." rule disabled 81 | dotnet_diagnostic.SA1127.severity = none 82 | 83 | # var preferences 84 | csharp_style_var_elsewhere = false 85 | csharp_style_var_for_built_in_types = false 86 | csharp_style_var_when_type_is_apparent = true 87 | 88 | # Expression-bodied members 89 | csharp_style_expression_bodied_accessors = true 90 | csharp_style_expression_bodied_constructors = false 91 | csharp_style_expression_bodied_indexers = true 92 | csharp_style_expression_bodied_lambdas = true 93 | csharp_style_expression_bodied_local_functions = false 94 | csharp_style_expression_bodied_methods = false 95 | csharp_style_expression_bodied_operators = false 96 | csharp_style_expression_bodied_properties = true 97 | 98 | # Pattern matching preferences 99 | csharp_style_pattern_matching_over_as_with_null_check = true 100 | csharp_style_pattern_matching_over_is_with_cast_check = true 101 | csharp_style_prefer_extended_property_pattern = true 102 | csharp_style_prefer_not_pattern = true 103 | csharp_style_prefer_pattern_matching = true 104 | csharp_style_prefer_switch_expression = true 105 | 106 | # Null-checking preferences 107 | csharp_style_conditional_delegate_call = true 108 | 109 | # Modifier preferences 110 | csharp_prefer_static_local_function = true 111 | csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async 112 | 113 | # Code-block preferences 114 | csharp_prefer_braces = true 115 | csharp_prefer_simple_using_statement = true 116 | csharp_style_namespace_declarations = block_scoped 117 | csharp_style_prefer_method_group_conversion = true 118 | csharp_style_prefer_top_level_statements = true 119 | 120 | # Expression-level preferences 121 | csharp_prefer_simple_default_expression = true 122 | csharp_style_deconstructed_variable_declaration = true 123 | csharp_style_implicit_object_creation_when_type_is_apparent = true 124 | csharp_style_inlined_variable_declaration = true 125 | csharp_style_prefer_index_operator = true 126 | csharp_style_prefer_local_over_anonymous_function = true 127 | csharp_style_prefer_null_check_over_type_check = true 128 | csharp_style_prefer_range_operator = true 129 | csharp_style_prefer_tuple_swap = true 130 | csharp_style_prefer_utf8_string_literals = true 131 | csharp_style_throw_expression = true 132 | csharp_style_unused_value_assignment_preference = discard_variable 133 | csharp_style_unused_value_expression_statement_preference = discard_variable 134 | 135 | # 'using' directive preferences 136 | csharp_using_directive_placement = outside_namespace 137 | 138 | # New line preferences 139 | csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true 140 | csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true 141 | csharp_style_allow_embedded_statements_on_same_line_experimental = true 142 | 143 | #### C# Formatting Rules #### 144 | 145 | # New line preferences 146 | csharp_new_line_before_catch = false 147 | csharp_new_line_before_else = false 148 | csharp_new_line_before_finally = false 149 | csharp_new_line_before_members_in_anonymous_types = true 150 | csharp_new_line_before_members_in_object_initializers = false 151 | csharp_new_line_before_open_brace = none 152 | csharp_new_line_between_query_expression_clauses = false 153 | 154 | # Indentation preferences 155 | csharp_indent_block_contents = true 156 | csharp_indent_braces = false 157 | csharp_indent_case_contents = true 158 | csharp_indent_case_contents_when_block = true 159 | csharp_indent_labels = one_less_than_current 160 | csharp_indent_switch_labels = true 161 | 162 | # Space preferences 163 | csharp_space_after_cast = false 164 | csharp_space_after_colon_in_inheritance_clause = true 165 | csharp_space_after_comma = true 166 | csharp_space_after_dot = false 167 | csharp_space_after_keywords_in_control_flow_statements = true 168 | csharp_space_after_semicolon_in_for_statement = true 169 | csharp_space_around_binary_operators = before_and_after 170 | csharp_space_around_declaration_statements = false 171 | csharp_space_before_colon_in_inheritance_clause = true 172 | csharp_space_before_comma = false 173 | csharp_space_before_dot = false 174 | csharp_space_before_open_square_brackets = false 175 | csharp_space_before_semicolon_in_for_statement = false 176 | csharp_space_between_empty_square_brackets = false 177 | csharp_space_between_method_call_empty_parameter_list_parentheses = false 178 | csharp_space_between_method_call_name_and_opening_parenthesis = false 179 | csharp_space_between_method_call_parameter_list_parentheses = false 180 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false 181 | csharp_space_between_method_declaration_name_and_open_parenthesis = false 182 | csharp_space_between_method_declaration_parameter_list_parentheses = false 183 | csharp_space_between_parentheses = false 184 | csharp_space_between_square_brackets = false 185 | 186 | # Wrapping preferences 187 | csharp_preserve_single_line_blocks = true 188 | csharp_preserve_single_line_statements = true 189 | 190 | #### Naming styles #### 191 | 192 | # Naming rules 193 | 194 | dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion 195 | dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface 196 | dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i 197 | 198 | dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion 199 | dotnet_naming_rule.types_should_be_pascal_case.symbols = types 200 | dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case 201 | 202 | dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion 203 | dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members 204 | dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case 205 | 206 | # Symbol specifications 207 | 208 | dotnet_naming_symbols.interface.applicable_kinds = interface 209 | dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 210 | dotnet_naming_symbols.interface.required_modifiers = 211 | 212 | dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum 213 | dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 214 | dotnet_naming_symbols.types.required_modifiers = 215 | 216 | dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method 217 | dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 218 | dotnet_naming_symbols.non_field_members.required_modifiers = 219 | 220 | # Naming styles 221 | 222 | dotnet_naming_style.pascal_case.required_prefix = 223 | dotnet_naming_style.pascal_case.required_suffix = 224 | dotnet_naming_style.pascal_case.word_separator = 225 | dotnet_naming_style.pascal_case.capitalization = pascal_case 226 | 227 | dotnet_naming_style.begins_with_i.required_prefix = I 228 | dotnet_naming_style.begins_with_i.required_suffix = 229 | dotnet_naming_style.begins_with_i.word_separator = 230 | dotnet_naming_style.begins_with_i.capitalization = pascal_case 231 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.cs eol=lf 3 | *.java eol=lf 4 | *.js eol=lf 5 | *.rb eol=lf 6 | *.py eol=lf 7 | *.php eol=lf 8 | *.c eol=lf 9 | *.h eol=lf 10 | *.cc eol=lf 11 | *.hh eol=lf 12 | *.cpp eol=lf 13 | *.cxx eol=lf 14 | *.md eol=lf 15 | *.sln eol=lf 16 | *.config eol=lf 17 | *.csproj eol=lf 18 | *.vbproj eol=lf 19 | *.fsproj eol=lf 20 | *.dbproj eol=lf 21 | *.nuspec eol=lf 22 | *.html eol=lf 23 | *.htm eol=lf 24 | *.css eol=lf 25 | *.less eol=lf 26 | *.xml eol=lf 27 | *.ruleset eol=lf 28 | *.yml eol=lf 29 | .gitattributes eol=lf 30 | .gitignore eol=lf 31 | .npmignore eol=lf 32 | *.cs diff=csharp 33 | *.sln merge=union 34 | *.csproj merge=union 35 | *.vbproj merge=union 36 | *.fsproj merge=union 37 | *.dbproj merge=union 38 | -------------------------------------------------------------------------------- /.github/workflows/Test.yml: -------------------------------------------------------------------------------- 1 | # NOTE by Peter O: 2 | # Modified from a file that was contributed by GitHub user Happypig375 3 | # at: https://github.com/peteroupc/Numbers/pull/10 4 | name: Test 5 | 6 | on: [push, pull_request] 7 | jobs: 8 | 9 | Core: 10 | runs-on: ${{ matrix.os }} 11 | strategy: 12 | matrix: 13 | os: [windows-latest, ubuntu-latest, macos-latest] 14 | steps: 15 | - uses: actions/checkout@v2 16 | with: 17 | submodules: 'recursive' 18 | - name: Setup .NET Core 19 | uses: actions/setup-dotnet@v1 20 | with: 21 | dotnet-version: '9.0' 22 | - name: Test 23 | run: | 24 | dotnet add Test package Microsoft.NET.Test.Sdk # Update is required for GitHubActionsTestLogger to print anything 25 | dotnet add Test package GitHubActionsTestLogger 26 | dotnet add Test package NUnit3TestAdapter 27 | dotnet test Test -c Release 28 | 29 | permissions: 30 | contents: read 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.Cache 2 | *.Settings 3 | *.bat 4 | *.cache 5 | *.class 6 | *.jar 7 | *.lock.json 8 | *.log 9 | *.map 10 | *.nupkg 11 | *.pyc 12 | *.sdsettings 13 | *.shf* 14 | *.suo 15 | *.user 16 | *.userprefs 17 | *.versionsBackup 18 | *.vspx 19 | .classpath 20 | .nuget/ 21 | .pmd 22 | .project 23 | .settings/ 24 | .vs/ 25 | CBORTest/OpenCover/ 26 | CBORTest/ProfilingSessions/ 27 | CBORTest/bin/ 28 | CBORTest/obj/ 29 | Help/ 30 | ProfilingSessions/ 31 | TestResults/ 32 | bin/ 33 | coverage/ 34 | encoding/ 35 | encodingfldr/ 36 | obj/ 37 | packages/ 38 | release.properties 39 | target/ 40 | -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | Release notes 2 | ------- 3 | Version 1.7.3 4 | 5 | - Fix bugs and regressions involving EInteger's Pow, Root, and new Gcd 6 | 7 | Version 1.7.2 8 | 9 | - Improve performance of EInteger's Gcd method for large integers 10 | 11 | Version 1.7.1 12 | 13 | - Fix bugs in new char[] and byte[] overloads of FromString 14 | 15 | Version 1.7.0 16 | 17 | - Added overloads to string-to-number methods that take char[] and byte[] arrays. 18 | - Added methods that convert EDecimal, EFloat, and ERational to and from raw bits that follow IEEE 754 binary floating-point formats (To/FromDoubleBits, To/FromSingleBits). 19 | - Added Log1P and ExpM1 methods to EDecimal and EFloat 20 | - Added 'long' overloads to several arithmetic methods 21 | - Added implication and equivalence (Imp/Eqv) methods and an nth-root method to EInteger 22 | 23 | Version 1.6.0 24 | 25 | - Numerous performance improvements in the EInteger, EDecimal, EFloat, and ERational classes. Among them is the use of caches for small EInteger, EDecimal, and EFloat values, and faster multiplication algorithms for large EIntegers. 26 | - Correctness fixes to the Log() methods in EDecimal and EFloat 27 | - New LogN() method in EDecimal and EFloat 28 | - New methods in EInteger, including FromBytes, GetDigitCountAsEInteger, and DivRem(long) 29 | - New ToSizedEInteger/ToSizedEIntegerIfExact/IsInteger methods in EDecimal, EFloat, and ERational 30 | - New Create overloads in EFloat and ERational 31 | - New Min and Max methods in EInteger and ERational 32 | - Issue fixes 33 | 34 | Version 1.5.1 35 | 36 | - Fix bugs in EDecimal.FromString and ERational.FromString involving substrings containing negative numbers. 37 | 38 | Version 1.5.0 39 | 40 | - Major performance improvements in certain number parsing and generating methods, including the FromString methods of EInteger, EDecimal, EFloat, and ERational, and the ToEFloat method of EDecimal, especially where they take an arithmetic context (EContext) that specifies a limited precision and exponent range. 41 | - There were also performance improvements in digit count calculation and in rounding many-digit-long numbers. 42 | - Add int overloads to EDecimal.Pow and EFloat.Pow. 43 | - Add int overloads to several ERational methods. 44 | - Add CompareTo overloads and CompareToValue (which implements current CompareTo) in EDecimal, EFloat, and ERational. In a future version, CompareTo's behavior might change to CompareToTotal in each of these classes. Also certain CompareTo* methods now have consistent behavior when they receive a null argument. 45 | - ETrapException now has an Errors property that holds all errors that occur at the same time as the primary error. 46 | - Fixed edge cases when ToShortestString might return an incorrect result. 47 | - Fixed bug when some ETrapExceptions aren't thrown as they should. 48 | - Other issue fixes. 49 | 50 | Version 1.4.3 51 | 52 | - Fix accuracy issue with Log, especially where 1 < x < 1.07 53 | - Remove StyleCop.Analyzers, which is used only in development, as dependency in .NET version 54 | 55 | Version 1.4.2 56 | 57 | - Issue fix in the EInteger.CanFitInInt64 method 58 | 59 | Version 1.4.1 60 | 61 | - Added EDecimals and EFloats classes to .NET 2.0 and .NET 4.0 versions; those classes were inadvertently omitted there 62 | 63 | Version 1.4.0 64 | 65 | - Added EDecimals and EFloats class that implements more methods for arbitrary-precision decimal and binary numbers 66 | - Increment and decrement operators added to EInteger, EDecimal, EFloat, and ERational classes 67 | - Allowed EDecimal values in (-1, 0) to EDecimal's *Checked methods, to conform to documentation. 68 | - Added WithNoFlagsOrTraps method and HasFlagsOrTraps property to EContext 69 | - Add Mod(int), Pow(int), and FromBoolean methods to EInteger 70 | - Add And, Not, Xor, and Or methods to EInteger.cs 71 | - Add Copy method to EDecimal, EFloat, and ERational 72 | - Add CompareToTotalMagnitude overload to EDecimal, EFloat, and ERational 73 | - Deprecated Odd and ZeroFiveUp rounding modes 74 | - Issue fixes and performance improvements 75 | 76 | Version 1.3.0: 77 | 78 | - Improve performance of EDecimal.CompareToBinary in certain cases 79 | - Fix ERational.ToSingle method 80 | - Add EInteger overloads to EInteger.GetSignedBit, EInteger.GetUnsignedBit, EInteger.ShiftLeft, and EInteger.ShiftRight 81 | - Add GetDigitCountAsEInteger and GetSignedBitLengthAsEInteger methods to EInteger class 82 | - Check for overflow in GetLowBit, GetDigitCount, GetUnsignedBitLength, and 83 | GetSignedBitLength methods in EInteger class; deprecate those methods 84 | - Add FromBoolean methods to EDecimal, EFloat, and ERational 85 | 86 | Version 1.2.2: 87 | 88 | - Fixed referencing issues with minor version 1.2.1 89 | 90 | Version 1.2.1: 91 | 92 | - Fixed bugs with new EInteger.Add and EInteger.Subtract overloads 93 | 94 | Version 1.2: 95 | 96 | - Add arithmetic methods to EInteger, EDecimal, and EFloat that 97 | take 'int' operands. 98 | - Fix issues with EDecimal/EFloat Remainder method in corner cases 99 | - Add RemainderNoRoundAfterDivide in EDecimal and EFloat 100 | 101 | Version 1.1.2 102 | 103 | - Add .NET Framework 4.0 targeted assembly to avoid compiler warnings that can appear when this package is added to a project that targets .NET Framework 4.0 or later. 104 | 105 | Version 1.1.1 106 | 107 | - Numbers .NET 2.0 assembly had wrong version number. 108 | 109 | Version 1.1.0 110 | 111 | - Added build targeting .NET Framework 2.0. 112 | 113 | Version 1.0.2 114 | 115 | - Really strong-name sign the assembly, which (probably) was inadvertently delay-signed in version 1.0. 116 | 117 | Version 1.0 118 | 119 | - Filled out documentation so that there are no more undocumented parts 120 | 121 | Version 0.5 122 | 123 | - Moved from .NET Portable to .NET Standard 1.0. Contributed by GitHub user NZSmartie 124 | - Broke backwards compatibility with .NET Framework 4.0 125 | - Issue fixes 126 | 127 | Version 0.4: 128 | 129 | - Assembly signed with a strong name 130 | - Some improvements to documentation 131 | 132 | Version 0.3: 133 | 134 | - Deprecated ERational constructor 135 | - Added many type conversion operators and methods 136 | to EDecimal, EFloat, ERational, and EInteger 137 | - Added FromString, CompareToTotal, and 138 | CompareToTotalMagnitude methods to ERational 139 | - An overload of RoundToExponentExact in EDecimal is 140 | no longer obsolete and uses the rounding mode specified 141 | - Used a new division implementation in EInteger 142 | - Used the new division implementation to optimize conversion 143 | of huge EIntegers to decimal strings 144 | - Issue fixes 145 | 146 | Version 0.2.2: 147 | 148 | - Previous assembly was released with wrong version number 149 | 150 | Version 0.2.1: 151 | 152 | - Fixed corner cases in EFloat's ToSingle and ToDouble methods 153 | 154 | Version 0.2: 155 | 156 | - Performance improvements 157 | - Added several overloads for DivideToExponent method 158 | - GCD code in EInteger rewritten 159 | - Added CopySign, CompareToTotal, and CompareToTotalMagnitude 160 | methods to EDecimal and EFloat. 161 | - Renamed several methods in EDecimal and EFloat 162 | - RoundToIntegral\* methods renamed to RoundToInteger\* methods 163 | - Renamed some EInteger integer conversion methods; added 164 | CanFitInInt64, GetUnsignedBitLengthAsEInteger, 165 | and GetLowBitAsEInteger methods 166 | - Several operators added to EDecimal in C# version 167 | - Rewrote code that converts from decimal to binary floating-point; 168 | add ToEFloat method taking an EContext in EDecimal 169 | - Added ToShortestString method in EFloat 170 | - Add UnlimitedHalfEven EContext object 171 | - Issue fixes 172 | 173 | Version 0.1: 174 | 175 | - Initial release 176 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. 4 | 5 | In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. 6 | 7 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /Numbers.nuspec: -------------------------------------------------------------------------------- 1 | 1.8.1PeterO.NumbersfalseVersion 1.8.1 3 | 4 | - Fix bugs in EFloat string parsing in certain corner cases 5 | - Fix NaN roundtripping with From/ToSingleBits and From/ToDoubleBits 6 | 7 | Version 1.8 8 | 9 | - Add LowBits family of methods to EInteger 10 | - Add FromInt64AsUnsigned to EInteger, EDecimal, EFloat, and ERational 11 | - Add overload to FromBytes method of EInteger 12 | - Issue fixesCC0-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 14 | -------------------------------------------------------------------------------- /Numbers.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio 15 3 | VisualStudioVersion = 15.0.26430.15 4 | MinimumVisualStudioVersion = 10.0.40219.1 5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test.csproj", "{8FE63143-541E-448D-8337-A98D1FA51541}" 6 | ProjectSection(ProjectDependencies) = postProject 7 | {C6EF158C-6F4B-4280-A823-44C945469E39} = {C6EF158C-6F4B-4280-A823-44C945469E39} 8 | EndProjectSection 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3F4A3741-A572-4B47-BEDA-24F7ADD1FBB2}" 11 | ProjectSection(SolutionItems) = preProject 12 | .gitattributes = .gitattributes 13 | .gitignore = .gitignore 14 | docs.xml = docs.xml 15 | examples.md = examples.md 16 | LICENSE.md = LICENSE.md 17 | Numbers.nuspec = Numbers.nuspec 18 | Numbers.ruleset = Numbers.ruleset 19 | README.md = README.md 20 | Settings.SourceAnalysis = Settings.SourceAnalysis 21 | EndProjectSection 22 | EndProject 23 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{53713F40-8C18-4478-8EA2-DD30E4C6BC38}" 24 | ProjectSection(SolutionItems) = preProject 25 | docs\APIDocs.md = docs\APIDocs.md 26 | docs\PeterO.Numbers.EContext.md = docs\PeterO.Numbers.EContext.md 27 | docs\PeterO.Numbers.EDecimal.md = docs\PeterO.Numbers.EDecimal.md 28 | docs\PeterO.Numbers.EFloat.md = docs\PeterO.Numbers.EFloat.md 29 | docs\PeterO.Numbers.EInteger.md = docs\PeterO.Numbers.EInteger.md 30 | docs\PeterO.Numbers.ERational.md = docs\PeterO.Numbers.ERational.md 31 | docs\PeterO.Numbers.ERounding.md = docs\PeterO.Numbers.ERounding.md 32 | docs\PeterO.Numbers.ETrapException.md = docs\PeterO.Numbers.ETrapException.md 33 | EndProjectSection 34 | EndProject 35 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Numbers", "Numbers\Numbers.csproj", "{C6EF158C-6F4B-4280-A823-44C945469E39}" 36 | EndProject 37 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Numbers40", "Numbers40\Numbers40.csproj", "{D7E09F55-3156-44B0-87D9-1BABCBB398D9}" 38 | EndProject 39 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Numbers20", "Numbers20\Numbers20.csproj", "{04A7B845-E447-4A46-ABB9-D195BDEDC735}" 40 | EndProject 41 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test20", "Test20\Test20.csproj", "{4CF0E5BA-CDE3-4DEA-B3F4-11EE544B3FB2}" 42 | EndProject 43 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test40", "Test40\Test40.csproj", "{00EB31B6-A805-4EFB-A64B-9F8176B2A1CC}" 44 | EndProject 45 | EndProject 46 | Global 47 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 48 | Debug|Any CPU = Debug|Any CPU 49 | Release|Any CPU = Release|Any CPU 50 | EndGlobalSection 51 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 52 | {8FE63143-541E-448D-8337-A98D1FA51541}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 53 | {8FE63143-541E-448D-8337-A98D1FA51541}.Debug|Any CPU.Build.0 = Debug|Any CPU 54 | {8FE63143-541E-448D-8337-A98D1FA51541}.Release|Any CPU.ActiveCfg = Release|Any CPU 55 | {8FE63143-541E-448D-8337-A98D1FA51541}.Release|Any CPU.Build.0 = Release|Any CPU 56 | {C6EF158C-6F4B-4280-A823-44C945469E39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 57 | {C6EF158C-6F4B-4280-A823-44C945469E39}.Debug|Any CPU.Build.0 = Debug|Any CPU 58 | {C6EF158C-6F4B-4280-A823-44C945469E39}.Release|Any CPU.ActiveCfg = Release|Any CPU 59 | {C6EF158C-6F4B-4280-A823-44C945469E39}.Release|Any CPU.Build.0 = Release|Any CPU 60 | {D7E09F55-3156-44B0-87D9-1BABCBB398D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 61 | {D7E09F55-3156-44B0-87D9-1BABCBB398D9}.Debug|Any CPU.Build.0 = Debug|Any CPU 62 | {D7E09F55-3156-44B0-87D9-1BABCBB398D9}.Release|Any CPU.ActiveCfg = Release|Any CPU 63 | {D7E09F55-3156-44B0-87D9-1BABCBB398D9}.Release|Any CPU.Build.0 = Release|Any CPU 64 | {04A7B845-E447-4A46-ABB9-D195BDEDC735}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 65 | {04A7B845-E447-4A46-ABB9-D195BDEDC735}.Debug|Any CPU.Build.0 = Debug|Any CPU 66 | {04A7B845-E447-4A46-ABB9-D195BDEDC735}.Release|Any CPU.ActiveCfg = Release|Any CPU 67 | {04A7B845-E447-4A46-ABB9-D195BDEDC735}.Release|Any CPU.Build.0 = Release|Any CPU 68 | {4CF0E5BA-CDE3-4DEA-B3F4-11EE544B3FB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 69 | {4CF0E5BA-CDE3-4DEA-B3F4-11EE544B3FB2}.Debug|Any CPU.Build.0 = Debug|Any CPU 70 | {4CF0E5BA-CDE3-4DEA-B3F4-11EE544B3FB2}.Release|Any CPU.ActiveCfg = Release|Any CPU 71 | {4CF0E5BA-CDE3-4DEA-B3F4-11EE544B3FB2}.Release|Any CPU.Build.0 = Release|Any CPU 72 | {00EB31B6-A805-4EFB-A64B-9F8176B2A1CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 73 | {00EB31B6-A805-4EFB-A64B-9F8176B2A1CC}.Debug|Any CPU.Build.0 = Debug|Any CPU 74 | {00EB31B6-A805-4EFB-A64B-9F8176B2A1CC}.Release|Any CPU.ActiveCfg = Release|Any CPU 75 | {00EB31B6-A805-4EFB-A64B-9F8176B2A1CC}.Release|Any CPU.Build.0 = Release|Any CPU 76 | EndGlobalSection 77 | GlobalSection(SolutionProperties) = preSolution 78 | HideSolutionNode = FALSE 79 | EndGlobalSection 80 | GlobalSection(NestedProjects) = preSolution 81 | {53713F40-8C18-4478-8EA2-DD30E4C6BC38} = {3F4A3741-A572-4B47-BEDA-24F7ADD1FBB2} 82 | EndGlobalSection 83 | EndGlobal 84 | -------------------------------------------------------------------------------- /Numbers/Numbers.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0; net6.0 5 | True 6 | true 7 | 1.9 8 | Peter Occil 9 | A 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. 10 | Written by Peter O. Any copyright to this work is released to the Public Domain. In case this is not possible, this work is also 11 | licensed under the Unlicense: https://unlicense.org/ 12 | Peter Occil 13 | PeterO.Numbers 14 | Arbitrary-Precision Number Library 15 | False 16 | CC0-1.0 17 | https://github.com/peteroupc/Numbers 18 | 19 | Version 1.8.1 20 | 21 | - Fix bugs in EFloat string parsing in certain corner cases 22 | - Fix NaN roundtripping with From/ToSingleBits and From/ToDoubleBits 23 | 24 | Version 1.8 25 | 26 | - Add LowBits family of methods to EInteger 27 | - Add FromInt64AsUnsigned to EInteger, EDecimal, EFloat, and ERational 28 | - Add overload to FromBytes method of EInteger 29 | - Issue fixes 30 | 31 | 32 | numbers arithmetic decimal math 33 | true true 34 | Arbitrary-Precision Arithmetic Library 35 | rules.ruleset 36 | 37 | true 38 | 11.0 39 | true 40 | MULTI_TARGETING_SUPPORT_ATTRIBUTES 41 | 42 | 43 | bin\Debug\netstandard2.0\Numbers.xml 44 | 45 | full 46 | rules.ruleset 47 | 48 | none 49 | bin\Release\netstandard2.0\Numbers.xml 50 | truePeterO.snk 51 | rules.ruleset 52 | 53 | 54 | 55 | 56 | all 57 | runtime; build; native; contentfiles; analyzers; buildtransitive 58 | 59 | 60 | -------------------------------------------------------------------------------- /Numbers/PeterO.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peteroupc/Numbers/56e62dca699e69256434bbdacbe8cb2b21ebb91c/Numbers/PeterO.snk -------------------------------------------------------------------------------- /Numbers/PeterO/DebugUtility.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Written by Peter O. 3 | Any copyright to this work is released to the Public Domain. 4 | In case this is not possible, this work is also 5 | licensed under the Unlicense: https://unlicense.org/ 6 | 7 | */ 8 | using System; 9 | using System.Diagnostics.CodeAnalysis; 10 | using System.Reflection; 11 | // Use directives rather than the Conditional attribute, 12 | // to avoid the chance of logging statements leaking in release builds 13 | #if DEBUGLOG 14 | namespace PeterO { 15 | internal static class DebugUtility { 16 | private static readonly object WriterLock = new object(); 17 | private static Action writer; 18 | 19 | [System.Diagnostics.Conditional("DEBUG")] 20 | public static void SetWriter(Action wr) { 21 | lock (WriterLock) { 22 | writer = wr; 23 | } 24 | } 25 | 26 | // [RequiresUnreferencedCode("Do not use in AOT or reflection-free 27 | // contexts.")] 28 | private static MethodInfo GetTypeMethod( 29 | Type t, 30 | string name, 31 | Type[] parameters) { 32 | #if NET40 || NET20 33 | return t.GetMethod(name, new[] { parameter }); 34 | #else 35 | { 36 | return t?.GetRuntimeMethod(name, parameters); 37 | } 38 | #endif 39 | } 40 | 41 | // [RequiresUnreferencedCode("Do not use in AOT or reflection-free 42 | // contexts.")] 43 | public static void Log(string str) { 44 | var type = Type.GetType("System.Console"); 45 | if (type == null) { 46 | Action wr = null; 47 | lock (WriterLock) { 48 | wr = writer; 49 | } 50 | if (wr != null) { 51 | #if !NET20 && !NET40 52 | System.Diagnostics.Debug.WriteLine(str); 53 | #endif 54 | wr(str); 55 | return; 56 | } else { 57 | #if !NET20 && !NET40 58 | System.Diagnostics.Debug.WriteLine(str); 59 | return; 60 | #else 61 | { 62 | throw new NotSupportedException("System.Console not found"); 63 | } 64 | #endif 65 | } 66 | } 67 | Type[] types = new[] { typeof(string) }; 68 | MethodInfo typeMethod = GetTypeMethod(type, "WriteLine", types); 69 | if (typeMethod != null) { 70 | typeMethod.Invoke( 71 | type, 72 | new object[] { str }); 73 | } else { 74 | throw new NotSupportedException("System.Console.WriteLine not found"); 75 | } 76 | } 77 | 78 | [System.Diagnostics.Conditional("DEBUG")] 79 | // [RequiresUnreferencedCode("Do not use in AOT or reflection-free 80 | // contexts.")] 81 | public static void Log(string format, params object[] args) { 82 | Log(String.Format( 83 | System.Globalization.CultureInfo.CurrentCulture, 84 | format, 85 | args)); 86 | } 87 | } 88 | } 89 | #endif 90 | -------------------------------------------------------------------------------- /Numbers/PeterO/Numbers/BigNumberFlags.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Written by Peter O. 3 | Any copyright to this work is released to the Public Domain. 4 | In case this is not possible, this work is also 5 | licensed under the Unlicense: https://unlicense.org/ 6 | 7 | */ 8 | using System; 9 | 10 | namespace PeterO.Numbers { 11 | internal static class BigNumberFlags { 12 | internal const int FlagNegative = 1; 13 | internal const int FlagQuietNaN = 4; 14 | internal const int FlagSignalingNaN = 8; 15 | internal const int FlagInfinity = 2; 16 | internal const int FlagSpecial = FlagQuietNaN | FlagSignalingNaN | 17 | FlagInfinity; 18 | internal const int FlagNaN = FlagQuietNaN | FlagSignalingNaN; 19 | internal const int LostDigitsFlags = EContext.FlagLostDigits | 20 | EContext.FlagInexact | EContext.FlagRounded; 21 | internal const int FiniteOnly = 0; 22 | internal const int FiniteAndNonFinite = 1; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Numbers/PeterO/Numbers/ERationalByteArrayString.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | 4 | namespace PeterO.Numbers { 5 | internal static class ERationalByteArrayString { 6 | private const int MaxSafeInt = EDecimal.MaxSafeInt; 7 | 8 | public static ERational FromString( 9 | byte[] chars, 10 | int offset, 11 | int length, 12 | bool throwException) { 13 | int tmpoffset = offset; 14 | if (chars == null) { 15 | if (!throwException) { 16 | return null; 17 | } else { 18 | throw new ArgumentNullException(nameof(chars)); 19 | } 20 | } 21 | if (tmpoffset < 0) { 22 | if (!throwException) { 23 | return null; 24 | } else { 25 | throw new FormatException("offset(" + tmpoffset + ") is" + 26 | "\u0020less" + "\u0020than " + "0"); 27 | } 28 | } 29 | if (tmpoffset > chars.Length) { 30 | if (!throwException) { 31 | return null; 32 | } else { 33 | throw new FormatException("offset(" + tmpoffset + ") is" + 34 | "\u0020more" + "\u0020than " + chars.Length); 35 | } 36 | } 37 | if (length < 0) { 38 | if (!throwException) { 39 | return null; 40 | } else { 41 | throw new FormatException("length(" + length + ") is less than " + 42 | "0"); 43 | } 44 | } 45 | if (length > chars.Length) { 46 | if (!throwException) { 47 | return null; 48 | } else { 49 | throw new FormatException("length(" + length + ") is more than " + 50 | chars.Length); 51 | } 52 | } 53 | if (chars.Length - tmpoffset < length) { 54 | if (!throwException) { 55 | return null; 56 | } else { 57 | throw new FormatException("chars's length minus " + 58 | tmpoffset + "(" + (chars.Length - tmpoffset) + ") is less than " + 59 | length); 60 | } 61 | } 62 | if (length == 0) { 63 | if (!throwException) { 64 | return null; 65 | } else { 66 | throw new FormatException(); 67 | } 68 | } 69 | var negative = false; 70 | int endStr = tmpoffset + length; 71 | if (chars[tmpoffset] == '+' || chars[tmpoffset] == '-') { 72 | negative = chars[tmpoffset] == '-'; 73 | ++tmpoffset; 74 | } 75 | var numerInt = 0; 76 | EInteger numer = null; 77 | var haveDigits = false; 78 | var haveDenominator = false; 79 | var ndenomInt = 0; 80 | EInteger ndenom = null; 81 | int i = tmpoffset; 82 | if (i + 8 == endStr) { 83 | if ((chars[i] == 'I' || chars[i] == 'i') && 84 | (chars[i + 1] == 'N' || chars[i + 1] == 'n') && 85 | (chars[i + 2] == 'F' || chars[i + 2] == 'f') && 86 | (chars[i + 3] == 'I' || chars[i + 3] == 'i') && (chars[i + 4] == 87 | 'N' || chars[i + 4] == 'n') && (chars[i + 5] == 'I' || chars[i + 5] == 88 | 'i') && 89 | (chars[i + 6] == 'T' || chars[i + 6] == 't') && (chars[i + 7] == 90 | 'Y' || chars[i + 7] == 'y')) { 91 | return negative ? ERational.NegativeInfinity : 92 | ERational.PositiveInfinity; 93 | } 94 | } 95 | if (i + 3 == endStr) { 96 | if ((chars[i] == 'I' || chars[i] == 'i') && 97 | (chars[i + 1] == 'N' || chars[i + 1] == 'n') && (chars[i + 2] == 98 | 'F' || chars[i + 2] == 'f')) { 99 | return negative ? ERational.NegativeInfinity : 100 | ERational.PositiveInfinity; 101 | } 102 | } 103 | var numerStart = 0; 104 | if (i + 3 <= endStr) { 105 | // Quiet NaN 106 | if ((chars[i] == 'N' || chars[i] == 'n') && (chars[i + 1] == 'A' || 107 | chars[i + 108 | 1] == 'a') && (chars[i + 2] == 'N' || chars[i + 2] == 'n')) { 109 | if (i + 3 == endStr) { 110 | return (!negative) ? ERational.NaN : ERational.NaN.Negate(); 111 | } 112 | i += 3; 113 | numerStart = i; 114 | for (; i < endStr; ++i) { 115 | if (chars[i] >= '0' && chars[i] <= '9') { 116 | var thisdigit = (int)(chars[i] - '0'); 117 | if (numerInt <= MaxSafeInt) { 118 | numerInt *= 10; 119 | numerInt += thisdigit; 120 | } 121 | } else { 122 | if (!throwException) { 123 | return null; 124 | } else { 125 | throw new FormatException(); 126 | } 127 | } 128 | } 129 | if (numerInt > MaxSafeInt) { 130 | numer = EInteger.FromSubstring(chars, numerStart, endStr); 131 | return ERational.CreateNaN(numer, false, negative); 132 | } else { 133 | return ERational.CreateNaN( 134 | EInteger.FromInt32(numerInt), 135 | false, 136 | negative); 137 | } 138 | } 139 | } 140 | if (i + 4 <= endStr) { 141 | // Signaling NaN 142 | if ((chars[i] == 'S' || chars[i] == 's') && (chars[i + 1] == 'N' || 143 | chars[i + 144 | 1] == 'n') && (chars[i + 2] == 'A' || chars[i + 2] == 'a') && 145 | (chars[i + 3] == 'N' || chars[i + 3] == 'n')) { 146 | if (i + 4 == endStr) { 147 | return (!negative) ? ERational.SignalingNaN : 148 | ERational.SignalingNaN.Negate(); 149 | } 150 | i += 4; 151 | numerStart = i; 152 | for (; i < endStr; ++i) { 153 | if (chars[i] >= '0' && chars[i] <= '9') { 154 | var thisdigit = (int)(chars[i] - '0'); 155 | haveDigits = haveDigits || thisdigit != 0; 156 | if (numerInt <= MaxSafeInt) { 157 | numerInt *= 10; 158 | numerInt += thisdigit; 159 | } 160 | } else { 161 | if (!throwException) { 162 | return null; 163 | } else { 164 | throw new FormatException(); 165 | } 166 | } 167 | } 168 | int flags3 = (negative ? BigNumberFlags.FlagNegative : 0) | 169 | BigNumberFlags.FlagSignalingNaN; 170 | if (numerInt > MaxSafeInt) { 171 | numer = EInteger.FromSubstring(chars, numerStart, endStr); 172 | return ERational.CreateNaN(numer, true, negative); 173 | } else { 174 | return ERational.CreateNaN( 175 | EInteger.FromInt32(numerInt), 176 | true, 177 | negative); 178 | } 179 | } 180 | } 181 | // Ordinary number 182 | numerStart = i; 183 | int numerEnd = i; 184 | for (; i < endStr; ++i) { 185 | if (chars[i] >= '0' && chars[i] <= '9') { 186 | var thisdigit = (int)(chars[i] - '0'); 187 | numerEnd = i + 1; 188 | if (numerInt <= MaxSafeInt) { 189 | numerInt *= 10; 190 | numerInt += thisdigit; 191 | } 192 | haveDigits = true; 193 | } else if (chars[i] == '/') { 194 | haveDenominator = true; 195 | ++i; 196 | break; 197 | } else { 198 | if (!throwException) { 199 | return null; 200 | } else { 201 | throw new FormatException(); 202 | } 203 | } 204 | } 205 | if (!haveDigits) { 206 | if (!throwException) { 207 | return null; 208 | } else { 209 | throw new FormatException(); 210 | } 211 | } 212 | if (numerInt > MaxSafeInt) { 213 | numer = EInteger.FromSubstring(chars, numerStart, numerEnd); 214 | } 215 | if (haveDenominator) { 216 | EInteger denom = null; 217 | var denomInt = 0; 218 | tmpoffset = 1; 219 | haveDigits = false; 220 | if (i == endStr) { 221 | if (!throwException) { 222 | return null; 223 | } else { 224 | throw new FormatException(); 225 | } 226 | } 227 | numerStart = i; 228 | for (; i < endStr; ++i) { 229 | if (chars[i] >= '0' && chars[i] <= '9') { 230 | haveDigits = true; 231 | var thisdigit = (int)(chars[i] - '0'); 232 | numerEnd = i + 1; 233 | if (denomInt <= MaxSafeInt) { 234 | denomInt *= 10; 235 | denomInt += thisdigit; 236 | } 237 | } else { 238 | if (!throwException) { 239 | return null; 240 | } else { 241 | throw new FormatException(); 242 | } 243 | } 244 | } 245 | if (!haveDigits) { 246 | if (!throwException) { 247 | return null; 248 | } else { 249 | throw new FormatException(); 250 | } 251 | } 252 | if (denomInt > MaxSafeInt) { 253 | denom = EInteger.FromSubstring(chars, numerStart, numerEnd); 254 | } 255 | if (denom == null) { 256 | ndenomInt = denomInt; 257 | } else { 258 | ndenom = denom; 259 | } 260 | } else { 261 | ndenomInt = 1; 262 | } 263 | if (i != endStr) { 264 | if (!throwException) { 265 | return null; 266 | } else { 267 | throw new FormatException(); 268 | } 269 | } 270 | if (ndenom == null ? (ndenomInt == 0) : ndenom.IsZero) { 271 | if (!throwException) { 272 | return null; 273 | } else { 274 | throw new FormatException(); 275 | } 276 | } 277 | ERational erat = ERational.Create( 278 | numer == null ? (EInteger)numerInt : numer, 279 | ndenom == null ? (EInteger)ndenomInt : ndenom); 280 | return negative ? erat.Negate() : erat; 281 | } 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /Numbers/PeterO/Numbers/ERationalCharArrayString.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | 4 | namespace PeterO.Numbers { 5 | internal static class ERationalCharArrayString { 6 | private const int MaxSafeInt = EDecimal.MaxSafeInt; 7 | 8 | public static ERational FromString( 9 | char[] chars, 10 | int offset, 11 | int length, 12 | bool throwException) { 13 | int tmpoffset = offset; 14 | if (chars == null) { 15 | if (!throwException) { 16 | return null; 17 | } else { 18 | throw new ArgumentNullException(nameof(chars)); 19 | } 20 | } 21 | if (tmpoffset < 0) { 22 | if (!throwException) { 23 | return null; 24 | } else { 25 | throw new FormatException("offset(" + tmpoffset + ") is" + 26 | "\u0020less" + "\u0020than " + "0"); 27 | } 28 | } 29 | if (tmpoffset > chars.Length) { 30 | if (!throwException) { 31 | return null; 32 | } else { 33 | throw new FormatException("offset(" + tmpoffset + ") is" + 34 | "\u0020more" + "\u0020than " + chars.Length); 35 | } 36 | } 37 | if (length < 0) { 38 | if (!throwException) { 39 | return null; 40 | } else { 41 | throw new FormatException("length(" + length + ") is less than " + 42 | "0"); 43 | } 44 | } 45 | if (length > chars.Length) { 46 | if (!throwException) { 47 | return null; 48 | } else { 49 | throw new FormatException("length(" + length + ") is more than " + 50 | chars.Length); 51 | } 52 | } 53 | if (chars.Length - tmpoffset < length) { 54 | if (!throwException) { 55 | return null; 56 | } else { 57 | throw new FormatException("chars's length minus " + 58 | tmpoffset + "(" + (chars.Length - tmpoffset) + ") is less than " + 59 | length); 60 | } 61 | } 62 | if (length == 0) { 63 | if (!throwException) { 64 | return null; 65 | } else { 66 | throw new FormatException(); 67 | } 68 | } 69 | var negative = false; 70 | int endStr = tmpoffset + length; 71 | if (chars[tmpoffset] == '+' || chars[tmpoffset] == '-') { 72 | negative = chars[tmpoffset] == '-'; 73 | ++tmpoffset; 74 | } 75 | var numerInt = 0; 76 | EInteger numer = null; 77 | var haveDigits = false; 78 | var haveDenominator = false; 79 | var ndenomInt = 0; 80 | EInteger ndenom = null; 81 | int i = tmpoffset; 82 | if (i + 8 == endStr) { 83 | if ((chars[i] == 'I' || chars[i] == 'i') && 84 | (chars[i + 1] == 'N' || chars[i + 1] == 'n') && 85 | (chars[i + 2] == 'F' || chars[i + 2] == 'f') && 86 | (chars[i + 3] == 'I' || chars[i + 3] == 'i') && (chars[i + 4] == 87 | 'N' || chars[i + 4] == 'n') && (chars[i + 5] == 'I' || chars[i + 5] == 88 | 'i') && 89 | (chars[i + 6] == 'T' || chars[i + 6] == 't') && (chars[i + 7] == 90 | 'Y' || chars[i + 7] == 'y')) { 91 | return negative ? ERational.NegativeInfinity : 92 | ERational.PositiveInfinity; 93 | } 94 | } 95 | if (i + 3 == endStr) { 96 | if ((chars[i] == 'I' || chars[i] == 'i') && 97 | (chars[i + 1] == 'N' || chars[i + 1] == 'n') && (chars[i + 2] == 98 | 'F' || chars[i + 2] == 'f')) { 99 | return negative ? ERational.NegativeInfinity : 100 | ERational.PositiveInfinity; 101 | } 102 | } 103 | var numerStart = 0; 104 | if (i + 3 <= endStr) { 105 | // Quiet NaN 106 | if ((chars[i] == 'N' || chars[i] == 'n') && (chars[i + 1] == 'A' || 107 | chars[i + 108 | 1] == 'a') && (chars[i + 2] == 'N' || chars[i + 2] == 'n')) { 109 | if (i + 3 == endStr) { 110 | return (!negative) ? ERational.NaN : ERational.NaN.Negate(); 111 | } 112 | i += 3; 113 | numerStart = i; 114 | for (; i < endStr; ++i) { 115 | if (chars[i] >= '0' && chars[i] <= '9') { 116 | var thisdigit = (int)(chars[i] - '0'); 117 | if (numerInt <= MaxSafeInt) { 118 | numerInt *= 10; 119 | numerInt += thisdigit; 120 | } 121 | } else { 122 | if (!throwException) { 123 | return null; 124 | } else { 125 | throw new FormatException(); 126 | } 127 | } 128 | } 129 | if (numerInt > MaxSafeInt) { 130 | numer = EInteger.FromSubstring(chars, numerStart, endStr); 131 | return ERational.CreateNaN(numer, false, negative); 132 | } else { 133 | return ERational.CreateNaN( 134 | EInteger.FromInt32(numerInt), 135 | false, 136 | negative); 137 | } 138 | } 139 | } 140 | if (i + 4 <= endStr) { 141 | // Signaling NaN 142 | if ((chars[i] == 'S' || chars[i] == 's') && (chars[i + 1] == 'N' || 143 | chars[i + 144 | 1] == 'n') && (chars[i + 2] == 'A' || chars[i + 2] == 'a') && 145 | (chars[i + 3] == 'N' || chars[i + 3] == 'n')) { 146 | if (i + 4 == endStr) { 147 | return (!negative) ? ERational.SignalingNaN : 148 | ERational.SignalingNaN.Negate(); 149 | } 150 | i += 4; 151 | numerStart = i; 152 | for (; i < endStr; ++i) { 153 | if (chars[i] >= '0' && chars[i] <= '9') { 154 | var thisdigit = (int)(chars[i] - '0'); 155 | haveDigits = haveDigits || thisdigit != 0; 156 | if (numerInt <= MaxSafeInt) { 157 | numerInt *= 10; 158 | numerInt += thisdigit; 159 | } 160 | } else { 161 | if (!throwException) { 162 | return null; 163 | } else { 164 | throw new FormatException(); 165 | } 166 | } 167 | } 168 | int flags3 = (negative ? BigNumberFlags.FlagNegative : 0) | 169 | BigNumberFlags.FlagSignalingNaN; 170 | if (numerInt > MaxSafeInt) { 171 | numer = EInteger.FromSubstring(chars, numerStart, endStr); 172 | return ERational.CreateNaN(numer, true, negative); 173 | } else { 174 | return ERational.CreateNaN( 175 | EInteger.FromInt32(numerInt), 176 | true, 177 | negative); 178 | } 179 | } 180 | } 181 | // Ordinary number 182 | numerStart = i; 183 | int numerEnd = i; 184 | for (; i < endStr; ++i) { 185 | if (chars[i] >= '0' && chars[i] <= '9') { 186 | var thisdigit = (int)(chars[i] - '0'); 187 | numerEnd = i + 1; 188 | if (numerInt <= MaxSafeInt) { 189 | numerInt *= 10; 190 | numerInt += thisdigit; 191 | } 192 | haveDigits = true; 193 | } else if (chars[i] == '/') { 194 | haveDenominator = true; 195 | ++i; 196 | break; 197 | } else { 198 | if (!throwException) { 199 | return null; 200 | } else { 201 | throw new FormatException(); 202 | } 203 | } 204 | } 205 | if (!haveDigits) { 206 | if (!throwException) { 207 | return null; 208 | } else { 209 | throw new FormatException(); 210 | } 211 | } 212 | if (numerInt > MaxSafeInt) { 213 | numer = EInteger.FromSubstring(chars, numerStart, numerEnd); 214 | } 215 | if (haveDenominator) { 216 | EInteger denom = null; 217 | var denomInt = 0; 218 | tmpoffset = 1; 219 | haveDigits = false; 220 | if (i == endStr) { 221 | if (!throwException) { 222 | return null; 223 | } else { 224 | throw new FormatException(); 225 | } 226 | } 227 | numerStart = i; 228 | for (; i < endStr; ++i) { 229 | if (chars[i] >= '0' && chars[i] <= '9') { 230 | haveDigits = true; 231 | var thisdigit = (int)(chars[i] - '0'); 232 | numerEnd = i + 1; 233 | if (denomInt <= MaxSafeInt) { 234 | denomInt *= 10; 235 | denomInt += thisdigit; 236 | } 237 | } else { 238 | if (!throwException) { 239 | return null; 240 | } else { 241 | throw new FormatException(); 242 | } 243 | } 244 | } 245 | if (!haveDigits) { 246 | if (!throwException) { 247 | return null; 248 | } else { 249 | throw new FormatException(); 250 | } 251 | } 252 | if (denomInt > MaxSafeInt) { 253 | denom = EInteger.FromSubstring(chars, numerStart, numerEnd); 254 | } 255 | if (denom == null) { 256 | ndenomInt = denomInt; 257 | } else { 258 | ndenom = denom; 259 | } 260 | } else { 261 | ndenomInt = 1; 262 | } 263 | if (i != endStr) { 264 | if (!throwException) { 265 | return null; 266 | } else { 267 | throw new FormatException(); 268 | } 269 | } 270 | if (ndenom == null ? (ndenomInt == 0) : ndenom.IsZero) { 271 | if (!throwException) { 272 | return null; 273 | } else { 274 | throw new FormatException(); 275 | } 276 | } 277 | ERational erat = ERational.Create( 278 | numer == null ? (EInteger)numerInt : numer, 279 | ndenom == null ? (EInteger)ndenomInt : ndenom); 280 | return negative ? erat.Negate() : erat; 281 | } 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /Numbers/PeterO/Numbers/ERationalTextString.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | 4 | namespace PeterO.Numbers { 5 | internal static class ERationalTextString { 6 | private const int MaxSafeInt = EDecimal.MaxSafeInt; 7 | 8 | public static ERational FromString( 9 | string chars, 10 | int offset, 11 | int length, 12 | bool throwException) { 13 | int tmpoffset = offset; 14 | if (chars == null) { 15 | if (!throwException) { 16 | return null; 17 | } else { 18 | throw new ArgumentNullException(nameof(chars)); 19 | } 20 | } 21 | if (tmpoffset < 0) { 22 | if (!throwException) { 23 | return null; 24 | } else { 25 | throw new FormatException("offset(" + tmpoffset + ") is" + 26 | "\u0020less" + "\u0020than " + "0"); 27 | } 28 | } 29 | if (tmpoffset > chars.Length) { 30 | if (!throwException) { 31 | return null; 32 | } else { 33 | throw new FormatException("offset(" + tmpoffset + ") is" + 34 | "\u0020more" + "\u0020than " + chars.Length); 35 | } 36 | } 37 | if (length < 0) { 38 | if (!throwException) { 39 | return null; 40 | } else { 41 | throw new FormatException("length(" + length + ") is less than " + 42 | "0"); 43 | } 44 | } 45 | if (length > chars.Length) { 46 | if (!throwException) { 47 | return null; 48 | } else { 49 | throw new FormatException("length(" + length + ") is more than " + 50 | chars.Length); 51 | } 52 | } 53 | if (chars.Length - tmpoffset < length) { 54 | if (!throwException) { 55 | return null; 56 | } else { 57 | throw new FormatException("chars's length minus " + 58 | tmpoffset + "(" + (chars.Length - tmpoffset) + ") is less than " + 59 | length); 60 | } 61 | } 62 | if (length == 0) { 63 | if (!throwException) { 64 | return null; 65 | } else { 66 | throw new FormatException(); 67 | } 68 | } 69 | var negative = false; 70 | int endStr = tmpoffset + length; 71 | if (chars[tmpoffset] == '+' || chars[tmpoffset] == '-') { 72 | negative = chars[tmpoffset] == '-'; 73 | ++tmpoffset; 74 | } 75 | var numerInt = 0; 76 | EInteger numer = null; 77 | var haveDigits = false; 78 | var haveDenominator = false; 79 | var ndenomInt = 0; 80 | EInteger ndenom = null; 81 | int i = tmpoffset; 82 | if (i + 8 == endStr) { 83 | if ((chars[i] == 'I' || chars[i] == 'i') && 84 | (chars[i + 1] == 'N' || chars[i + 1] == 'n') && 85 | (chars[i + 2] == 'F' || chars[i + 2] == 'f') && 86 | (chars[i + 3] == 'I' || chars[i + 3] == 'i') && (chars[i + 4] == 87 | 'N' || chars[i + 4] == 'n') && (chars[i + 5] == 'I' || chars[i + 5] == 88 | 'i') && 89 | (chars[i + 6] == 'T' || chars[i + 6] == 't') && (chars[i + 7] == 90 | 'Y' || chars[i + 7] == 'y')) { 91 | return negative ? ERational.NegativeInfinity : 92 | ERational.PositiveInfinity; 93 | } 94 | } 95 | if (i + 3 == endStr) { 96 | if ((chars[i] == 'I' || chars[i] == 'i') && 97 | (chars[i + 1] == 'N' || chars[i + 1] == 'n') && (chars[i + 2] == 98 | 'F' || chars[i + 2] == 'f')) { 99 | return negative ? ERational.NegativeInfinity : 100 | ERational.PositiveInfinity; 101 | } 102 | } 103 | var numerStart = 0; 104 | if (i + 3 <= endStr) { 105 | // Quiet NaN 106 | if ((chars[i] == 'N' || chars[i] == 'n') && (chars[i + 1] == 'A' || 107 | chars[i + 108 | 1] == 'a') && (chars[i + 2] == 'N' || chars[i + 2] == 'n')) { 109 | if (i + 3 == endStr) { 110 | return (!negative) ? ERational.NaN : ERational.NaN.Negate(); 111 | } 112 | i += 3; 113 | numerStart = i; 114 | for (; i < endStr; ++i) { 115 | if (chars[i] >= '0' && chars[i] <= '9') { 116 | var thisdigit = (int)(chars[i] - '0'); 117 | if (numerInt <= MaxSafeInt) { 118 | numerInt *= 10; 119 | numerInt += thisdigit; 120 | } 121 | } else { 122 | if (!throwException) { 123 | return null; 124 | } else { 125 | throw new FormatException(); 126 | } 127 | } 128 | } 129 | if (numerInt > MaxSafeInt) { 130 | numer = EInteger.FromSubstring(chars, numerStart, endStr); 131 | return ERational.CreateNaN(numer, false, negative); 132 | } else { 133 | return ERational.CreateNaN( 134 | EInteger.FromInt32(numerInt), 135 | false, 136 | negative); 137 | } 138 | } 139 | } 140 | if (i + 4 <= endStr) { 141 | // Signaling NaN 142 | if ((chars[i] == 'S' || chars[i] == 's') && (chars[i + 1] == 'N' || 143 | chars[i + 144 | 1] == 'n') && (chars[i + 2] == 'A' || chars[i + 2] == 'a') && 145 | (chars[i + 3] == 'N' || chars[i + 3] == 'n')) { 146 | if (i + 4 == endStr) { 147 | return (!negative) ? ERational.SignalingNaN : 148 | ERational.SignalingNaN.Negate(); 149 | } 150 | i += 4; 151 | numerStart = i; 152 | for (; i < endStr; ++i) { 153 | if (chars[i] >= '0' && chars[i] <= '9') { 154 | var thisdigit = (int)(chars[i] - '0'); 155 | haveDigits = haveDigits || thisdigit != 0; 156 | if (numerInt <= MaxSafeInt) { 157 | numerInt *= 10; 158 | numerInt += thisdigit; 159 | } 160 | } else { 161 | if (!throwException) { 162 | return null; 163 | } else { 164 | throw new FormatException(); 165 | } 166 | } 167 | } 168 | int flags3 = (negative ? BigNumberFlags.FlagNegative : 0) | 169 | BigNumberFlags.FlagSignalingNaN; 170 | if (numerInt > MaxSafeInt) { 171 | numer = EInteger.FromSubstring(chars, numerStart, endStr); 172 | return ERational.CreateNaN(numer, true, negative); 173 | } else { 174 | return ERational.CreateNaN( 175 | EInteger.FromInt32(numerInt), 176 | true, 177 | negative); 178 | } 179 | } 180 | } 181 | // Ordinary number 182 | numerStart = i; 183 | int numerEnd = i; 184 | for (; i < endStr; ++i) { 185 | if (chars[i] >= '0' && chars[i] <= '9') { 186 | var thisdigit = (int)(chars[i] - '0'); 187 | numerEnd = i + 1; 188 | if (numerInt <= MaxSafeInt) { 189 | numerInt *= 10; 190 | numerInt += thisdigit; 191 | } 192 | haveDigits = true; 193 | } else if (chars[i] == '/') { 194 | haveDenominator = true; 195 | ++i; 196 | break; 197 | } else { 198 | if (!throwException) { 199 | return null; 200 | } else { 201 | throw new FormatException(); 202 | } 203 | } 204 | } 205 | if (!haveDigits) { 206 | if (!throwException) { 207 | return null; 208 | } else { 209 | throw new FormatException(); 210 | } 211 | } 212 | if (numerInt > MaxSafeInt) { 213 | numer = EInteger.FromSubstring(chars, numerStart, numerEnd); 214 | } 215 | if (haveDenominator) { 216 | EInteger denom = null; 217 | var denomInt = 0; 218 | tmpoffset = 1; 219 | haveDigits = false; 220 | if (i == endStr) { 221 | if (!throwException) { 222 | return null; 223 | } else { 224 | throw new FormatException(); 225 | } 226 | } 227 | numerStart = i; 228 | for (; i < endStr; ++i) { 229 | if (chars[i] >= '0' && chars[i] <= '9') { 230 | haveDigits = true; 231 | var thisdigit = (int)(chars[i] - '0'); 232 | numerEnd = i + 1; 233 | if (denomInt <= MaxSafeInt) { 234 | denomInt *= 10; 235 | denomInt += thisdigit; 236 | } 237 | } else { 238 | if (!throwException) { 239 | return null; 240 | } else { 241 | throw new FormatException(); 242 | } 243 | } 244 | } 245 | if (!haveDigits) { 246 | if (!throwException) { 247 | return null; 248 | } else { 249 | throw new FormatException(); 250 | } 251 | } 252 | if (denomInt > MaxSafeInt) { 253 | denom = EInteger.FromSubstring(chars, numerStart, numerEnd); 254 | } 255 | if (denom == null) { 256 | ndenomInt = denomInt; 257 | } else { 258 | ndenom = denom; 259 | } 260 | } else { 261 | ndenomInt = 1; 262 | } 263 | if (i != endStr) { 264 | if (!throwException) { 265 | return null; 266 | } else { 267 | throw new FormatException(); 268 | } 269 | } 270 | if (ndenom == null ? (ndenomInt == 0) : ndenom.IsZero) { 271 | if (!throwException) { 272 | return null; 273 | } else { 274 | throw new FormatException(); 275 | } 276 | } 277 | ERational erat = ERational.Create( 278 | numer == null ? (EInteger)numerInt : numer, 279 | ndenom == null ? (EInteger)ndenomInt : ndenom); 280 | return negative ? erat.Negate() : erat; 281 | } 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /Numbers/PeterO/Numbers/ERounding.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Written by Peter O. 3 | Any copyright to this work is released to the Public Domain. 4 | In case this is not possible, this work is also 5 | licensed under the Unlicense: https://unlicense.org/ 6 | 7 | */ 8 | 9 | using System; 10 | 11 | namespace PeterO.Numbers { 12 | /// Specifies the mode to use when "shortening" numbers that 13 | /// otherwise can't fit a given number of digits, so that the shortened 14 | /// number has about the same value. This "shortening" is known as 15 | /// rounding. (The "E" stands for "extended", and has this prefix to 16 | /// group it with the other classes common to this library, 17 | /// particularly EDecimal, EFloat, and ERational.). 18 | public enum ERounding { 19 | /// Indicates that rounding will not be used. If rounding to 20 | /// an inexact value is required, the rounding operation will report an 21 | /// error. 22 | None, 23 | 24 | /// If there is a fractional part, the number is rounded to 25 | /// the closest representable number away from zero. 26 | Up, 27 | 28 | /// The fractional part is discarded (the number is 29 | /// truncated). 30 | Down, 31 | 32 | /// Rounded to the nearest number; if the fractional part is 33 | /// exactly half, the number is rounded to the closest representable 34 | /// number away from zero. This is the most familiar rounding mode for 35 | /// many people. 36 | HalfUp, 37 | 38 | /// Rounded to the nearest number; if the fractional part is 39 | /// exactly half, it is discarded. 40 | HalfDown, 41 | 42 | /// Rounded to the nearest number; if the fractional part is 43 | /// exactly half, the number is rounded to the closest representable 44 | /// number that is even. This is sometimes also known as "banker's 45 | /// rounding". 46 | HalfEven, 47 | 48 | /// If there is a fractional part, the number is rounded to 49 | /// the highest representable number that's closest to it. 50 | Ceiling, 51 | 52 | /// If there is a fractional part, the number is rounded to 53 | /// the lowest representable number that's closest to it. 54 | Floor, 55 | 56 | /// If there is a fractional part and the whole number part is 57 | /// even, the number is rounded to the closest representable odd number 58 | /// away from zero. 59 | [Obsolete("Consider using ERounding.OddOrZeroFiveUp instead.")] 60 | Odd, 61 | 62 | /// If there is a fractional part and if the last digit before 63 | /// rounding is 0 or half the radix, the number is rounded to the 64 | /// closest representable number away from zero; otherwise the 65 | /// fractional part is discarded. In overflow, the fractional part is 66 | /// always discarded. 67 | [Obsolete("Use ERounding.OddOrZeroFiveUp instead.")] 68 | ZeroFiveUp, 69 | 70 | /// For binary floating point numbers, this is the same as 71 | /// Odd. For other bases (including decimal numbers), this is the same 72 | /// as ZeroFiveUp. This rounding mode is useful for rounding 73 | /// intermediate results at a slightly higher precision (at least 2 74 | /// bits more for binary) than the final precision. 75 | OddOrZeroFiveUp, 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Numbers/PeterO/Numbers/ETrapException.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Written by Peter O. 3 | Any copyright to this work is released to the Public Domain. 4 | In case this is not possible, this work is also 5 | licensed under the Unlicense: https://unlicense.org/ 6 | 7 | */ 8 | using System; 9 | 10 | namespace PeterO.Numbers { 11 | /// Exception thrown for arithmetic trap errors. (The "E" 12 | /// stands for "extended", and has this prefix to group it with the 13 | /// other classes common to this library, particularly EDecimal, 14 | /// EFloat, and ERational.). 15 | /// This library may throw exceptions of this type in certain 16 | /// cases, notably when errors occur, and may supply messages to those 17 | /// exceptions (the message can be accessed through the Message 18 | /// property in.NET or the getMessage() method in Java). These 19 | /// messages are intended to be read by humans to help diagnose the 20 | /// error (or other cause of the exception); they are not intended to 21 | /// be parsed by computer programs, and the exact text of the messages 22 | /// may change at any time between versions of this 23 | /// library. 24 | #if NET20 || NET40 25 | [Serializable] 26 | #endif 27 | public sealed class ETrapException : ArithmeticException { 28 | private readonly Object result; 29 | private readonly EContext ctx; 30 | 31 | /// Gets the arithmetic context used during the operation that 32 | /// triggered the trap. May be null. 33 | /// The arithmetic context used during the operation that 34 | /// triggered the trap. May be null. 35 | public EContext Context { 36 | get { 37 | return this.ctx; 38 | } 39 | } 40 | 41 | private readonly int error; 42 | 43 | private readonly int errors; 44 | 45 | /// Initializes a new instance of the 46 | /// class. 47 | public ETrapException() : this(FlagToMessage(EContext.FlagInvalid)) { 48 | } 49 | 50 | /// Initializes a new instance of the 51 | /// class. 52 | /// The parameter is a 53 | /// text string. 54 | public ETrapException(string message) : base(message) { 55 | this.error = EContext.FlagInvalid; 56 | this.errors = EContext.FlagInvalid; 57 | this.ctx = null; 58 | this.result = null; 59 | } 60 | 61 | /// Initializes a new instance of the 62 | /// class. 63 | /// The parameter is a 64 | /// text string. 65 | /// The parameter is an Exception object. 67 | public ETrapException(string message, Exception innerException) 68 | : base(message, innerException) { 69 | this.error = EContext.FlagInvalid; 70 | this.errors = EContext.FlagInvalid; 71 | this.ctx = null; 72 | this.result = null; 73 | } 74 | 75 | /// Gets the defined result of the operation that caused the 76 | /// trap. 77 | /// The defined result of the operation that caused the 78 | /// trap. 79 | public Object Result { 80 | get { 81 | return this.result; 82 | } 83 | } 84 | 85 | /// Gets the flag that specifies the primary kind of error in 86 | /// one or more operations (EContext.FlagXXX). This will only be one 87 | /// flag, such as FlagInexact or FlagSubnormal. 88 | /// The flag that specifies the primary kind of error in one or 89 | /// more operations. 90 | public int Error { 91 | get { 92 | return this.error; 93 | } 94 | } 95 | 96 | /// Gets the flags that were signaled as the result of one or 97 | /// more operations. This includes the flag specified in the "flag" 98 | /// parameter, but can include other flags. For instance, if "flag" is 99 | /// EContext.FlagInexact, this parameter might be 100 | /// EContext.FlagInexact | EContext.FlagRounded. 101 | /// The flags that specify the errors in one or more 102 | /// operations. 103 | public int Errors { 104 | get { 105 | return this.errors; 106 | } 107 | } 108 | 109 | /// Returns whether this trap exception specifies all the 110 | /// flags given. (Flags are signaled in a trap exception as the result 111 | /// of one or more operations involving arbitrary-precision numbers, 112 | /// such as multiplication of two EDecimals.). 113 | /// A combination of one or more flags, such as 114 | /// EContext.FlagInexact | EContext.FlagRounded. 115 | /// True if this exception pertains to all of the flags given 116 | /// in ; otherwise, false. 117 | public bool HasError(int flag) { 118 | return (this.Error & flag) == flag; 119 | } 120 | 121 | private static string FlagToMessage(int flags) { 122 | var sb = new System.Text.StringBuilder(); 123 | var first = true; 124 | for (var i = 0; i < 32; ++i) { 125 | int flag = 1 << i; 126 | if ((flags & flag) != 0) { 127 | if (!first) { 128 | sb.Append(", "); 129 | } 130 | first = false; 131 | string str = (flag == EContext.FlagClamped) ? "Clamped" : ((flag == 132 | EContext.FlagDivideByZero) ? "DivideByZero" : ((flag == 133 | EContext.FlagInexact) ? "Inexact" : ((flag == 134 | EContext.FlagInvalid) ? "Invalid" : ((flag == 135 | EContext.FlagOverflow) ? "Overflow" : ((flag == 136 | EContext.FlagRounded) ? "Rounded" : ((flag == 137 | EContext.FlagSubnormal) ? "Subnormal" : ((flag == 138 | EContext.FlagUnderflow) ? "Underflow" : "Trap"))))))); 139 | sb.Append(str); 140 | } 141 | } 142 | return sb.ToString(); 143 | } 144 | 145 | /// Initializes a new instance of the 146 | /// class. 147 | /// The flag that specifies the kind of error from 148 | /// one or more operations (EContext.FlagXXX). This will only be one 149 | /// flag, such as FlagInexact or FlagSubnormal. 150 | /// The arithmetic context used during the operation 151 | /// that triggered the trap. Can be null. 152 | /// The defined result of the operation that 153 | /// caused the trap. 154 | public ETrapException(int flag, EContext ctx, Object result) 155 | : this(flag, flag, ctx, result) { 156 | } 157 | 158 | /// Initializes a new instance of the 159 | /// class. 160 | /// Specifies the flags that were signaled as the 161 | /// result of one or more operations. This includes the flag specified 162 | /// in the "flag" parameter, but can include other flags. For instance, 163 | /// if "flag" is EContext.FlagInexact, this parameter might be 164 | /// EContext.FlagInexact | EContext.FlagRounded. 165 | /// Specifies the flag that specifies the primary 166 | /// kind of error from one or more operations (EContext.FlagXXX). This 167 | /// will only be one flag, such as FlagInexact or 168 | /// FlagSubnormal. 169 | /// The arithmetic context used during the operation 170 | /// that triggered the trap. Can be null. 171 | /// The defined result of the operation that 172 | /// caused the trap. 173 | /// The parameter doesn't include all the flags in the parameter. 176 | public ETrapException(int flags, int flag, EContext ctx, Object result) 177 | : base(FlagToMessage(flags)) { 178 | if ((flags & flag) != flag) { 179 | throw new ArgumentException("flags doesn't include flag"); 180 | } 181 | this.error = flag; 182 | this.errors = flags; 183 | this.ctx = (ctx == null) ? null : ctx.Copy(); 184 | this.result = result; 185 | } 186 | 187 | #if NET20 || NET40 188 | private ETrapException( 189 | System.Runtime.Serialization.SerializationInfo info, 190 | System.Runtime.Serialization.StreamingContext context) 191 | : base(info, context) { 192 | } 193 | #endif 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /Numbers/PeterO/Numbers/ExtendedOrSimpleRadixMath.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Written by Peter O. 3 | Any copyright to this work is released to the Public Domain. 4 | In case this is not possible, this work is also 5 | licensed under the Unlicense: https://unlicense.org/ 6 | 7 | */ 8 | using System; 9 | 10 | namespace PeterO.Numbers { 11 | internal class ExtendedOrSimpleRadixMath : IRadixMath { 12 | private readonly RadixMath ext; 13 | private readonly SimpleRadixMath simp; 14 | 15 | public ExtendedOrSimpleRadixMath(IRadixMathHelper helper) { 16 | this.ext = new RadixMath(helper); 17 | this.simp = new SimpleRadixMath(this.ext); 18 | } 19 | 20 | public IRadixMathHelper GetHelper() { 21 | // Both RadixMath implementations return the 22 | // same helper, so use the ext implementation 23 | return this.ext.GetHelper(); 24 | } 25 | 26 | public T DivideToIntegerNaturalScale( 27 | T thisValue, 28 | T divisor, 29 | EContext ctx) { 30 | return (ctx == null || !ctx.IsSimplified) ? 31 | this.ext.DivideToIntegerNaturalScale(thisValue, divisor, ctx) : 32 | this.simp.DivideToIntegerNaturalScale(thisValue, divisor, ctx); 33 | } 34 | 35 | public T DivideToIntegerZeroScale( 36 | T thisValue, 37 | T divisor, 38 | EContext ctx) { 39 | return (ctx == null || !ctx.IsSimplified) ? 40 | this.ext.DivideToIntegerZeroScale(thisValue, divisor, ctx) : 41 | this.simp.DivideToIntegerZeroScale(thisValue, divisor, ctx); 42 | } 43 | 44 | public T Abs(T value, EContext ctx) { 45 | return (ctx == null || !ctx.IsSimplified) ? this.ext.Abs(value, ctx) : 46 | this.simp.Abs(value, ctx); 47 | } 48 | 49 | public T Negate(T value, EContext ctx) { 50 | return (ctx == null || !ctx.IsSimplified) ? this.ext.Negate(value, ctx) : 51 | this.simp.Negate(value, ctx); 52 | } 53 | 54 | public T Remainder( 55 | T thisValue, 56 | T divisor, 57 | EContext ctx, 58 | bool roundAfterDivide) { 59 | return (ctx == null || !ctx.IsSimplified) ? 60 | this.ext.Remainder(thisValue, divisor, ctx, roundAfterDivide) : 61 | this.simp.Remainder(thisValue, divisor, ctx, roundAfterDivide); 62 | } 63 | 64 | public T RemainderNear(T thisValue, T divisor, EContext ctx) { 65 | return (ctx == null || !ctx.IsSimplified) ? 66 | this.ext.RemainderNear(thisValue, divisor, ctx) : 67 | this.simp.RemainderNear(thisValue, divisor, ctx); 68 | } 69 | 70 | public T Pi(EContext ctx) { 71 | return (!ctx.IsSimplified) ? this.ext.Pi(ctx) : this.simp.Pi(ctx); 72 | } 73 | 74 | public T Power(T thisValue, T pow, EContext ctx) { 75 | return ( 76 | ctx == null || !ctx.IsSimplified) ? this.ext.Power( 77 | thisValue, 78 | pow, 79 | ctx) : this.simp.Power(thisValue, pow, ctx); 80 | } 81 | 82 | public T Ln(T thisValue, EContext ctx) { 83 | return (ctx == null || !ctx.IsSimplified) ? this.ext.Ln(thisValue, ctx) : 84 | this.simp.Ln(thisValue, ctx); 85 | } 86 | 87 | public T Exp(T thisValue, EContext ctx) { 88 | return (ctx == null || !ctx.IsSimplified) ? this.ext.Exp(thisValue, 89 | ctx) : this.simp.Exp(thisValue, ctx); 90 | } 91 | 92 | public T SquareRoot(T thisValue, EContext ctx) { 93 | return (ctx == null || !ctx.IsSimplified) ? 94 | this.ext.SquareRoot( 95 | thisValue, 96 | ctx) : this.simp.SquareRoot( 97 | thisValue, 98 | ctx); 99 | } 100 | 101 | public T NextMinus(T thisValue, EContext ctx) { 102 | return (ctx == null || !ctx.IsSimplified) ? 103 | this.ext.NextMinus(thisValue, ctx) : this.simp.NextMinus( 104 | thisValue, 105 | ctx); 106 | } 107 | 108 | public T NextToward(T thisValue, T otherValue, EContext ctx) { 109 | return (ctx == null || !ctx.IsSimplified) ? 110 | this.ext.NextToward(thisValue, otherValue, ctx) : 111 | this.simp.NextToward(thisValue, otherValue, ctx); 112 | } 113 | 114 | public T NextPlus(T thisValue, EContext ctx) { 115 | return (ctx == null || !ctx.IsSimplified) ? 116 | this.ext.NextPlus(thisValue, ctx) : this.simp.NextPlus(thisValue, 117 | ctx); 118 | } 119 | 120 | public T DivideToExponent( 121 | T thisValue, 122 | T divisor, 123 | EInteger desiredExponent, 124 | EContext ctx) { 125 | return (ctx == null || !ctx.IsSimplified) ? 126 | this.ext.DivideToExponent(thisValue, divisor, desiredExponent, ctx) : 127 | this.simp.DivideToExponent(thisValue, divisor, desiredExponent, ctx); 128 | } 129 | public T Divide(T thisValue, T divisor, EContext ctx) { 130 | return ( 131 | ctx == null || !ctx.IsSimplified) ? this.ext.Divide( 132 | thisValue, 133 | divisor, 134 | ctx) : this.simp.Divide(thisValue, divisor, ctx); 135 | } 136 | 137 | public T MinMagnitude(T a, T b, EContext ctx) { 138 | return ( 139 | ctx == null || !ctx.IsSimplified) ? this.ext.MinMagnitude( 140 | a, 141 | b, 142 | ctx) : this.simp.MinMagnitude(a, b, ctx); 143 | } 144 | 145 | public T MaxMagnitude(T a, T b, EContext ctx) { 146 | return ( 147 | ctx == null || !ctx.IsSimplified) ? this.ext.MaxMagnitude( 148 | a, 149 | b, 150 | ctx) : this.simp.MaxMagnitude(a, b, ctx); 151 | } 152 | 153 | public T Max(T a, T b, EContext ctx) { 154 | return (ctx == null || !ctx.IsSimplified) ? this.ext.Max(a, b, ctx) : 155 | this.simp.Max(a, b, ctx); 156 | } 157 | 158 | public T Min(T a, T b, EContext ctx) { 159 | return (ctx == null || !ctx.IsSimplified) ? this.ext.Min(a, b, ctx) : 160 | this.simp.Min(a, b, ctx); 161 | } 162 | 163 | public T Multiply(T thisValue, T other, EContext ctx) { 164 | return (ctx == null || !ctx.IsSimplified) ? 165 | this.ext.Multiply(thisValue, other, ctx) : 166 | this.simp.Multiply(thisValue, other, ctx); 167 | } 168 | 169 | public T MultiplyAndAdd( 170 | T thisValue, 171 | T multiplicand, 172 | T augend, 173 | EContext ctx) { 174 | return (ctx == null || !ctx.IsSimplified) ? 175 | this.ext.MultiplyAndAdd(thisValue, multiplicand, augend, ctx) : 176 | this.simp.MultiplyAndAdd(thisValue, multiplicand, augend, ctx); 177 | } 178 | 179 | public T Plus(T thisValue, EContext ctx) { 180 | return ( 181 | ctx == null || !ctx.IsSimplified) ? this.ext.Plus( 182 | thisValue, 183 | ctx) : this.simp.Plus(thisValue, ctx); 184 | } 185 | 186 | public T RoundToPrecision(T thisValue, EContext ctx) { 187 | return (ctx == null || !ctx.IsSimplified) ? 188 | this.ext.RoundToPrecision(thisValue, ctx) : 189 | this.simp.RoundToPrecision(thisValue, ctx); 190 | } 191 | 192 | public T RoundAfterConversion(T thisValue, EContext ctx) { 193 | return (ctx == null || !ctx.IsSimplified) ? 194 | this.ext.RoundAfterConversion(thisValue, ctx) : 195 | this.simp.RoundAfterConversion(thisValue, ctx); 196 | } 197 | 198 | public T SignalOverflow(EContext ctx, bool neg) { 199 | return (ctx == null || !ctx.IsSimplified) ? 200 | this.ext.SignalOverflow(ctx, neg) : this.simp.SignalOverflow(ctx, neg); 201 | } 202 | 203 | public T Quantize(T thisValue, T otherValue, EContext ctx) { 204 | return (ctx == null || !ctx.IsSimplified) ? 205 | this.ext.Quantize(thisValue, otherValue, ctx) : 206 | this.simp.Quantize(thisValue, otherValue, ctx); 207 | } 208 | 209 | public T RoundToExponentExact( 210 | T thisValue, 211 | EInteger expOther, 212 | EContext ctx) { 213 | return (ctx == null || !ctx.IsSimplified) ? 214 | this.ext.RoundToExponentExact(thisValue, expOther, ctx) : 215 | this.simp.RoundToExponentExact(thisValue, expOther, ctx); 216 | } 217 | 218 | public T RoundToExponentSimple( 219 | T thisValue, 220 | EInteger expOther, 221 | EContext ctx) { 222 | return (ctx == null || !ctx.IsSimplified) ? 223 | this.ext.RoundToExponentSimple(thisValue, expOther, ctx) : 224 | this.simp.RoundToExponentSimple(thisValue, expOther, ctx); 225 | } 226 | 227 | public T RoundToExponentNoRoundedFlag( 228 | T thisValue, 229 | EInteger exponent, 230 | EContext ctx) { 231 | return (ctx == null || !ctx.IsSimplified) ? 232 | this.ext.RoundToExponentNoRoundedFlag(thisValue, exponent, ctx) : 233 | this.simp.RoundToExponentNoRoundedFlag(thisValue, exponent, ctx); 234 | } 235 | 236 | public T Reduce(T thisValue, EContext ctx) { 237 | return ( 238 | ctx == null || !ctx.IsSimplified) ? this.ext.Reduce( 239 | thisValue, 240 | ctx) : this.simp.Reduce(thisValue, ctx); 241 | } 242 | 243 | public T Add(T thisValue, T other, EContext ctx) { 244 | return ( 245 | ctx == null || !ctx.IsSimplified) ? this.ext.Add( 246 | thisValue, 247 | other, 248 | ctx) : this.simp.Add(thisValue, other, ctx); 249 | } 250 | 251 | public T AddEx( 252 | T thisValue, 253 | T other, 254 | EContext ctx, 255 | bool roundToOperandPrecision) { 256 | return ( 257 | ctx == null || !ctx.IsSimplified) ? this.ext.AddEx( 258 | thisValue, 259 | other, 260 | ctx, 261 | roundToOperandPrecision) : 262 | this.simp.AddEx(thisValue, other, ctx, roundToOperandPrecision); 263 | } 264 | 265 | public T CompareToWithContext( 266 | T thisValue, 267 | T otherValue, 268 | bool treatQuietNansAsSignaling, 269 | EContext ctx) { 270 | return (ctx == null || !ctx.IsSimplified) ? 271 | this.ext.CompareToWithContext( 272 | thisValue, 273 | otherValue, 274 | treatQuietNansAsSignaling, 275 | ctx) : this.simp.CompareToWithContext( 276 | thisValue, 277 | otherValue, 278 | treatQuietNansAsSignaling, 279 | ctx); 280 | } 281 | 282 | public int CompareTo(T thisValue, T otherValue) { 283 | return this.ext.CompareTo(thisValue, otherValue); 284 | } 285 | } 286 | } 287 | -------------------------------------------------------------------------------- /Numbers/PeterO/Numbers/Extras.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Written by Peter O. 3 | Any copyright to this work is released to the Public Domain. 4 | In case this is not possible, this work is also 5 | licensed under the Unlicense: https://unlicense.org/ 6 | 7 | */ 8 | using System; 9 | 10 | namespace PeterO.Numbers { 11 | internal static class Extras { 12 | public static byte[] CharsConcat( 13 | byte[] c1, 14 | int offset1, 15 | int length1, 16 | byte[] c2, 17 | int offset2, 18 | int length2) { 19 | var chars = new byte[length1 + length2]; 20 | Array.Copy(c1, offset1, chars, 0, length1); 21 | Array.Copy(c2, offset2, chars, length1, length2); 22 | return chars; 23 | } 24 | public static string CharsConcat( 25 | string s1, 26 | int offset1, 27 | int length1, 28 | string s2, 29 | int offset2, 30 | int length2) { 31 | // Console.WriteLine(s1.Substring(offset1, length1)); 32 | // Console.WriteLine(s2.Substring(offset2, length2)); 33 | return s1.Substring(offset1, length1) + s2.Substring(offset2, length2); 34 | } 35 | 36 | public static char[] CharsConcat( 37 | char[] c1, 38 | int offset1, 39 | int length1, 40 | char[] c2, 41 | int offset2, 42 | int length2) { 43 | var chars = new char[length1 + length2]; 44 | Array.Copy(c1, offset1, chars, 0, length1); 45 | Array.Copy(c2, offset2, chars, length1, length2); 46 | return chars; 47 | } 48 | 49 | public static int[] DoubleToIntegers(double dbl) { 50 | long value = BitConverter.ToInt64( 51 | BitConverter.GetBytes((double)dbl), 52 | 0); 53 | var ret = new int[2]; 54 | ret[0] = unchecked((int)(value & 0xffffffffL)); 55 | ret[1] = unchecked((int)((value >> 32) & 0xffffffffL)); 56 | return ret; 57 | } 58 | 59 | public static double IntegersToDouble(int[] integers) { 60 | // NOTE: least significant word first 61 | return IntegersToDouble(integers[0], integers[1]); 62 | } 63 | 64 | public static double IntegersToDouble(int lsw, int msw) { 65 | // NOTE: least significant word first 66 | long value = ((long)lsw) & 0xffffffffL; 67 | value |= (((long)msw) & 0xffffffffL) << 32; 68 | return BitConverter.ToDouble(BitConverter.GetBytes((long)value), 0); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Numbers/PeterO/Numbers/IRadixMath.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Written by Peter O. 3 | Any copyright to this work is released to the Public Domain. 4 | In case this is not possible, this work is also 5 | licensed under the Unlicense: https://unlicense.org/ 6 | 7 | */ 8 | using System; 9 | 10 | namespace PeterO.Numbers { 11 | internal interface IRadixMath { 12 | IRadixMathHelper GetHelper(); 13 | 14 | T DivideToIntegerNaturalScale(T thisValue, T divisor, EContext ctx); 15 | 16 | T DivideToIntegerZeroScale(T thisValue, T divisor, EContext ctx); 17 | 18 | T Abs(T value, EContext ctx); 19 | 20 | T Negate(T value, EContext ctx); 21 | 22 | T Remainder(T thisValue, T divisor, EContext ctx, bool roundAfterDivide); 23 | 24 | T RemainderNear(T thisValue, T divisor, EContext ctx); 25 | 26 | T Pi(EContext ctx); 27 | 28 | T Power(T thisValue, T pow, EContext ctx); 29 | 30 | T Ln(T thisValue, EContext ctx); 31 | 32 | T Exp(T thisValue, EContext ctx); 33 | 34 | T SquareRoot(T thisValue, EContext ctx); 35 | 36 | T NextMinus(T thisValue, EContext ctx); 37 | 38 | T NextToward(T thisValue, T otherValue, EContext ctx); 39 | 40 | T NextPlus(T thisValue, EContext ctx); 41 | 42 | T DivideToExponent( 43 | T thisValue, 44 | T divisor, 45 | EInteger desiredExponent, 46 | EContext ctx); 47 | 48 | T Divide(T thisValue, T divisor, EContext ctx); 49 | 50 | T MinMagnitude(T a, T b, EContext ctx); 51 | 52 | T MaxMagnitude(T a, T b, EContext ctx); 53 | 54 | T Max(T a, T b, EContext ctx); 55 | 56 | T Min(T a, T b, EContext ctx); 57 | 58 | T Multiply(T thisValue, T other, EContext ctx); 59 | 60 | T MultiplyAndAdd( 61 | T thisValue, 62 | T multiplicand, 63 | T augend, 64 | EContext ctx); 65 | 66 | T Plus(T thisValue, EContext ctx); 67 | 68 | T RoundToPrecision(T thisValue, EContext ctx); 69 | 70 | T RoundAfterConversion(T thisValue, EContext ctx); 71 | 72 | T SignalOverflow(EContext ctx, bool neg); 73 | 74 | T Quantize(T thisValue, T otherValue, EContext ctx); 75 | 76 | T RoundToExponentExact( 77 | T thisValue, 78 | EInteger expOther, 79 | EContext ctx); 80 | 81 | T RoundToExponentSimple( 82 | T thisValue, 83 | EInteger expOther, 84 | EContext ctx); 85 | 86 | T RoundToExponentNoRoundedFlag( 87 | T thisValue, 88 | EInteger exponent, 89 | EContext ctx); 90 | 91 | T Reduce(T thisValue, EContext ctx); 92 | 93 | T Add(T thisValue, T other, EContext ctx); 94 | 95 | T AddEx( 96 | T thisValue, 97 | T other, 98 | EContext ctx, 99 | bool roundToOperandPrecision); 100 | 101 | T CompareToWithContext( 102 | T thisValue, 103 | T otherValue, 104 | bool treatQuietNansAsSignaling, 105 | EContext ctx); 106 | 107 | int CompareTo(T thisValue, T otherValue); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /Numbers/PeterO/Numbers/IRadixMathHelper.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Written by Peter O. 3 | Any copyright to this work is released to the Public Domain. 4 | In case this is not possible, this work is also 5 | licensed under the Unlicense: https://unlicense.org/ 6 | 7 | */ 8 | using System; 9 | 10 | namespace PeterO.Numbers { 11 | internal interface IRadixMathHelper { 12 | int GetRadix(); 13 | 14 | int GetArithmeticSupport(); 15 | 16 | int GetSign(T value); 17 | 18 | int GetFlags(T value); 19 | 20 | EInteger GetMantissa(T value); 21 | 22 | EInteger GetExponent(T value); 23 | 24 | FastIntegerFixed GetMantissaFastInt(T value); 25 | 26 | FastIntegerFixed GetExponentFastInt(T value); 27 | 28 | T ValueOf(int val); 29 | 30 | T CreateNewWithFlags(EInteger mantissa, EInteger exponent, int flags); 31 | 32 | T CreateNewWithFlagsFastInt( 33 | FastIntegerFixed mantissa, 34 | FastIntegerFixed exponent, 35 | int flags); 36 | 37 | IShiftAccumulator CreateShiftAccumulatorWithDigits( 38 | EInteger value, 39 | int lastDigit, 40 | int olderDigits); 41 | 42 | IShiftAccumulator CreateShiftAccumulatorWithDigitsFastInt( 43 | FastIntegerFixed value, 44 | int lastDigit, 45 | int olderDigits); 46 | 47 | FastInteger DivisionShift(EInteger num, EInteger den); 48 | 49 | FastInteger GetDigitLength(EInteger ei); 50 | 51 | EInteger MultiplyByRadixPower(EInteger value, FastInteger power); 52 | 53 | FastIntegerFixed MultiplyByRadixPowerFastInt( 54 | FastIntegerFixed value, 55 | FastIntegerFixed power); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Numbers/PeterO/Numbers/IShiftAccumulator.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Written by Peter O. 3 | Any copyright to this work is released to the Public Domain. 4 | In case this is not possible, this work is also 5 | licensed under the Unlicense: https://unlicense.org/ 6 | 7 | */ 8 | using System; 9 | 10 | namespace PeterO.Numbers { 11 | /// Common interface for classes that shift a number of digits 12 | /// and record information on whether a nonzero digit was discarded 13 | /// this way. 14 | internal interface IShiftAccumulator { 15 | EInteger ShiftedInt { 16 | get; 17 | } 18 | 19 | FastInteger GetDigitLength(); 20 | 21 | FastInteger OverestimateDigitLength(); 22 | 23 | int OlderDiscardedDigits { 24 | get; 25 | } 26 | 27 | int LastDiscardedDigit { 28 | get; 29 | } 30 | 31 | FastInteger ShiftedIntFast { 32 | get; 33 | } 34 | 35 | FastInteger DiscardedDigitCount { 36 | get; 37 | } 38 | 39 | void TruncateOrShiftRight(FastInteger bits, bool truncate); 40 | 41 | int ShiftedIntMod(int mod); 42 | 43 | void ShiftRightInt(int bits); 44 | 45 | void ShiftToDigits(FastInteger bits, FastInteger preShift, bool truncate); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Numbers/PeterO/Numbers/TrappableRadixMath.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Written by Peter O. 3 | Any copyright to this work is released to the Public Domain. 4 | In case this is not possible, this work is also 5 | licensed under the Unlicense: https://unlicense.org/ 6 | 7 | */ 8 | using System; 9 | 10 | namespace PeterO.Numbers { 11 | // Implements arithmetic methods that support 12 | // traps. 13 | // Data type for a numeric value in a particular 14 | // radix. 15 | internal class TrappableRadixMath : IRadixMath { 16 | private readonly IRadixMath math; 17 | 18 | public TrappableRadixMath(IRadixMath math) { 19 | #if DEBUG 20 | if (math == null) { 21 | throw new ArgumentNullException(nameof(math)); 22 | } 23 | #endif 24 | this.math = math; 25 | } 26 | 27 | public T DivideToIntegerNaturalScale( 28 | T thisValue, 29 | T divisor, 30 | EContext ctx) { 31 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 32 | T result = this.math.DivideToIntegerNaturalScale( 33 | thisValue, 34 | divisor, 35 | tctx); 36 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 37 | } 38 | 39 | public T DivideToIntegerZeroScale( 40 | T thisValue, 41 | T divisor, 42 | EContext ctx) { 43 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 44 | T result = this.math.DivideToIntegerZeroScale(thisValue, divisor, tctx); 45 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 46 | } 47 | 48 | public T Abs(T value, EContext ctx) { 49 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 50 | T result = this.math.Abs(value, tctx); 51 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 52 | } 53 | 54 | public T Negate(T value, EContext ctx) { 55 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 56 | T result = this.math.Negate(value, tctx); 57 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 58 | } 59 | 60 | public T Remainder( 61 | T thisValue, 62 | T divisor, 63 | EContext ctx, 64 | bool roundAfterDivide) { 65 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 66 | T result = this.math.Remainder( 67 | thisValue, 68 | divisor, 69 | tctx, 70 | roundAfterDivide); 71 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 72 | } 73 | 74 | public IRadixMathHelper GetHelper() { 75 | return this.math.GetHelper(); 76 | } 77 | 78 | public T RemainderNear(T thisValue, T divisor, EContext ctx) { 79 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 80 | T result = this.math.RemainderNear(thisValue, divisor, tctx); 81 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 82 | } 83 | 84 | public T Pi(EContext ctx) { 85 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 86 | T result = this.math.Pi(tctx); 87 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 88 | } 89 | 90 | public T Power(T thisValue, T pow, EContext ctx) { 91 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 92 | T result = this.math.Power(thisValue, pow, tctx); 93 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 94 | } 95 | 96 | public T Ln(T thisValue, EContext ctx) { 97 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 98 | T result = this.math.Ln(thisValue, tctx); 99 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 100 | } 101 | 102 | public T Exp(T thisValue, EContext ctx) { 103 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 104 | T result = this.math.Exp(thisValue, tctx); 105 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 106 | } 107 | 108 | public T SquareRoot(T thisValue, EContext ctx) { 109 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 110 | T result = this.math.SquareRoot(thisValue, tctx); 111 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 112 | } 113 | 114 | public T NextMinus(T thisValue, EContext ctx) { 115 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 116 | T result = this.math.NextMinus(thisValue, tctx); 117 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 118 | } 119 | 120 | public T NextToward(T thisValue, T otherValue, EContext ctx) { 121 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 122 | T result = this.math.NextToward(thisValue, otherValue, tctx); 123 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 124 | } 125 | 126 | public T NextPlus(T thisValue, EContext ctx) { 127 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 128 | T result = this.math.NextPlus(thisValue, tctx); 129 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 130 | } 131 | 132 | public T DivideToExponent( 133 | T thisValue, 134 | T divisor, 135 | EInteger desiredExponent, 136 | EContext ctx) { 137 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 138 | T result = this.math.DivideToExponent( 139 | thisValue, 140 | divisor, 141 | desiredExponent, 142 | tctx); 143 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 144 | } 145 | 146 | public T Divide(T thisValue, T divisor, EContext ctx) { 147 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 148 | T result = this.math.Divide(thisValue, divisor, tctx); 149 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 150 | } 151 | 152 | public T MinMagnitude(T a, T b, EContext ctx) { 153 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 154 | T result = this.math.MinMagnitude(a, b, tctx); 155 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 156 | } 157 | 158 | public T MaxMagnitude(T a, T b, EContext ctx) { 159 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 160 | T result = this.math.MaxMagnitude(a, b, tctx); 161 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 162 | } 163 | 164 | public T Max(T a, T b, EContext ctx) { 165 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 166 | T result = this.math.Max(a, b, tctx); 167 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 168 | } 169 | 170 | public T Min(T a, T b, EContext ctx) { 171 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 172 | T result = this.math.Min(a, b, tctx); 173 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 174 | } 175 | 176 | public T Multiply(T thisValue, T other, EContext ctx) { 177 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 178 | T result = this.math.Multiply(thisValue, other, tctx); 179 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 180 | } 181 | 182 | public T MultiplyAndAdd( 183 | T thisValue, 184 | T multiplicand, 185 | T augend, 186 | EContext ctx) { 187 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 188 | T result = this.math.MultiplyAndAdd( 189 | thisValue, 190 | multiplicand, 191 | augend, 192 | tctx); 193 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 194 | } 195 | 196 | public T Plus(T thisValue, EContext ctx) { 197 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 198 | T result = this.math.Plus(thisValue, tctx); 199 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 200 | } 201 | 202 | public T RoundToPrecision(T thisValue, EContext ctx) { 203 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 204 | T result = this.math.RoundToPrecision(thisValue, tctx); 205 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 206 | } 207 | 208 | public T Quantize(T thisValue, T otherValue, EContext ctx) { 209 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 210 | T result = this.math.Quantize(thisValue, otherValue, tctx); 211 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 212 | } 213 | 214 | public T RoundToExponentExact( 215 | T thisValue, 216 | EInteger expOther, 217 | EContext ctx) { 218 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 219 | T result = this.math.RoundToExponentExact(thisValue, expOther, tctx); 220 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 221 | } 222 | 223 | public T RoundToExponentSimple( 224 | T thisValue, 225 | EInteger expOther, 226 | EContext ctx) { 227 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 228 | T result = this.math.RoundToExponentSimple(thisValue, expOther, ctx); 229 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 230 | } 231 | 232 | public T RoundToExponentNoRoundedFlag( 233 | T thisValue, 234 | EInteger exponent, 235 | EContext ctx) { 236 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 237 | T result = this.math.RoundToExponentNoRoundedFlag( 238 | thisValue, 239 | exponent, 240 | ctx); 241 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 242 | } 243 | 244 | public T Reduce(T thisValue, EContext ctx) { 245 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 246 | T result = this.math.Reduce(thisValue, ctx); 247 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 248 | } 249 | 250 | public T Add(T thisValue, T other, EContext ctx) { 251 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 252 | T result = this.math.Add(thisValue, other, tctx); 253 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 254 | } 255 | 256 | public T CompareToWithContext( 257 | T thisValue, 258 | T otherValue, 259 | bool treatQuietNansAsSignaling, 260 | EContext ctx) { 261 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 262 | T result = this.math.CompareToWithContext( 263 | thisValue, 264 | otherValue, 265 | treatQuietNansAsSignaling, 266 | tctx); 267 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 268 | } 269 | 270 | // Compares a T object with this instance. 271 | // 272 | // Zero if the values are equal; a negative number if this 273 | // instance is less, or a positive number if this instance is 274 | // greater. 275 | public int CompareTo(T thisValue, T otherValue) { 276 | return this.math.CompareTo(thisValue, otherValue); 277 | } 278 | 279 | public T RoundAfterConversion(T thisValue, EContext ctx) { 280 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 281 | T result = this.math.RoundAfterConversion(thisValue, tctx); 282 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 283 | } 284 | 285 | public T SignalOverflow(EContext ctx, bool neg) { 286 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 287 | T result = this.math.SignalOverflow(tctx, neg); 288 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 289 | } 290 | 291 | public T AddEx( 292 | T thisValue, 293 | T other, 294 | EContext ctx, 295 | bool roundToOperandPrecision) { 296 | EContext tctx = (ctx == null) ? ctx : ctx.GetNontrapping(); 297 | T result = this.math.AddEx( 298 | thisValue, 299 | other, 300 | ctx, 301 | roundToOperandPrecision); 302 | return ctx == null ? result : ctx.TriggerTraps(result, tctx); 303 | } 304 | } 305 | } 306 | -------------------------------------------------------------------------------- /Numbers/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | [assembly: CLSCompliant(true)] 3 | -------------------------------------------------------------------------------- /Numbers/rules.ruleset: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Numbers/stylecop.json: -------------------------------------------------------------------------------- 1 | {"settings":{"documentationRules":{"documentInternalElements":false,"documentInterfaces":false},"orderingRules":{"usingDirectivesPlacement":"outsideNamespace"}}} 2 | -------------------------------------------------------------------------------- /Numbers20/Numbers20.csproj: -------------------------------------------------------------------------------- 1 | winDebugAnyCPULibraryNumbersv2.0truetrue..\Numbers\PeterO.snk{04A7B845-E447-4A46-ABB9-D195BDEDC735}rules.rulesettruetruefullfalsebin\DebugDEBUG;NET40prompt4bin\Debug\Numbers.xmlrules.rulesettruebin\ReleaseNET40prompt4bin\Release\Numbers.xmlrules.ruleset1.1.1187.0.3stylecop.jsondocs.xmlPeterO/DebugUtility.csPeterO/Numbers/EIntegerExtra.csPeterO/Numbers/EInteger.csPeterO/Numbers/TrappableRadixMath.csPeterO/Numbers/EDecimalByteArrayString.csPeterO/Numbers/ETrapException.csPeterO/Numbers/EContext.csPeterO/Numbers/BigNumberFlags.csPeterO/Numbers/EIntegerCharArrayString.csPeterO/Numbers/ERationalByteArrayString.csPeterO/Numbers/EDecimalExtra.csPeterO/Numbers/IRadixMathHelper.csPeterO/Numbers/SimpleRadixMath.csPeterO/Numbers/FastInteger.csPeterO/Numbers/DigitShiftAccumulator.csPeterO/Numbers/Extras.csPeterO/Numbers/FastIntegerFixed.csPeterO/Numbers/EDecimalCharArrayString.csPeterO/Numbers/ERationalCharArrayString.csPeterO/Numbers/ERationalTextString.csPeterO/Numbers/EDecimals.csPeterO/Numbers/ExtendedOrSimpleRadixMath.csPeterO/Numbers/ERounding.csPeterO/Numbers/ERationalExtra.csPeterO/Numbers/EFloat.csPeterO/Numbers/NumberUtility.csPeterO/Numbers/EFloats.csPeterO/Numbers/RadixMath.csPeterO/Numbers/EFloatExtra.csPeterO/Numbers/EIntegerTextString.csPeterO/Numbers/EFloatByteArrayString.csPeterO/Numbers/ERational.csPeterO/Numbers/IRadixMath.csPeterO/Numbers/EFloatCharArrayString.csPeterO/Numbers/EIntegerByteArrayString.csPeterO/Numbers/BitShiftAccumulator.csPeterO/Numbers/EDecimal.csPeterO/Numbers/EFloatTextString.csPeterO/Numbers/IShiftAccumulator.csPeterO/Numbers/EDecimalTextString.cs 2 | -------------------------------------------------------------------------------- /Numbers20/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | [assembly: System.CLSCompliant(true)] 3 | [assembly: AssemblyInformationalVersion("1.8.1")] 4 | [assembly: AssemblyVersion("1.8.1.0")] 5 | [assembly: AssemblyFileVersion("1.8.1.0")] 6 | [assembly: AssemblyProduct("Arbitrary-Precision Number Library")] 7 | [assembly: AssemblyTitle("Arbitrary-Precision Number Library")] 8 | [assembly: AssemblyDescription("A C# library that supports arbitrary-pre" + 9 | "cision binary and decimal floating-point" + 10 | " numbers and rational numbers with arbit" + 11 | "rary-precision components, and supports " + 12 | "arithmetic with these numbers.")] 13 | [assembly: AssemblyCompany("Peter Occil")] 14 | [assembly: AssemblyCopyright("CC0-1.0")] 15 | -------------------------------------------------------------------------------- /Numbers20/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Numbers20/rules.ruleset: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Numbers20/stylecop.json: -------------------------------------------------------------------------------- 1 | {"settings":{"documentationRules":{"documentInternalElements":false,"documentInterfaces":false},"orderingRules":{"usingDirectivesPlacement":"outsideNamespace"}}} 2 | -------------------------------------------------------------------------------- /Numbers40/Numbers40.csproj: -------------------------------------------------------------------------------- 1 | winDebugAnyCPULibraryNumbersv4.0truetrue..\Numbers\PeterO.snk{D7E09F55-3156-44B0-87D9-1BABCBB398D9}rules.rulesettruefullfalsebin\DebugDEBUG;NET40prompt4bin\Debug\Numbers.xmlrules.rulesettruebin\ReleaseNET40prompt4bin\Release\Numbers.xmlrules.ruleset1.1.1187.0.3stylecop.jsondocs.xmlPeterO/DebugUtility.csPeterO/Numbers/EIntegerExtra.csPeterO/Numbers/EInteger.csPeterO/Numbers/TrappableRadixMath.csPeterO/Numbers/EDecimalByteArrayString.csPeterO/Numbers/ETrapException.csPeterO/Numbers/EContext.csPeterO/Numbers/BigNumberFlags.csPeterO/Numbers/EIntegerCharArrayString.csPeterO/Numbers/ERationalByteArrayString.csPeterO/Numbers/EDecimalExtra.csPeterO/Numbers/IRadixMathHelper.csPeterO/Numbers/SimpleRadixMath.csPeterO/Numbers/FastInteger.csPeterO/Numbers/DigitShiftAccumulator.csPeterO/Numbers/Extras.csPeterO/Numbers/FastIntegerFixed.csPeterO/Numbers/EDecimalCharArrayString.csPeterO/Numbers/ERationalCharArrayString.csPeterO/Numbers/ERationalTextString.csPeterO/Numbers/EDecimals.csPeterO/Numbers/ExtendedOrSimpleRadixMath.csPeterO/Numbers/ERounding.csPeterO/Numbers/ERationalExtra.csPeterO/Numbers/EFloat.csPeterO/Numbers/NumberUtility.csPeterO/Numbers/EFloats.csPeterO/Numbers/RadixMath.csPeterO/Numbers/EFloatExtra.csPeterO/Numbers/EIntegerTextString.csPeterO/Numbers/EFloatByteArrayString.csPeterO/Numbers/ERational.csPeterO/Numbers/IRadixMath.csPeterO/Numbers/EFloatCharArrayString.csPeterO/Numbers/EIntegerByteArrayString.csPeterO/Numbers/BitShiftAccumulator.csPeterO/Numbers/EDecimal.csPeterO/Numbers/EFloatTextString.csPeterO/Numbers/IShiftAccumulator.csPeterO/Numbers/EDecimalTextString.cs 2 | -------------------------------------------------------------------------------- /Numbers40/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | [assembly: System.CLSCompliant(true)] 3 | [assembly: AssemblyInformationalVersion("1.8.1")] 4 | [assembly: AssemblyVersion("1.8.1.0")] 5 | [assembly: AssemblyFileVersion("1.8.1.0")] 6 | [assembly: AssemblyProduct("Arbitrary-Precision Number Library")] 7 | [assembly: AssemblyTitle("Arbitrary-Precision Number Library")] 8 | [assembly: AssemblyDescription("A C# library that supports arbitrary-pre" + 9 | "cision binary and decimal floating-point" + 10 | " numbers and rational numbers with arbit" + 11 | "rary-precision components, and supports " + 12 | "arithmetic with these numbers.")] 13 | [assembly: AssemblyCompany("Peter Occil")] 14 | [assembly: AssemblyCopyright("CC0-1.0")] 15 | -------------------------------------------------------------------------------- /Numbers40/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Numbers40/rules.ruleset: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Numbers40/stylecop.json: -------------------------------------------------------------------------------- 1 | {"settings":{"documentationRules":{"documentInternalElements":false,"documentInterfaces":false},"orderingRules":{"usingDirectivesPlacement":"outsideNamespace"}}} 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Numbers 2 | ==== 3 | [![NuGet Status](http://img.shields.io/nuget/v/PeterO.Numbers.svg?style=flat)](https://www.nuget.org/packages/PeterO.Numbers) 4 | 5 | **Download source code: [ZIP file](https://github.com/peteroupc/Numbers/archive/master.zip)** 6 | 7 | ---- 8 | 9 | A C# library that supports arbitrary-precision binary and decimal floating-point numbers and rational numbers with arbitrary-precision components. 10 | 11 | Source code is available in the [project page](https://github.com/peteroupc/Numbers). 12 | 13 | How to Install 14 | --------- 15 | The library is available in the 16 | NuGet Package Gallery under the name 17 | [PeterO.Numbers](https://www.nuget.org/packages/PeterO.Numbers). To install 18 | this library as a NuGet package, enter `Install-Package PeterO.Numbers` in the 19 | NuGet Package Manager Console. 20 | 21 | Documentation 22 | ------------ 23 | 24 | **See the [C# (.NET) API documentation](https://peteroupc.github.io/Numbers/docs/).** 25 | 26 | Examples 27 | ---------- 28 | 29 | *For more examples, see [examples.md](https://github.com/peteroupc/Numbers/tree/master/examples.md).* 30 | 31 | About 32 | ----------- 33 | 34 | Written by Peter O. 35 | 36 | Any copyright to this work is released to the Public Domain. 37 | In case this is not possible, this work is also 38 | licensed under the Unlicense: [https://unlicense.org/](https://unlicense.org/) 39 | 40 | Release notes 41 | ------- 42 | 43 | For full release history, see [History.md](History.md). 44 | -------------------------------------------------------------------------------- /Test/AppResources.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.Resources; 4 | using System.Text; 5 | 6 | namespace Test { 7 | internal sealed class AppResources { 8 | private readonly ResourceManager mgr; 9 | 10 | public AppResources(string name) { 11 | // #if NET20 || NET40 12 | this.mgr = new ResourceManager( 13 | name, 14 | Assembly.GetExecutingAssembly()); 15 | // #else 16 | // this.mgr = new ResourceManager(typeof(AppResources)); 17 | // #endif 18 | } 19 | public string GetString(string name) { 20 | return this.mgr.GetString(name, 21 | System.Globalization.CultureInfo.InvariantCulture); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Test/DecimalTest.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Written by Peter O. 3 | Any copyright to this work is released to the Public Domain. 4 | In case this is not possible, this work is also 5 | licensed under the Unlicense: https://unlicense.org/ 6 | 7 | */ 8 | using System; 9 | using System.Collections.Generic; 10 | using System.IO; 11 | using NUnit.Framework; 12 | using PeterO; 13 | using PeterO.Numbers; 14 | 15 | namespace Test { 16 | [TestFixture] 17 | public class DecimalTest { 18 | internal static void PrintTime(System.Diagnostics.Stopwatch sw) { 19 | Console.WriteLine("Elapsed time: " + (sw.ElapsedMilliseconds / 1000.0) + 20 | " s"); 21 | } 22 | 23 | [Test] 24 | public void TestPi() { 25 | var sw = new System.Diagnostics.Stopwatch(); 26 | sw.Start(); 27 | EDecimal.PI(EContext.ForPrecision(1000)).ToString(); 28 | sw.Stop(); 29 | PrintTime(sw); 30 | } 31 | 32 | private static decimal RandomDecimal(RandomGenerator rand) { 33 | int a, b, c; 34 | a = rand.UniformInt(0x10000); 35 | a = unchecked((a << 16) + rand.UniformInt(0x10000)); 36 | b = rand.UniformInt(0x10000); 37 | b = unchecked((b << 16) + rand.UniformInt(0x10000)); 38 | c = rand.UniformInt(0x10000); 39 | c = unchecked((c << 16) + rand.UniformInt(0x10000)); 40 | int scale = rand.UniformInt(29); 41 | return new Decimal(a, b, c, rand.UniformInt(2) == 0, (byte)scale); 42 | } 43 | 44 | [Test] 45 | [Timeout(100000)] 46 | public void TestDecimalString() { 47 | var fr = new RandomGenerator(); 48 | // var sw = new System.Diagnostics.Stopwatch(); 49 | // var sw2 = new System.Diagnostics.Stopwatch(); 50 | // var sw3 = new System.Diagnostics.Stopwatch(); 51 | for (var i = 0; i < 10000; ++i) { 52 | if (i % 100 == 0) { 53 | // Console.WriteLine(i + " sw=" + 54 | // sw.ElapsedMilliseconds + ", " + (sw2.ElapsedMilliseconds) + 55 | // ", " + (sw3.ElapsedMilliseconds)); 56 | } 57 | // sw3.Start(); 58 | EDecimal ed = RandomNumerics.RandomEDecimal(fr); 59 | // sw3.Stop(); 60 | // Reduce to Decimal128. Without this reduction, 61 | // Decimal.Parse would run significantly more slowly 62 | // on average for random 63 | // EDecimals than 64 | // EDecimal.FromString(CliDecimal) does. 65 | // Decimal128 covers all numbers representable 66 | // in a CliDecimal. 67 | ed = ed.RoundToPrecision(EContext.Decimal128); 68 | 69 | if (!ed.IsFinite) { 70 | continue; 71 | } 72 | string edString = ed.ToString(); 73 | decimal d; 74 | try { 75 | System.Globalization.NumberStyles numstyles = 76 | System.Globalization.NumberStyles.AllowExponent | 77 | System.Globalization.NumberStyles.Number; 78 | // sw.Start(); 79 | d = Decimal.Parse( 80 | edString, 81 | numstyles, 82 | System.Globalization.CultureInfo.InvariantCulture); 83 | // sw.Stop(); 84 | // sw2.Start(); 85 | EDecimal ed3 = EDecimal.FromString( 86 | edString, 87 | EContext.CliDecimal); 88 | // sw2.Stop(); 89 | var edd = (EDecimal)d; 90 | if (!edd.Equals(ed3)) { 91 | string msg = ed.ToString() + " (expanded: " + 92 | EDecimal.FromString(ed.ToString()) + ")"; 93 | TestCommon.CompareTestEqual( 94 | (EDecimal)d, 95 | ed3, 96 | msg); 97 | } 98 | // sw3.Stop(); 99 | } catch (OverflowException ex) { 100 | EDecimal ed2 = EDecimal.FromString( 101 | edString, 102 | EContext.CliDecimal); 103 | if (!ed2.IsInfinity()) { 104 | Assert.Fail(edString + "\n" + ex.ToString()); 105 | } 106 | } 107 | } 108 | } 109 | 110 | [Test] 111 | public static void TestUint64() { 112 | EInteger ei = EInteger.FromString("9223372036854775808"); 113 | Assert.AreEqual((ulong)9223372036854775808, ei.ToUInt64Checked()); 114 | Assert.AreEqual((ulong)9223372036854775808, ei.ToUInt64Unchecked()); 115 | } 116 | 117 | [Test] 118 | public static void TestToDecimal() { 119 | try { 120 | EDecimal.FromString("8.8888888e-7").ToDecimal(); 121 | } catch (Exception ex) { 122 | Assert.Fail(ex.ToString()); 123 | throw new InvalidOperationException(String.Empty, ex); 124 | } 125 | try { 126 | EDecimal.FromString("8.8888888e-8").ToDecimal(); 127 | } catch (Exception ex) { 128 | Assert.Fail(ex.ToString()); 129 | throw new InvalidOperationException(String.Empty, ex); 130 | } 131 | try { 132 | EDecimal.FromString("8.8888888e-18").ToDecimal(); 133 | } catch (Exception ex) { 134 | Assert.Fail(ex.ToString()); 135 | throw new InvalidOperationException(String.Empty, ex); 136 | } 137 | } 138 | 139 | [Test] 140 | public void TestDecimal() { 141 | var fr = new RandomGenerator(); 142 | for (var i = 0; i < 1000; ++i) { 143 | decimal d = RandomDecimal(fr); 144 | EDecimal ed = d; 145 | TestCommon.CompareTestEqual(d, (decimal)ed, ed.ToString()); 146 | EDecimal ed2 = 147 | 148 | EDecimal.FromString( 149 | d.ToString(System.Globalization.CultureInfo.InvariantCulture)); 150 | TestCommon.CompareTestEqual(ed, ed2); 151 | } 152 | } 153 | 154 | [Test] 155 | public void TestToUintChecked() { 156 | Assert.AreEqual((byte)0, EDecimal.FromString("-0.1").ToUInt16Checked()); 157 | Assert.AreEqual((byte)0, EDecimal.FromString("-0.4").ToUInt16Checked()); 158 | Assert.AreEqual((byte)0, EDecimal.FromString("-0.5").ToUInt16Checked()); 159 | Assert.AreEqual((byte)0, EDecimal.FromString("-0.6").ToUInt16Checked()); 160 | try { 161 | EDecimal.FromString("-1.0").ToUInt16Checked(); 162 | Assert.Fail("Should have failed"); 163 | } catch (OverflowException) { 164 | // NOTE: Intentionally empty 165 | } catch (Exception ex) { 166 | Assert.Fail(ex.ToString()); 167 | throw new InvalidOperationException(String.Empty, ex); 168 | } 169 | try { 170 | EDecimal.FromString("-1.4").ToUInt16Checked(); 171 | Assert.Fail("Should have failed"); 172 | } catch (OverflowException) { 173 | // NOTE: Intentionally empty 174 | } catch (Exception ex) { 175 | Assert.Fail(ex.ToString()); 176 | throw new InvalidOperationException(String.Empty, ex); 177 | } 178 | try { 179 | EDecimal.FromString("-1.5").ToUInt16Checked(); 180 | Assert.Fail("Should have failed"); 181 | } catch (OverflowException) { 182 | // NOTE: Intentionally empty 183 | } catch (Exception ex) { 184 | Assert.Fail(ex.ToString()); 185 | throw new InvalidOperationException(String.Empty, ex); 186 | } 187 | try { 188 | EDecimal.FromString("-1.6").ToUInt16Checked(); 189 | Assert.Fail("Should have failed"); 190 | } catch (OverflowException) { 191 | // NOTE: Intentionally empty 192 | } catch (Exception ex) { 193 | Assert.Fail(ex.ToString()); 194 | throw new InvalidOperationException(String.Empty, ex); 195 | } 196 | Assert.AreEqual((byte)0, EDecimal.FromString("-0.1").ToUInt32Checked()); 197 | Assert.AreEqual((byte)0, EDecimal.FromString("-0.4").ToUInt32Checked()); 198 | Assert.AreEqual((byte)0, EDecimal.FromString("-0.5").ToUInt32Checked()); 199 | Assert.AreEqual((byte)0, EDecimal.FromString("-0.6").ToUInt32Checked()); 200 | try { 201 | EDecimal.FromString("-1.0").ToUInt32Checked(); 202 | Assert.Fail("Should have failed"); 203 | } catch (OverflowException) { 204 | // NOTE: Intentionally empty 205 | } catch (Exception ex) { 206 | Assert.Fail(ex.ToString()); 207 | throw new InvalidOperationException(String.Empty, ex); 208 | } 209 | try { 210 | EDecimal.FromString("-1.4").ToUInt32Checked(); 211 | Assert.Fail("Should have failed"); 212 | } catch (OverflowException) { 213 | // NOTE: Intentionally empty 214 | } catch (Exception ex) { 215 | Assert.Fail(ex.ToString()); 216 | throw new InvalidOperationException(String.Empty, ex); 217 | } 218 | try { 219 | EDecimal.FromString("-1.5").ToUInt32Checked(); 220 | Assert.Fail("Should have failed"); 221 | } catch (OverflowException) { 222 | // NOTE: Intentionally empty 223 | } catch (Exception ex) { 224 | Assert.Fail(ex.ToString()); 225 | throw new InvalidOperationException(String.Empty, ex); 226 | } 227 | try { 228 | EDecimal.FromString("-1.6").ToUInt32Checked(); 229 | Assert.Fail("Should have failed"); 230 | } catch (OverflowException) { 231 | // NOTE: Intentionally empty 232 | } catch (Exception ex) { 233 | Assert.Fail(ex.ToString()); 234 | throw new InvalidOperationException(String.Empty, ex); 235 | } 236 | Assert.AreEqual((byte)0, EDecimal.FromString("-0.1").ToUInt64Checked()); 237 | Assert.AreEqual((byte)0, EDecimal.FromString("-0.4").ToUInt64Checked()); 238 | Assert.AreEqual((byte)0, EDecimal.FromString("-0.5").ToUInt64Checked()); 239 | Assert.AreEqual((byte)0, EDecimal.FromString("-0.6").ToUInt64Checked()); 240 | try { 241 | EDecimal.FromString("-1.0").ToUInt64Checked(); 242 | Assert.Fail("Should have failed"); 243 | } catch (OverflowException) { 244 | // NOTE: Intentionally empty 245 | } catch (Exception ex) { 246 | Assert.Fail(ex.ToString()); 247 | throw new InvalidOperationException(String.Empty, ex); 248 | } 249 | try { 250 | EDecimal.FromString("-1.4").ToUInt64Checked(); 251 | Assert.Fail("Should have failed"); 252 | } catch (OverflowException) { 253 | // NOTE: Intentionally empty 254 | } catch (Exception ex) { 255 | Assert.Fail(ex.ToString()); 256 | throw new InvalidOperationException(String.Empty, ex); 257 | } 258 | try { 259 | EDecimal.FromString("-1.5").ToUInt64Checked(); 260 | Assert.Fail("Should have failed"); 261 | } catch (OverflowException) { 262 | // NOTE: Intentionally empty 263 | } catch (Exception ex) { 264 | Assert.Fail(ex.ToString()); 265 | throw new InvalidOperationException(String.Empty, ex); 266 | } 267 | try { 268 | EDecimal.FromString("-1.6").ToUInt64Checked(); 269 | Assert.Fail("Should have failed"); 270 | } catch (OverflowException) { 271 | // NOTE: Intentionally empty 272 | } catch (Exception ex) { 273 | Assert.Fail(ex.ToString()); 274 | throw new InvalidOperationException(String.Empty, ex); 275 | } 276 | } 277 | } 278 | } 279 | -------------------------------------------------------------------------------- /Test/DelayingStream.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace Test { 5 | /// Stream that can return fewer bytes than 6 | /// requested. 7 | public sealed class DelayingStream : Stream { 8 | private readonly Stream ms; 9 | 10 | /// Initializes a new instance of the 11 | /// class. 12 | /// 13 | /// The parameter is null. 15 | public DelayingStream(Stream ms) { 16 | this.ms = ms ?? throw new ArgumentNullException(nameof(ms)); 17 | } 18 | 19 | /// Initializes a new instance of the 20 | /// class. 21 | /// 22 | public DelayingStream(byte[] bytes) : this(new MemoryStream(bytes)) { 23 | } 24 | 25 | /// Initializes a new instance of the 26 | /// class. 27 | public DelayingStream() : this(new MemoryStream()) { 28 | } 29 | 30 | /// Initializes a new instance of the 31 | /// class. 32 | /// 33 | public DelayingStream(int size) : this(new MemoryStream(size)) { 34 | } 35 | 36 | public new void Dispose() { 37 | this.ms.Dispose(); 38 | } 39 | 40 | /// 41 | public override long Length => this.ms.Length; 42 | 43 | /// 44 | /// 45 | /// Not documented yet. 46 | /// Not documented yet. 47 | public override long Seek(long pos, SeekOrigin origin) { 48 | return this.ms.Seek(pos, origin); 49 | } 50 | 51 | /// 52 | /// Not documented yet. 53 | public override void SetLength(long len) { 54 | this.ms.SetLength(len); 55 | } 56 | 57 | /// 58 | public override long Position 59 | { 60 | get => this.ms.Position; 61 | 62 | set => this.ms.Position = value; 63 | } 64 | 65 | public byte[] ToArray() { 66 | var ms = this.ms as MemoryStream; 67 | return ms != null ? ms.ToArray() : throw new NotSupportedException(); 68 | } 69 | 70 | /// 71 | public override bool CanRead => this.ms.CanRead; 72 | 73 | /// 74 | public override bool CanSeek => this.ms.CanSeek; 75 | 76 | /// 77 | public override bool CanWrite => this.ms.CanWrite; 78 | 79 | /// 80 | /// 81 | /// Not documented yet. 82 | /// Not documented yet. 83 | /// Not documented yet. 84 | /// The parameter is null. 86 | public override int Read(byte[] bytes, int offset, int count) { 87 | if (bytes == null) { 88 | throw new ArgumentNullException(nameof(bytes)); 89 | } 90 | if (offset < 0) { 91 | throw new ArgumentException("\"offset\" (" + offset + ") is not" + 92 | "\u0020greater or equal to 0"); 93 | } 94 | if (offset > bytes.Length) { 95 | throw new ArgumentException("\"offset\" (" + offset + ") is not less" + 96 | "\u0020or equal to " + bytes.Length); 97 | } 98 | if (count < 0) { 99 | throw new ArgumentException(" (" + count + ") is not greater or" + 100 | "\u0020equal to 0"); 101 | } 102 | if (count > bytes.Length) { 103 | throw new ArgumentException(" (" + count + ") is not less or equal" + 104 | "\u0020to " + bytes.Length); 105 | } 106 | if (bytes.Length - offset < count) { 107 | throw new ArgumentException("\"bytes\" + \"'s length minus \" +" + 108 | "\u0020offset (" + (bytes.Length - offset) + ") is not greater or" + 109 | "\u0020 equal to " + count); 110 | } 111 | if (count == 0) { 112 | return 0; 113 | } 114 | int b = this.ms.ReadByte(); 115 | if (b < 0) { 116 | return 0; 117 | } 118 | bytes[offset] = (byte)b; 119 | return 1; 120 | } 121 | 122 | /// 123 | public override void Flush() { 124 | this.ms.Flush(); 125 | } 126 | 127 | /// 128 | /// Not documented yet. 129 | /// Not documented yet. 130 | /// Not documented yet. 131 | public override void Write(byte[] bytes, int offset, int count) { 132 | this.ms.Write(bytes, offset, count); 133 | } 134 | 135 | /// 136 | /// Not documented yet. 137 | public override void WriteByte(byte c) { 138 | this.ms.WriteByte(c); 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /Test/EContextTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework; 3 | using PeterO.Numbers; 4 | 5 | namespace Test { 6 | [TestFixture] 7 | public class EContextTest { 8 | [Test] 9 | public void TestConstructor() { 10 | try { 11 | Assert.AreEqual( 12 | null, 13 | new EContext(-1, ERounding.HalfEven, 0, 0, false)); 14 | Assert.Fail("Should have failed"); 15 | } catch (ArgumentException) { 16 | // NOTE: Intentionally empty 17 | } catch (Exception ex) { 18 | Assert.Fail(ex.ToString()); 19 | throw new InvalidOperationException(String.Empty, ex); 20 | } 21 | try { 22 | Assert.AreEqual( 23 | null, 24 | new EContext(0, ERounding.HalfEven, 0, -1, false)); 25 | Assert.Fail("Should have failed"); 26 | } catch (ArgumentException) { 27 | // NOTE: Intentionally empty 28 | } catch (Exception ex) { 29 | Assert.Fail(ex.ToString()); 30 | throw new InvalidOperationException(String.Empty, ex); 31 | } 32 | } 33 | [Test] 34 | public void TestAdjustExponent() { 35 | // not implemented yet 36 | } 37 | [Test] 38 | public void TestClampNormalExponents() { 39 | // not implemented yet 40 | } 41 | [Test] 42 | public void TestCopy() { 43 | // not implemented yet 44 | } 45 | [Test] 46 | public void TestEMax() { 47 | EContext ctx = EContext.Unlimited; 48 | Assert.AreEqual(EInteger.Zero, ctx.EMax); 49 | ctx = EContext.Unlimited.WithExponentRange(-5, 5); 50 | Assert.AreEqual((EInteger)5, ctx.EMax); 51 | } 52 | [Test] 53 | public void TestEMin() { 54 | EContext ctx = EContext.Unlimited; 55 | Assert.AreEqual(EInteger.Zero, ctx.EMin); 56 | ctx = EContext.Unlimited.WithExponentRange(-5, 5); 57 | Assert.AreEqual((EInteger)(-5), ctx.EMin); 58 | } 59 | [Test] 60 | public void TestExponentWithinRange() { 61 | Assert.IsTrue(EContext.Unlimited.ExponentWithinRange( 62 | EInteger.FromString( 63 | "-9999999"))); 64 | 65 | Assert.IsTrue(EContext.Unlimited.ExponentWithinRange( 66 | EInteger.FromString( 67 | "9999999"))); 68 | try { 69 | EContext.Unlimited.ExponentWithinRange(null); 70 | Assert.Fail("Should have failed"); 71 | } catch (ArgumentNullException) { 72 | // NOTE: Intentionally empty 73 | } catch (Exception ex) { 74 | Assert.Fail(ex.ToString()); 75 | throw new InvalidOperationException(String.Empty, ex); 76 | } 77 | } 78 | [Test] 79 | public void TestFlags() { 80 | EContext ctx = EContext.Unlimited; 81 | try { 82 | ctx.Flags = 5; 83 | Assert.Fail("Should have failed"); 84 | } catch (InvalidOperationException) { 85 | // NOTE: Intentionally empty 86 | } catch (Exception ex) { 87 | Assert.Fail(ex.ToString()); 88 | throw new InvalidOperationException(String.Empty, ex); 89 | } 90 | ctx = ctx.WithBlankFlags(); 91 | try { 92 | ctx.Flags = 5; 93 | } catch (Exception ex) { 94 | Assert.Fail(ex.ToString()); 95 | throw new InvalidOperationException(String.Empty, ex); 96 | } 97 | ctx = ctx.WithNoFlags(); 98 | try { 99 | ctx.Flags = 5; 100 | Assert.Fail("Should have failed"); 101 | } catch (InvalidOperationException) { 102 | // NOTE: Intentionally empty 103 | } catch (Exception ex) { 104 | Assert.Fail(ex.ToString()); 105 | throw new InvalidOperationException(String.Empty, ex); 106 | } 107 | } 108 | 109 | [Test] 110 | public void TestCliDecimal() { 111 | EDecimal valueEdTmp; 112 | valueEdTmp = EDecimal.FromString( 113 | "-79228162514264337593543950336") 114 | .RoundToPrecision(EContext.CliDecimal); 115 | Assert.AreEqual( 116 | EDecimal.NegativeInfinity, 117 | valueEdTmp); 118 | valueEdTmp = EDecimal.FromString( 119 | "8.782580686213340724E+28") 120 | .RoundToPrecision(EContext.CliDecimal); 121 | Assert.AreEqual( 122 | EDecimal.PositiveInfinity, 123 | valueEdTmp); 124 | { 125 | object objectTemp = EDecimal.NegativeInfinity; 126 | object objectTemp2 = EDecimal.FromString( 127 | "-9.3168444507547E+28").RoundToPrecision(EContext.CliDecimal); 128 | Assert.AreEqual(objectTemp, objectTemp2); 129 | } 130 | { 131 | string stringTemp = 132 | 133 | EDecimal.FromString( 134 | "-9344285899206687626894794544.04982268810272216796875") 135 | .RoundToPrecision(EContext.CliDecimal).ToPlainString(); 136 | Assert.AreEqual( 137 | "-9344285899206687626894794544", 138 | stringTemp); 139 | } 140 | { 141 | object objectTemp = EDecimal.PositiveInfinity; 142 | object objectTemp2 = EDecimal.FromString( 143 | "96148154858060747311034406200").RoundToPrecision( 144 | EContext.CliDecimal); 145 | Assert.AreEqual(objectTemp, objectTemp2); 146 | } 147 | { 148 | object objectTemp = EDecimal.PositiveInfinity; 149 | object objectTemp2 = EDecimal.FromString( 150 | "90246605365627217170000000000").RoundToPrecision( 151 | EContext.CliDecimal); 152 | Assert.AreEqual(objectTemp, objectTemp2); 153 | } 154 | } 155 | 156 | [Test] 157 | public void TestForPrecision() { 158 | // not implemented yet 159 | } 160 | [Test] 161 | public void TestForPrecisionAndRounding() { 162 | // not implemented yet 163 | } 164 | [Test] 165 | public void TestForRounding() { 166 | EContext ctx; 167 | ctx = EContext.ForRounding(ERounding.HalfEven); 168 | Assert.AreEqual(ERounding.HalfEven, ctx.Rounding); 169 | ctx = EContext.ForRounding(ERounding.HalfUp); 170 | Assert.AreEqual(ERounding.HalfUp, ctx.Rounding); 171 | } 172 | [Test] 173 | public void TestHasExponentRange() { 174 | // not implemented yet 175 | } 176 | [Test] 177 | public void TestHasFlags() { 178 | // not implemented yet 179 | } 180 | [Test] 181 | public void TestHasMaxPrecision() { 182 | // not implemented yet 183 | } 184 | [Test] 185 | public void TestIsPrecisionInBits() { 186 | // not implemented yet 187 | } 188 | [Test] 189 | public void TestIsSimplified() { 190 | // not implemented yet 191 | } 192 | [Test] 193 | public void TestPrecision() { 194 | // not implemented yet 195 | } 196 | [Test] 197 | public void TestRounding() { 198 | // not implemented yet 199 | } 200 | [Test] 201 | public void TestToString() { 202 | if (EContext.Unlimited.ToString() == null) { 203 | Assert.Fail(); 204 | } 205 | } 206 | [Test] 207 | public void TestTraps() { 208 | // not implemented yet 209 | } 210 | [Test] 211 | public void TestWithAdjustExponent() { 212 | // not implemented yet 213 | } 214 | [Test] 215 | public void TestWithBigExponentRange() { 216 | // not implemented yet 217 | } 218 | [Test] 219 | public void TestWithBigPrecision() { 220 | try { 221 | EContext.Unlimited.WithBigPrecision(null); 222 | Assert.Fail("Should have failed"); 223 | } catch (ArgumentNullException) { 224 | // NOTE: Intentionally empty 225 | } catch (Exception ex) { 226 | Assert.Fail(ex.ToString()); 227 | throw new InvalidOperationException(String.Empty, ex); 228 | } 229 | try { 230 | EContext.Unlimited.WithBigPrecision(EInteger.One.Negate()); 231 | Assert.Fail("Should have failed"); 232 | } catch (ArgumentException) { 233 | // NOTE: Intentionally empty 234 | } catch (Exception ex) { 235 | Assert.Fail(ex.ToString()); 236 | throw new InvalidOperationException(String.Empty, ex); 237 | } 238 | } 239 | [Test] 240 | public void TestWithBlankFlags() { 241 | // not implemented yet 242 | } 243 | [Test] 244 | public void TestWithExponentClamp() { 245 | // not implemented yet 246 | } 247 | [Test] 248 | public void TestWithExponentRange() { 249 | try { 250 | EContext.Unlimited.WithExponentRange(1, 0); 251 | Assert.Fail("Should have failed"); 252 | } catch (ArgumentException) { 253 | // NOTE: Intentionally empty 254 | } catch (Exception ex) { 255 | Assert.Fail(ex.ToString()); 256 | throw new InvalidOperationException(String.Empty, ex); 257 | } 258 | try { 259 | EContext.Unlimited.WithBigExponentRange(null, EInteger.Zero); 260 | Assert.Fail("Should have failed"); 261 | } catch (ArgumentNullException) { 262 | // NOTE: Intentionally empty 263 | } catch (Exception ex) { 264 | Assert.Fail(ex.ToString()); 265 | throw new InvalidOperationException(String.Empty, ex); 266 | } 267 | try { 268 | EContext.Unlimited.WithBigExponentRange(EInteger.Zero, null); 269 | Assert.Fail("Should have failed"); 270 | } catch (ArgumentNullException) { 271 | // NOTE: Intentionally empty 272 | } catch (Exception ex) { 273 | Assert.Fail(ex.ToString()); 274 | throw new InvalidOperationException(String.Empty, ex); 275 | } 276 | try { 277 | EInteger bigintBig = EInteger.One << 64; 278 | EContext.Unlimited.WithBigExponentRange( 279 | bigintBig, 280 | EInteger.Zero); 281 | Assert.Fail("Should have failed"); 282 | } catch (ArgumentException) { 283 | // NOTE: Intentionally empty 284 | } catch (Exception ex) { 285 | Assert.Fail(ex.ToString()); 286 | throw new InvalidOperationException(String.Empty, ex); 287 | } 288 | } 289 | [Test] 290 | public void TestWithNoFlags() { 291 | // not implemented yet 292 | } 293 | [Test] 294 | public void TestWithPrecision() { 295 | try { 296 | EContext.Unlimited.WithPrecision(-1); 297 | Assert.Fail("Should have failed"); 298 | } catch (ArgumentException) { 299 | // NOTE: Intentionally empty 300 | } catch (Exception ex) { 301 | Assert.Fail(ex.ToString()); 302 | throw new InvalidOperationException(String.Empty, ex); 303 | } 304 | EContext ctx; 305 | ctx = EContext.Unlimited.WithPrecision(6); 306 | Assert.AreEqual((EInteger)6, ctx.Precision); 307 | } 308 | [Test] 309 | public void TestWithPrecisionInBits() { 310 | // not implemented yet 311 | } 312 | [Test] 313 | public void TestWithRounding() { 314 | // not implemented yet 315 | } 316 | [Test] 317 | public void TestWithSimplified() { 318 | var pc = new EContext(0, ERounding.HalfUp, 0, 5, true); 319 | Assert.IsFalse(pc.IsSimplified); 320 | pc = pc.WithSimplified(true); 321 | Assert.IsTrue(pc.IsSimplified); 322 | pc = pc.WithSimplified(false); 323 | Assert.IsFalse(pc.IsSimplified); 324 | } 325 | [Test] 326 | public void TestWithTraps() { 327 | // not implemented yet 328 | } 329 | [Test] 330 | public void TestWithUnlimitedExponents() { 331 | var pc = new EContext(0, ERounding.HalfUp, 0, 5, true); 332 | Assert.IsTrue(pc.HasExponentRange); 333 | pc = pc.WithUnlimitedExponents(); 334 | Assert.IsFalse(pc.HasExponentRange); 335 | } 336 | } 337 | } 338 | -------------------------------------------------------------------------------- /Test/ETrapExceptionTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework; 3 | 4 | namespace Test { 5 | [TestFixture] 6 | public class ETrapExceptionTest { 7 | [Test] 8 | public void TestConstructor() { 9 | // not implemented yet 10 | } 11 | [Test] 12 | public void TestContext() { 13 | // not implemented yet 14 | } 15 | [Test] 16 | public void TestError() { 17 | // not implemented yet 18 | } 19 | [Test] 20 | public void TestResult() { 21 | // not implemented yet 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Test/ExtensiveTest.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Written by Peter O. 3 | Any copyright to this work is released to the Public Domain. 4 | In case this is not possible, this work is also 5 | licensed under the Unlicense: https://unlicense.org/ 6 | 7 | */ 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Diagnostics; 11 | using System.IO; 12 | using System.Text.RegularExpressions; 13 | using NUnit.Framework; 14 | using PeterO; 15 | using PeterO.Numbers; 16 | 17 | namespace Test { 18 | [TestFixture] 19 | public class ExtensiveTest { 20 | public static string[] GetTestFiles() { 21 | try { 22 | var path = Path.GetDirectoryName( 23 | System.Reflection.Assembly.GetExecutingAssembly().Location); 24 | var list = new List( 25 | Directory.GetFiles(path)); 26 | list.Sort(); 27 | return list.ToArray(); 28 | } catch (IOException) { 29 | return new string[0]; 30 | } 31 | } 32 | 33 | [System.Diagnostics.Conditional("DEBUG")] 34 | public static void IgnoreIfDebug() { 35 | Assert.Ignore(); 36 | } 37 | 38 | [Test] 39 | [Timeout(300000)] 40 | public void TestParser() { 41 | var errors = new List(); 42 | var dirfiles = new List(); 43 | var slowlines = new List(); 44 | var sw = new System.Diagnostics.Stopwatch(); 45 | sw.Start(); 46 | var valueSwProcessing = new System.Diagnostics.Stopwatch(); 47 | var standardOut = Console.Out; 48 | var x = 0; 49 | dirfiles.AddRange(GetTestFiles()); 50 | foreach (var f in dirfiles) { 51 | ++x; 52 | var context = new Dictionary(); 53 | var lowerF = DecTestUtil.ToLowerCaseAscii(f); 54 | if (!DecTestUtil.Contains(lowerF, ".input") && 55 | !DecTestUtil.Contains(lowerF, ".txt") && 56 | !DecTestUtil.Contains(lowerF, ".dectest") && 57 | !DecTestUtil.Contains(lowerF, ".fptest")) { 58 | continue; 59 | } 60 | Console.WriteLine((sw.ElapsedMilliseconds / 1000.0) + " " + f); 61 | var i = 0; 62 | using (var w = new StreamReader(f)) { 63 | while (!w.EndOfStream) { 64 | var ln = w.ReadLine(); 65 | ++i; 66 | double em = sw.ElapsedMilliseconds / 1000.0; 67 | valueSwProcessing.Start(); 68 | DecTestUtil.ParseDecTest(ln, context); 69 | valueSwProcessing.Stop(); 70 | double em2 = sw.ElapsedMilliseconds / 1000.0; 71 | if (em2 - em > 1) { 72 | foreach (var k in context.Keys) { 73 | slowlines.Add(k + ": " + context[k]); 74 | } 75 | slowlines.Add(ln); 76 | Console.WriteLine( 77 | ln.Substring(0, Math.Min(ln.Length, 200))); 78 | Console.WriteLine("Processing time: " + (em2 - em) + " s"); 79 | } 80 | } 81 | } 82 | } 83 | sw.Stop(); 84 | // Total running time 85 | Console.WriteLine("Time: " + (sw.ElapsedMilliseconds / 1000.0) + " s"); 86 | // Number processing time 87 | Console.WriteLine("ProcTime: " + (valueSwProcessing.ElapsedMilliseconds / 88 | 1000.0) + " s"); 89 | // Ratio of number processing time to total running time 90 | Console.WriteLine("Rate: " + (valueSwProcessing.ElapsedMilliseconds * 91 | 100.0 / sw.ElapsedMilliseconds) + "%"); 92 | // System.IO.File.WriteAllLines("slow.dectest",slowlines.ToArray()); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /Test/ExtraTest.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Written by Peter O. 3 | Any copyright to this work is released to the Public Domain. 4 | In case this is not possible, this work is also 5 | licensed under the Unlicense: https://unlicense.org/ 6 | 7 | */ 8 | using System; 9 | using NUnit.Framework; 10 | using PeterO.Numbers; 11 | 12 | namespace Test { 13 | public static class ExtraTest { 14 | public static void TestStringEqualRoundTrip(EDecimal obj) { 15 | if (obj == null) { 16 | throw new ArgumentNullException(nameof(obj)); 17 | } 18 | string str = obj.ToString(); 19 | EDecimal newobj = EDecimal.FromString(str); 20 | if (str.Length < 100 || !obj.Equals(newobj)) { 21 | TestCommon.AssertEqualsHashCode(obj, newobj); 22 | string str2 = newobj.ToString(); 23 | TestCommon.AssertEqualsHashCode(str, str2); 24 | } 25 | } 26 | 27 | public static void TestStringEqualRoundTrip(ERational obj) { 28 | if (obj == null) { 29 | throw new ArgumentNullException(nameof(obj)); 30 | } 31 | string str = obj.ToString(); 32 | ERational newobj = ERational.FromString(str); 33 | if (str.Length < 100 || !obj.Equals(newobj)) { 34 | TestCommon.AssertEqualsHashCode(obj, newobj); 35 | string str2 = newobj.ToString(); 36 | TestCommon.AssertEqualsHashCode(str, str2); 37 | } 38 | } 39 | public static void TestStringEqualRoundTrip(EInteger obj) { 40 | if (obj == null) { 41 | throw new ArgumentNullException(nameof(obj)); 42 | } 43 | string str = obj.ToString(); 44 | EInteger newobj = EInteger.FromString(str); 45 | if (str.Length < 100 || !obj.Equals(newobj)) { 46 | TestCommon.AssertEqualsHashCode(obj, newobj); 47 | string str2 = newobj.ToString(); 48 | TestCommon.AssertEqualsHashCode(str, str2); 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Test/IRandomGen.cs: -------------------------------------------------------------------------------- 1 | namespace PeterO { 2 | /// Interface for random-number generators. 3 | public interface IRandomGen { 4 | /// Randomly generates a set of bytes. 5 | /// Byte buffer to store the random bytes. 6 | /// A zero-based index showing where the desired 7 | /// portion of begins. 8 | /// The length, in bytes, of the desired portion 9 | /// of (but not more than 's length). 11 | /// Number of bytes returned. 12 | int GetBytes(byte[] bytes, int offset, int length); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Test/IRandomGenExtended.cs: -------------------------------------------------------------------------------- 1 | namespace PeterO { 2 | public interface IRandomGenExtended : IRandomGen { 3 | int GetInt32(int maxExclusive); 4 | 5 | long GetInt64(long maxExclusive); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Test/README.md: -------------------------------------------------------------------------------- 1 | Note 2 | ---- 3 | 4 | The test program will read the following test files, which 5 | must be placed in the same folder as the program: 6 | 7 | * Decimal test files in the *.decTest format, 8 | which is described at . 9 | * Binary floating point test files in the *.fptest format, 10 | which is described at . 11 | * Test cases in the *.input format, from . 12 | * Decimal test cases in *.txt format, from . 13 | -------------------------------------------------------------------------------- /Test/RandomNumerics.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Written by Peter O. 3 | Any copyright to this work is released to the Public Domain. 4 | In case this is not possible, this work is also 5 | licensed under the Unlicense: https://unlicense.org/ 6 | 7 | */ 8 | using System; 9 | using System.Text; 10 | using PeterO; 11 | using PeterO.Numbers; 12 | 13 | namespace Test { 14 | /// Generates random objects of various kinds for purposes of 15 | /// testing code that uses them. The methods will not necessarily 16 | /// sample uniformly from all objects of a particular kind. 17 | public static class RandomNumerics { 18 | private const int MaxExclusiveStringLength = 0x2000; 19 | private const int MaxExclusiveShortStringLength = 50; 20 | private const int MaxNumberLength = 50000; 21 | private const int MaxShortNumberLength = 40; 22 | 23 | public static ERational RandomERational(IRandomGenExtended rand) { 24 | EInteger bigintA = RandomEInteger(rand); 25 | EInteger bigintB = RandomEInteger(rand); 26 | if (bigintB.IsZero) { 27 | bigintB = EInteger.One; 28 | } 29 | return ERational.Create(bigintA, bigintB); 30 | } 31 | 32 | public static EDecimal GenerateEDecimalSmall(IRandomGenExtended wrapper) { 33 | if (wrapper == null) { 34 | throw new ArgumentNullException(nameof(wrapper)); 35 | } 36 | if (wrapper.GetInt32(2) == 0) { 37 | var eix = EInteger.FromBytes( 38 | RandomObjects.RandomByteString(wrapper, 1 + wrapper.GetInt32(36)), 39 | true); 40 | int exp = wrapper.GetInt32(25) - 12; 41 | return EDecimal.Create(eix, exp); 42 | } 43 | return 44 | EDecimal.FromString(RandomObjects.RandomDecimalStringShort(wrapper, false)); 45 | } 46 | 47 | public static EDecimal RandomEDecimal(IRandomGenExtended r) { 48 | return RandomEDecimal(r, null); 49 | } 50 | 51 | public static EDecimal RandomEDecimal(IRandomGenExtended r, string[] 52 | decimalString) { 53 | if (r == null) { 54 | throw new ArgumentNullException(nameof(r)); 55 | } 56 | if (r.GetInt32(100) == 0) { 57 | int x = r.GetInt32(3); 58 | if (x == 0) { 59 | if (decimalString != null) { 60 | decimalString[0] = "Infinity"; 61 | } 62 | return EDecimal.PositiveInfinity; 63 | } 64 | if (x == 1) { 65 | if (decimalString != null) { 66 | decimalString[0] = "-Infinity"; 67 | } 68 | return EDecimal.NegativeInfinity; 69 | } 70 | if (x == 2) { 71 | if (decimalString != null) { 72 | decimalString[0] = "NaN"; 73 | } 74 | return EDecimal.NaN; 75 | } 76 | // Signaling NaN currently not generated because 77 | // it doesn't round-trip as well 78 | } 79 | if (r.GetInt32(100) < 30) { 80 | string str = RandomObjects.RandomDecimalString(r); 81 | if (str.Length < 500) { 82 | if (decimalString != null) { 83 | decimalString[0] = str; 84 | } 85 | return EDecimal.FromString(str); 86 | } 87 | } 88 | EInteger emant = RandomEInteger(r); 89 | EInteger eexp; 90 | if (r.GetInt32(100) < 95) { 91 | int exp = (r.GetInt32(100) < 80) ? (r.GetInt32(50) - 25) : 92 | (r.GetInt32(5000) - 2500); 93 | eexp = EInteger.FromInt32(exp); 94 | } else { 95 | eexp = RandomEInteger(r); 96 | } 97 | var ed = EDecimal.Create(emant, eexp); 98 | if (decimalString != null) { 99 | decimalString[0] = emant.ToString() + "E" + eexp.ToString(); 100 | } 101 | return ed; 102 | } 103 | 104 | private static EInteger BitHeavyEInteger(IRandomGenExtended rg, int count) { 105 | var sb = new StringBuilder(); 106 | int[] oneChances = { 107 | 999, 1, 980, 20, 750, 250, 980, 108 | 20, 980, 20, 980, 20, 750, 250, 109 | }; 110 | int oneChance = oneChances[rg.GetInt32(oneChances.Length)]; 111 | for (int i = 0; i < count; ++i) { 112 | _ = sb.Append((rg.GetInt32(1000) >= oneChance) ? '0' : '1'); 113 | } 114 | return EInteger.FromRadixString(sb.ToString(), 2); 115 | } 116 | 117 | private static EInteger DigitHeavyEInteger(IRandomGenExtended rg, int 118 | count) { 119 | var sb = new StringBuilder(); 120 | int[] oneChances = { 121 | 999, 1, 980, 20, 750, 250, 980, 122 | 20, 980, 20, 980, 20, 750, 250, 123 | }; 124 | int oneChance = oneChances[rg.GetInt32(oneChances.Length)]; 125 | for (int i = 0; i < count; ++i) { 126 | _ = sb.Append((rg.GetInt32(1000) >= oneChance) ? '0' : '9'); 127 | } 128 | return EInteger.FromRadixString(sb.ToString(), 10); 129 | } 130 | 131 | public static EInteger RandomEInteger(IRandomGenExtended r) { 132 | if (r == null) { 133 | throw new ArgumentNullException(nameof(r)); 134 | } 135 | int selection = r.GetInt32(100); 136 | if (selection < 10) { 137 | int count = r.GetInt32(MaxNumberLength); 138 | count = (int)((long)count * r.GetInt32(MaxNumberLength) / 139 | MaxNumberLength); 140 | count = (int)((long)count * r.GetInt32(MaxNumberLength) / 141 | MaxNumberLength); 142 | count = Math.Max(count, 1); 143 | if (selection is 0 or 1) { 144 | return BitHeavyEInteger(r, count); 145 | } else if ((selection == 2 || selection == 3) && count < 500) { 146 | return DigitHeavyEInteger(r, count); 147 | } 148 | byte[] bytes = RandomObjects.RandomByteString(r, count); 149 | return EInteger.FromBytes(bytes, true); 150 | } else { 151 | byte[] bytes = RandomObjects.RandomByteString( 152 | r, 153 | r.GetInt32(MaxShortNumberLength) + 1); 154 | return EInteger.FromBytes(bytes, true); 155 | } 156 | } 157 | 158 | public static EInteger RandomEIntegerSmall(IRandomGenExtended r) { 159 | if (r == null) { 160 | throw new ArgumentNullException(nameof(r)); 161 | } 162 | byte[] bytes = RandomObjects.RandomByteString( 163 | r, 164 | r.GetInt32(MaxShortNumberLength) + 1); 165 | return EInteger.FromBytes(bytes, true); 166 | } 167 | 168 | private static int IntInRange(IRandomGenExtended rg, int minInc, int 169 | maxExc) { 170 | return minInc + rg.GetInt32(maxExc - minInc); 171 | } 172 | 173 | public static EFloat CloseToPowerOfTwo(IRandomGenExtended rg) { 174 | if (rg == null) { 175 | throw new ArgumentNullException(nameof(rg)); 176 | } 177 | int pwr = (rg.GetInt32(100) < 80) ? IntInRange(rg, -20, 20) : 178 | IntInRange(rg, -300, 300); 179 | int pwr2 = pwr - (rg.GetInt32(100) < 80 ? IntInRange(rg, 51, 61) : 180 | IntInRange(rg, 2, 300)); 181 | EFloat ef = rg.GetInt32(2) == 0 ? EFloat.Create(1, 182 | pwr).Add(EFloat.Create(1, pwr2)) : EFloat.Create(1, 183 | pwr).Subtract(EFloat.Create(1, pwr2)); 184 | if (rg.GetInt32(10) == 0) { 185 | pwr2 = pwr - (rg.GetInt32(100) < 80 ? IntInRange(rg, 51, 61) : 186 | IntInRange(rg, 2, 300)); 187 | ef = (rg.GetInt32(2) == 0) ? ef.Add(EFloat.Create(1, pwr2)) : 188 | ef.Subtract(EFloat.Create(1, pwr2)); 189 | } 190 | return ef; 191 | } 192 | 193 | public static EFloat RandomEFloat(IRandomGenExtended r) { 194 | if (r == null) { 195 | throw new ArgumentNullException(nameof(r)); 196 | } 197 | if (r.GetInt32(100) == 0) { 198 | int x = r.GetInt32(3); 199 | if (x == 0) { 200 | return EFloat.PositiveInfinity; 201 | } 202 | if (x == 1) { 203 | return EFloat.NegativeInfinity; 204 | } 205 | if (x == 2) { 206 | return EFloat.NaN; 207 | } 208 | } 209 | return r.GetInt32(100) == 3 ? 210 | CloseToPowerOfTwo(r) : EFloat.Create( 211 | RandomEInteger(r), 212 | (EInteger)(r.GetInt32(400) - 200)); 213 | } 214 | 215 | public static EInteger RandomSmallIntegral(IRandomGenExtended r) { 216 | return EInteger.FromString(RandomObjects.RandomSmallIntegralString(r)); 217 | } 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /Test/Runner.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Written by Peter O. 3 | Any copyright to this work is released to the Public Domain. 4 | In case this is not possible, this work is also 5 | licensed under the Unlicense: https://unlicense.org/ 6 | */ 7 | using System; 8 | using PeterO.Numbers; 9 | 10 | namespace PeterO { 11 | /// Description of Runner. 12 | public static class Runner { 13 | public static void Main() { 14 | new Test.EDecimalTest().TestToString(); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Test/SevenBitEncoded.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using PeterO.Numbers; 4 | namespace Test { 5 | public static class SevenBitEncoded { 6 | private static void Write7BitEncoded(Stream outputStream, EInteger ei) { 7 | if (outputStream == null) { 8 | throw new ArgumentNullException(nameof(outputStream)); 9 | } 10 | if (ei.Sign < 0) { 11 | throw new ArgumentOutOfRangeException(nameof(ei)); 12 | } 13 | if (ei.IsZero) { 14 | outputStream.WriteByte(0); 15 | return; 16 | } 17 | var tmp = new byte[4]; 18 | while (!ei.IsZero) { 19 | int chunk = ei.ToInt32Unchecked() & 0xfffffff; 20 | ei = ei.ShiftRight(7); 21 | if (ei.IsZero) { 22 | var chunksize = 0; 23 | tmp[chunksize++] = (byte)chunk; 24 | if (chunk <= 0x7f) { 25 | outputStream.WriteByte((byte)chunk); 26 | } else if (chunk > 0x3fff) { 27 | tmp[0] = (byte)(0x80 | (chunk & 0x7f)); 28 | tmp[1] = (byte)((chunk >> 7) & 0x7f); 29 | outputStream.Write(tmp, 0, 2); 30 | } else if (chunk > 0x1fffff) { 31 | tmp[0] = (byte)(0x80 | (chunk & 0x7f)); 32 | tmp[1] = (byte)(0x80 | ((chunk >> 7) & 0x7f)); 33 | tmp[2] = (byte)((chunk >> 14) & 0x7f); 34 | outputStream.Write(tmp, 0, 3); 35 | } else { 36 | tmp[0] = (byte)(0x80 | (chunk & 0x7f)); 37 | tmp[1] = (byte)(0x80 | ((chunk >> 7) & 0x7f)); 38 | tmp[2] = (byte)(0x80 | ((chunk >> 14) & 0x7f)); 39 | tmp[3] = (byte)((chunk >> 21) & 0x7f); 40 | outputStream.Write(tmp, 0, 4); 41 | } 42 | } else { 43 | tmp[0] = (byte)(0x80 | (chunk & 0x7f)); 44 | tmp[1] = (byte)(0x80 | ((chunk >> 7) & 0x7f)); 45 | tmp[2] = (byte)(0x80 | ((chunk >> 14) & 0x7f)); 46 | tmp[3] = (byte)(0x80 | ((chunk >> 21) & 0x7f)); 47 | outputStream.Write(tmp, 0, 4); 48 | } 49 | } 50 | } 51 | 52 | private static EInteger Read7BitEncoded(Stream inputStream, EInteger 53 | maxValue) { 54 | if (inputStream == null) { 55 | throw new ArgumentNullException(nameof(inputStream)); 56 | } 57 | EInteger ei = EInteger.Zero; 58 | EInteger shift = EInteger.Zero; 59 | var endOfValue = false; 60 | bool haveMaxValue = maxValue != null && maxValue.Sign >= 0; 61 | while (!endOfValue) { 62 | var tmp = 0; 63 | var b = 0; 64 | var smallshift = 0; 65 | for (var i = 0; i < 4; ++i) { 66 | b = inputStream.ReadByte(); 67 | if (b < 0) { 68 | throw new IOException("End of stream"); 69 | } 70 | tmp += (b & 0x7f) << smallshift; 71 | if ((b & 0x80) == 0) { 72 | endOfValue = true; 73 | break; 74 | } 75 | smallshift += 7; 76 | } 77 | ei = ei.Add(EInteger.FromInt32(tmp).ShiftLeft(shift)); 78 | if (haveMaxValue && ei.CompareTo(maxValue) > 0) { 79 | throw new IOException("Value read is too high"); 80 | } 81 | shift = shift.Add(28); 82 | } 83 | return ei; 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /Test/StringAndBigInt.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using PeterO; 4 | using PeterO.Numbers; 5 | 6 | namespace Test { 7 | internal sealed class StringAndBigInt { 8 | private const string ValueDigits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 9 | 10 | private const string ValueDigitsLower = 11 | "0123456789abcdefghijklmnopqrstuvwxyz"; 12 | 13 | public string StringValue { 14 | get; 15 | private set; 16 | } 17 | 18 | public EInteger BigIntValue { 19 | get; 20 | private set; 21 | } 22 | 23 | private StringAndBigInt(string sv, EInteger biv) { 24 | this.StringValue = sv; 25 | this.BigIntValue = biv; 26 | } 27 | 28 | public static StringAndBigInt Generate(IRandomGenExtended rand, int radix) { 29 | return Generate(rand, radix, 50); 30 | } 31 | 32 | public static StringAndBigInt Generate( 33 | IRandomGenExtended rand, 34 | int radix, 35 | int maxNumDigits) { 36 | if (radix < 2) { 37 | throw new ArgumentException("radix(" + radix + 38 | ") is less than 2"); 39 | } 40 | if (radix > 36) { 41 | throw new ArgumentException("radix(" + radix + 42 | ") is more than 36"); 43 | } 44 | EInteger bv = EInteger.Zero; 45 | int numDigits = 1 + rand.GetInt32(maxNumDigits); 46 | var negative = false; 47 | var builder = new StringBuilder(); 48 | if (rand.GetInt32(2) == 0) { 49 | _ = builder.Append('-'); 50 | negative = true; 51 | } 52 | int radixpowint = radix * radix * radix * radix; 53 | var radixpow4 = EInteger.FromInt32(radixpowint); 54 | var radixpow1 = EInteger.FromInt32(radix); 55 | var count = 0; 56 | for (int i = 0; i < numDigits - 4; i += 4) { 57 | int digitvalues = rand.GetInt32(radixpowint); 58 | int digit = digitvalues % radix; 59 | digitvalues /= radix; 60 | int digit2 = digitvalues % radix; 61 | digitvalues /= radix; 62 | int digit3 = digitvalues % radix; 63 | digitvalues /= radix; 64 | int digit4 = digitvalues % radix; 65 | count += 4; 66 | int bits = rand.GetInt32(16); 67 | builder = (bits & 0x01) == 0 ? builder.Append(ValueDigits[digit]) : 68 | builder.Append(ValueDigitsLower[digit]); 69 | builder = (bits & 0x02) == 0 ? builder.Append(ValueDigits[digit2]) : 70 | builder.Append(ValueDigitsLower[digit2]); 71 | builder = (bits & 0x04) == 0 ? builder.Append(ValueDigits[digit3]) : 72 | builder.Append(ValueDigitsLower[digit3]); 73 | builder = (bits & 0x08) == 0 ? builder.Append(ValueDigits[digit4]) : 74 | builder.Append(ValueDigitsLower[digit4]); 75 | int digits = (((((digit * radix) + digit2) * 76 | radix) + digit3) * radix) + digit4; 77 | bv *= radixpow4; 78 | var bigintTmp = (EInteger)digits; 79 | bv += bigintTmp; 80 | } 81 | for (int i = count; i < numDigits; ++i) { 82 | int digit = rand.GetInt32(radix); 83 | builder = rand.GetInt32(2) == 0 ? builder.Append(ValueDigits[digit]) : 84 | builder.Append(ValueDigitsLower[digit]); 85 | bv *= radixpow1; 86 | var bigintTmp = (EInteger)digit; 87 | bv += bigintTmp; 88 | } 89 | if (negative) { 90 | bv = -bv; 91 | } 92 | return new StringAndBigInt(builder.ToString(), bv); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /Test/Test.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net9.0 4 | false 5 | true 6 | 7 | 8 | full 9 | rules.ruleset 10 | 11 | none 12 | rules.ruleset 13 | 14 | 15 | 16 | 17 | Resources.resources 18 | 19 | 20 | 21 | 22 | 23 | runtime; build; native; contentfiles; analyzers; buildtransitive 24 | all 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /Test/XorShift128Plus.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace PeterO { 4 | /// A class that implements a statistically-random byte 5 | /// generator, using Sebastiano Vigna's 6 | /// xorshift128+ 8 | /// RNG as the underlying implementation. This class is safe for 9 | /// concurrent use among multiple threads. 10 | public class XorShift128Plus : IRandomGen { 11 | private readonly long[] s = new long[2]; 12 | private object syncRoot = new Object(); 13 | 14 | public XorShift128Plus() { 15 | this.Seed(); 16 | } 17 | 18 | public int GetBytes(byte[] bytes, int offset, int length) { 19 | if (bytes == null) { 20 | throw new ArgumentNullException(nameof(bytes)); 21 | } 22 | if (offset < 0) { 23 | throw new ArgumentException("offset(" + offset + 24 | ") is less than 0"); 25 | } 26 | if (offset > bytes.Length) { 27 | throw new ArgumentException("offset(" + offset + 28 | ") is more than " + bytes.Length); 29 | } 30 | if (length < 0) { 31 | throw new ArgumentException("length(" + length + 32 | ") is less than 0"); 33 | } 34 | if (length > bytes.Length) { 35 | throw new ArgumentException("length(" + length + 36 | ") is more than " + bytes.Length); 37 | } 38 | if (bytes.Length - offset < length) { 39 | throw new ArgumentException("bytes's length minus " + offset + "(" + 40 | (bytes.Length - offset) + ") is less than " + length); 41 | } 42 | int count = length; 43 | lock (this.syncRoot) { 44 | while (length >= 8) { 45 | long nv = this.NextValue(); 46 | bytes[offset++] = unchecked((byte)nv); 47 | nv >>= 8; 48 | bytes[offset++] = unchecked((byte)nv); 49 | nv >>= 8; 50 | bytes[offset++] = unchecked((byte)nv); 51 | nv >>= 8; 52 | bytes[offset++] = unchecked((byte)nv); 53 | nv >>= 8; 54 | bytes[offset++] = unchecked((byte)nv); 55 | nv >>= 8; 56 | bytes[offset++] = unchecked((byte)nv); 57 | nv >>= 8; 58 | bytes[offset++] = unchecked((byte)nv); 59 | nv >>= 8; 60 | bytes[offset++] = unchecked((byte)nv); 61 | length -= 8; 62 | } 63 | if (length != 0) { 64 | long nv = this.NextValue(); 65 | while (length > 0) { 66 | bytes[offset++] = unchecked((byte)nv); 67 | nv >>= 8; 68 | --length; 69 | } 70 | } 71 | } 72 | return count; 73 | } 74 | 75 | // xorshift128 + generator 76 | // http://xorshift.di.unimi.it/xorshift128plus.c 77 | private long NextValue() { 78 | long s1 = this.s[0]; 79 | long s0 = this.s[1]; 80 | this.s[0] = s0; 81 | s1 ^= s1 << 23; 82 | long t1 = (s1 >> 18) & 0x3fffffffffffL; 83 | long t0 = (s0 >> 5) & 0x7ffffffffffffffL; 84 | this.s[1] = s1 ^ s0 ^ t1 ^ t0; 85 | return unchecked(this.s[1] + s0); 86 | } 87 | 88 | private void Seed() { 89 | long lb = DateTime.Now.Ticks & 0xffffffffffL; 90 | this.s[0] = lb; 91 | lb = 0L; 92 | this.s[1] = lb; 93 | if ((this.s[0] | this.s[1]) == 0) { 94 | ++this.s[0]; 95 | } 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Test/rules.ruleset: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Test/stylecop.json: -------------------------------------------------------------------------------- 1 | {"settings":{"documentationRules":{"documentInternalElements":false,"documentInterfaces":false},"orderingRules":{"usingDirectivesPlacement":"outsideNamespace"}}} 2 | -------------------------------------------------------------------------------- /Test20/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | 4 | [assembly: AssemblyTitle("Test20")] 5 | [assembly: AssemblyDescription("")] 6 | [assembly: AssemblyConfiguration("")] 7 | [assembly: AssemblyCompany("")] 8 | [assembly: AssemblyProduct("")] 9 | [assembly: AssemblyCopyright("rooster")] 10 | [assembly: AssemblyTrademark("")] 11 | [assembly: AssemblyCulture("")] 12 | [assembly: AssemblyVersion("1.0")] 13 | -------------------------------------------------------------------------------- /Test20/Test20.csproj: -------------------------------------------------------------------------------- 1 | DebugAnyCPU{4CF0E5BA-CDE3-4DEA-B3F4-11EE544B3FB2}ExeTest20v2.0rules.rulesetwintruetruefullfalsebin\DebugDEBUG;NET20prompt4truerules.rulesettruebin\ReleasepromptNET204truerules.ruleset2.0.01.1.1187.0.3stylecop.jsonETrapExceptionTest.csIRandomGenExtended.csEIntegerTest.csStringAndBigInt.csRandomObjects.csEFloatTest.csRandomGenerator.csTestCommon.csDecTestUtil.csSevenBitEncoded.csRunner.csResources.restextResources.resourcesERationalTest.csAppResources.csEContextTest.csIRandomGen.csExtraTest.csExtensiveTest.csDecimalTest.csXorShift128Plus.csEDecimalTest.cs{04A7B845-E447-4A46-ABB9-D195BDEDC735}Test20 2 | -------------------------------------------------------------------------------- /Test20/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Test20/rules.ruleset: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Test20/stylecop.json: -------------------------------------------------------------------------------- 1 | {"settings":{"documentationRules":{"documentInternalElements":false,"documentInterfaces":false},"orderingRules":{"usingDirectivesPlacement":"outsideNamespace"}}} 2 | -------------------------------------------------------------------------------- /Test40/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | 4 | // Information about this assembly is defined by the following attributes. 5 | // Change them to the values specific to your project. 6 | [assembly: AssemblyTitle("Test40")] 7 | [assembly: AssemblyDescription("")] 8 | [assembly: AssemblyConfiguration("")] 9 | [assembly: AssemblyCompany("")] 10 | [assembly: AssemblyProduct("")] 11 | [assembly: AssemblyCopyright("rooster")] 12 | [assembly: AssemblyTrademark("")] 13 | [assembly: AssemblyCulture("")] 14 | [assembly: AssemblyVersion("1.0")] 15 | -------------------------------------------------------------------------------- /Test40/Test40.csproj: -------------------------------------------------------------------------------- 1 | 2 | DebugAnyCPU{00EB31B6-A805-4EFB-A64B-9F8176B2A1CC}ExeTest40rules.rulesettruefullfalsebin\DebugDEBUG;NET40prompt4 3 | true 4 | rules.ruleset 5 | truebin\ReleasepromptNET404truerules.ruleset 6 | 3.12.01.1.1187.0.3stylecop.jsonETrapExceptionTest.csIRandomGenExtended.csEIntegerTest.csStringAndBigInt.csRandomObjects.csEFloatTest.csRandomGenerator.csTestCommon.csDecTestUtil.csSevenBitEncoded.csRunner.csResources.restextResources.resourcesERationalTest.csAppResources.csEContextTest.csIRandomGen.csExtraTest.csExtensiveTest.csDecimalTest.csXorShift128Plus.csEDecimalTest.cs{D7E09F55-3156-44B0-87D9-1BABCBB398D9}Test40 7 | v4.0win 8 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}. 9 | 10 | -------------------------------------------------------------------------------- /Test40/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Test40/rules.ruleset: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Test40/stylecop.json: -------------------------------------------------------------------------------- 1 | {"settings":{"documentationRules":{"documentInternalElements":false,"documentInterfaces":false},"orderingRules":{"usingDirectivesPlacement":"outsideNamespace"}}} 2 | -------------------------------------------------------------------------------- /docs/APIDocs.md: -------------------------------------------------------------------------------- 1 | ## API Documentation 2 | 3 | * [PeterO.Numbers.EContext](PeterO.Numbers.EContext.md) - Contains parameters for controlling the precision, rounding, and exponent range of arbitrary-precision numbers. 4 | 5 | * [PeterO.Numbers.EDecimal](PeterO.Numbers.EDecimal.md) - Represents an arbitrary-precision decimal floating-point number. 6 | 7 | * [PeterO.Numbers.EDecimals](PeterO.Numbers.EDecimals.md) - A class that implements additional operations on arbitrary-precision decimal numbers. 8 | 9 | * [PeterO.Numbers.EFloat](PeterO.Numbers.EFloat.md) - Represents an arbitrary-precision binary floating-point number. 10 | 11 | * [PeterO.Numbers.EFloats](PeterO.Numbers.EFloats.md) - A class that implements additional operations on arbitrary-precision binary floating-point numbers. 12 | 13 | * [PeterO.Numbers.EInteger](PeterO.Numbers.EInteger.md) - Represents an arbitrary-precision integer. 14 | 15 | * [PeterO.Numbers.ERational](PeterO.Numbers.ERational.md) - Represents an arbitrary-precision rational number. 16 | 17 | * [PeterO.Numbers.ERounding](PeterO.Numbers.ERounding.md) - Specifies the mode to use when "shortening" numbers that otherwise can't fit a given number of digits, so that the shortened number has about the same value. 18 | 19 | * [PeterO.Numbers.ETrapException](PeterO.Numbers.ETrapException.md) - Exception thrown for arithmetic trap errors. 20 | -------------------------------------------------------------------------------- /docs/PeterO.Numbers.ERounding.md: -------------------------------------------------------------------------------- 1 | ## PeterO.Numbers.ERounding 2 | 3 | public sealed struct ERounding : 4 | System.Enum, 5 | System.IComparable, 6 | System.IConvertible, 7 | System.IFormattable, 8 | System.ISpanFormattable 9 | 10 | Specifies the mode to use when "shortening" numbers that otherwise can't fit a given number of digits, so that the shortened number has about the same value. This "shortening" is known as rounding. (The "E" stands for "extended", and has this prefix to group it with the other classes common to this library, particularly EDecimal, EFloat, and ERational.). 11 | 12 | ### Member Summary 13 | * [public static PeterO.Numbers.ERounding Ceiling = 6;](#Ceiling) - If there is a fractional part, the number is rounded to the highest representable number that's closest to it. 14 | * [public static PeterO.Numbers.ERounding Down = 2;](#Down) - The fractional part is discarded (the number is truncated). 15 | * [public static PeterO.Numbers.ERounding Floor = 7;](#Floor) - If there is a fractional part, the number is rounded to the lowest representable number that's closest to it. 16 | * [public static PeterO.Numbers.ERounding HalfDown = 4;](#HalfDown) - Rounded to the nearest number; if the fractional part is exactly half, it is discarded. 17 | * [public static PeterO.Numbers.ERounding HalfEven = 5;](#HalfEven) - Rounded to the nearest number; if the fractional part is exactly half, the number is rounded to the closest representable number that is even. 18 | * [public static PeterO.Numbers.ERounding HalfUp = 3;](#HalfUp) - Rounded to the nearest number; if the fractional part is exactly half, the number is rounded to the closest representable number away from zero. 19 | * [public static PeterO.Numbers.ERounding None = 0;](#None) - Indicates that rounding will not be used. 20 | * [public static PeterO.Numbers.ERounding Odd = 8;](#Odd) - Obsolete: Consider using ERounding.OddOrZeroFiveUp instead. 21 | * [public static PeterO.Numbers.ERounding OddOrZeroFiveUp = 10;](#OddOrZeroFiveUp) - For binary floating point numbers, this is the same as Odd. 22 | * [public static PeterO.Numbers.ERounding Up = 1;](#Up) - If there is a fractional part, the number is rounded to the closest representable number away from zero. 23 | * [public static PeterO.Numbers.ERounding ZeroFiveUp = 9;](#ZeroFiveUp) - Obsolete: Use ERounding.OddOrZeroFiveUp instead. 24 | 25 | 26 | ### Ceiling 27 | 28 | public static PeterO.Numbers.ERounding Ceiling = 6; 29 | 30 | If there is a fractional part, the number is rounded to the highest representable number that's closest to it. 31 | 32 | 33 | ### Down 34 | 35 | public static PeterO.Numbers.ERounding Down = 2; 36 | 37 | The fractional part is discarded (the number is truncated). 38 | 39 | 40 | ### Floor 41 | 42 | public static PeterO.Numbers.ERounding Floor = 7; 43 | 44 | If there is a fractional part, the number is rounded to the lowest representable number that's closest to it. 45 | 46 | 47 | ### HalfDown 48 | 49 | public static PeterO.Numbers.ERounding HalfDown = 4; 50 | 51 | Rounded to the nearest number; if the fractional part is exactly half, it is discarded. 52 | 53 | 54 | ### HalfEven 55 | 56 | public static PeterO.Numbers.ERounding HalfEven = 5; 57 | 58 | Rounded to the nearest number; if the fractional part is exactly half, the number is rounded to the closest representable number that is even. This is sometimes also known as "banker's rounding". 59 | 60 | 61 | ### HalfUp 62 | 63 | public static PeterO.Numbers.ERounding HalfUp = 3; 64 | 65 | Rounded to the nearest number; if the fractional part is exactly half, the number is rounded to the closest representable number away from zero. This is the most familiar rounding mode for many people. 66 | 67 | 68 | ### None 69 | 70 | public static PeterO.Numbers.ERounding None = 0; 71 | 72 | Indicates that rounding will not be used. If rounding to an inexact value is required, the rounding operation will report an error. 73 | 74 | 75 | ### Odd 76 | 77 | public static PeterO.Numbers.ERounding Odd = 8; 78 | 79 | Obsolete. Consider using ERounding.OddOrZeroFiveUp instead. 80 | 81 | If there is a fractional part and the whole number part is even, the number is rounded to the closest representable odd number away from zero. 82 | 83 | 84 | ### OddOrZeroFiveUp 85 | 86 | public static PeterO.Numbers.ERounding OddOrZeroFiveUp = 10; 87 | 88 | For binary floating point numbers, this is the same as Odd. For other bases (including decimal numbers), this is the same as ZeroFiveUp. This rounding mode is useful for rounding intermediate results at a slightly higher precision (at least 2 bits more for binary) than the final precision. 89 | 90 | 91 | ### Up 92 | 93 | public static PeterO.Numbers.ERounding Up = 1; 94 | 95 | If there is a fractional part, the number is rounded to the closest representable number away from zero. 96 | 97 | 98 | ### ZeroFiveUp 99 | 100 | public static PeterO.Numbers.ERounding ZeroFiveUp = 9; 101 | 102 | Obsolete. Use ERounding.OddOrZeroFiveUp instead. 103 | 104 | If there is a fractional part and if the last digit before rounding is 0 or half the radix, the number is rounded to the closest representable number away from zero; otherwise the fractional part is discarded. In overflow, the fractional part is always discarded. 105 | -------------------------------------------------------------------------------- /docs/PeterO.Numbers.ETrapException.md: -------------------------------------------------------------------------------- 1 | ## PeterO.Numbers.ETrapException 2 | 3 | public sealed class ETrapException : 4 | System.ArithmeticException, 5 | System.Runtime.Serialization.ISerializable 6 | 7 | Exception thrown for arithmetic trap errors. (The "E" stands for "extended", and has this prefix to group it with the other classes common to this library, particularly EDecimal, EFloat, and ERational.). This library may throw exceptions of this type in certain cases, notably when errors occur, and may supply messages to those exceptions (the message can be accessed through the `Message` property in.NET or the `getMessage()` method in Java). These messages are intended to be read by humans to help diagnose the error (or other cause of the exception); they are not intended to be parsed by computer programs, and the exact text of the messages may change at any time between versions of this library. 8 | 9 | ### Member Summary 10 | * [Context](#Context) - Gets the arithmetic context used during the operation that triggered the trap. 11 | * [Error](#Error) - Gets the flag that specifies the primary kind of error in one or more operations (EContext. 12 | * [Errors](#Errors) - Gets the flags that were signaled as the result of one or more operations. 13 | * [HasError(int)](#HasError_int) - Returns whether this trap exception specifies all the flags given. 14 | * [Result](#Result) - Gets the defined result of the operation that caused the trap. 15 | 16 | 17 | ### ETrapException Constructor 18 | 19 | public ETrapException( 20 | int flag, 21 | PeterO.Numbers.EContext ctx, 22 | object result); 23 | 24 | Initializes a new instance of the [PeterO.Numbers.ETrapException](PeterO.Numbers.ETrapException.md) class. 25 | 26 | Parameters: 27 | 28 | * flag: The flag that specifies the kind of error from one or more operations (EContext.FlagXXX). This will only be one flag, such as `FlagInexact` or FlagSubnormal. 29 | 30 | * ctx: The arithmetic context used during the operation that triggered the trap. Can be null. 31 | 32 | * result: The defined result of the operation that caused the trap. 33 | 34 | 35 | ### ETrapException Constructor 36 | 37 | public ETrapException( 38 | int flags, 39 | int flag, 40 | PeterO.Numbers.EContext ctx, 41 | object result); 42 | 43 | Initializes a new instance of the [PeterO.Numbers.ETrapException](PeterO.Numbers.ETrapException.md) class. 44 | 45 | Parameters: 46 | 47 | * flags: Specifies the flags that were signaled as the result of one or more operations. This includes the flag specified in the "flag" parameter, but can include other flags. For instance, if "flag" is `EContext.FlagInexact` , this parameter might be `EContext.FlagInexact | EContext.FlagRounded` . 48 | 49 | * flag: Specifies the flag that specifies the primary kind of error from one or more operations (EContext.FlagXXX). This will only be one flag, such as `FlagInexact` or FlagSubnormal. 50 | 51 | * ctx: The arithmetic context used during the operation that triggered the trap. Can be null. 52 | 53 | * result: The defined result of the operation that caused the trap. 54 | 55 | Exceptions: 56 | 57 | * System.ArgumentException: 58 | The parameter flags 59 | doesn't include all the flags in the flag 60 | parameter. 61 | 62 | 63 | ### ETrapException Constructor 64 | 65 | public ETrapException( 66 | string message, 67 | System.Exception innerException); 68 | 69 | Initializes a new instance of the [PeterO.Numbers.ETrapException](PeterO.Numbers.ETrapException.md) class. 70 | 71 | Parameters: 72 | 73 | * message: The parameter message 74 | is a text string. 75 | 76 | * innerException: The parameter innerException 77 | is an Exception object. 78 | 79 | 80 | ### ETrapException Constructor 81 | 82 | public ETrapException( 83 | string message); 84 | 85 | Initializes a new instance of the [PeterO.Numbers.ETrapException](PeterO.Numbers.ETrapException.md) class. 86 | 87 | Parameters: 88 | 89 | * message: The parameter message 90 | is a text string. 91 | 92 | 93 | ### ETrapException Constructor 94 | 95 | public ETrapException(); 96 | 97 | Initializes a new instance of the [PeterO.Numbers.ETrapException](PeterO.Numbers.ETrapException.md) class. 98 | 99 | 100 | ### Context 101 | 102 | public PeterO.Numbers.EContext Context { get; } 103 | 104 | Gets the arithmetic context used during the operation that triggered the trap. May be null. 105 | 106 | Returns: 107 | 108 | The arithmetic context used during the operation that triggered the trap. May be null. 109 | 110 | 111 | ### Error 112 | 113 | public int Error { get; } 114 | 115 | Gets the flag that specifies the primary kind of error in one or more operations (EContext.FlagXXX). This will only be one flag, such as `FlagInexact` or FlagSubnormal. 116 | 117 | Returns: 118 | 119 | The flag that specifies the primary kind of error in one or more operations. 120 | 121 | 122 | ### Errors 123 | 124 | public int Errors { get; } 125 | 126 | Gets the flags that were signaled as the result of one or more operations. This includes the flag specified in the "flag" parameter, but can include other flags. For instance, if "flag" is `EContext.FlagInexact` , this parameter might be `EContext.FlagInexact | EContext.FlagRounded` . 127 | 128 | Returns: 129 | 130 | The flags that specify the errors in one or more operations. 131 | 132 | 133 | ### Result 134 | 135 | public object Result { get; } 136 | 137 | Gets the defined result of the operation that caused the trap. 138 | 139 | Returns: 140 | 141 | The defined result of the operation that caused the trap. 142 | 143 | 144 | ### HasError 145 | 146 | public bool HasError( 147 | int flag); 148 | 149 | Returns whether this trap exception specifies all the flags given. (Flags are signaled in a trap exception as the result of one or more operations involving arbitrary-precision numbers, such as multiplication of two EDecimals.). 150 | 151 | Parameters: 152 | 153 | * flag: A combination of one or more flags, such as `EContext.FlagInexact | EContext.FlagRounded` . 154 | 155 | Return Value: 156 | 157 | True if this exception pertains to all of the flags given in flag 158 | ; otherwise, false. 159 | -------------------------------------------------------------------------------- /examples.md: -------------------------------------------------------------------------------- 1 | # More Examples 2 | 3 | ## Number Conversion 4 | 5 | Converting a hex string to a big integer: 6 | ```c# 7 | public static EInteger HexToEInteger(string hexString){ 8 | // Parse the hexadecimal string as a big integer. Will 9 | // throw a FormatException if the parsing fails 10 | var bigInteger = EInteger.FromRadixString(hexString, 16); 11 | // Optional: Check if the parsed integer is negative 12 | if(bigInteger.Sign < 0) 13 | throw new FormatException("negative hex string"); 14 | return bigInteger; 15 | } 16 | ``` 17 | 18 | Converting a big integer to a `double`: 19 | ```c# 20 | public static double EIntegerToDouble(EInteger bigInteger){ 21 | return EFloat.FromEInteger(bigInteger).ToDouble(); 22 | } 23 | ``` 24 | 25 | Converting a number string to a `double`: 26 | ```c# 27 | public static double StringToDouble(string str){ 28 | return EFloat.FromString(str).ToDouble(); 29 | } 30 | ``` 31 | 32 | Converting to and from the .NET decimal formats: 33 | ```c# 34 | public static EDecimal FromDotNetDecimal(int[] bits) { 35 | int scale = (bits[3] >> 16) & 0xff; 36 | var data = new byte[13]; 37 | data[0] = (byte)(bits[0] & 0xff); 38 | data[1] = (byte)((bits[0] >> 8) & 0xff); 39 | data[2] = (byte)((bits[0] >> 16) & 0xff); 40 | data[3] = (byte)((bits[0] >> 24) & 0xff); 41 | data[4] = (byte)(bits[1] & 0xff); 42 | data[5] = (byte)((bits[1] >> 8) & 0xff); 43 | data[6] = (byte)((bits[1] >> 16) & 0xff); 44 | data[7] = (byte)((bits[1] >> 24) & 0xff); 45 | data[8] = (byte)(bits[2] & 0xff); 46 | data[9] = (byte)((bits[2] >> 8) & 0xff); 47 | data[10] = (byte)((bits[2] >> 16) & 0xff); 48 | data[11] = (byte)((bits[2] >> 24) & 0xff); 49 | data[12] = 0; 50 | var mantissa = EInteger.FromBytes(data, true); 51 | bool negative = (bits[3] >> 31) != 0; 52 | if (negative) { 53 | mantissa = -mantissa; 54 | } 55 | return EDecimal.Create(mantissa, (EInteger)(-scale)); 56 | } 57 | 58 | private static int[] EncodeDotNetDecimal( 59 | EInteger bigmant, 60 | int scale, 61 | bool neg) { 62 | if (scale < 0) { 63 | throw new ArgumentException( 64 | "scale (" + scale + ") is less than 0"); 65 | } 66 | if (scale > 28) { 67 | throw new ArgumentException( 68 | "scale (" + scale + ") is more than " + "28"); 69 | } 70 | var data = bigmant.ToBytes(true); 71 | var a = 0; 72 | var b = 0; 73 | var c = 0; 74 | for (var i = 0; i < Math.Min(4, data.Length); ++i) { 75 | a |= (((int)data[i]) & 0xff) << (i * 8); 76 | } 77 | for (int i = 4; i < Math.Min(8, data.Length); ++i) { 78 | b |= (((int)data[i]) & 0xff) << ((i - 4) * 8); 79 | } 80 | for (int i = 8; i < Math.Min(12, data.Length); ++i) { 81 | c |= (((int)data[i]) & 0xff) << ((i - 8) * 8); 82 | } 83 | int d = scale << 16; 84 | if (neg) { 85 | d |= 1 << 31; 86 | } 87 | return new[] { a, b, c, d }; 88 | } 89 | 90 | public int[] ToDotNetDecimal() { 91 | EDecimal extendedNumber = this; 92 | if (extendedNumber.IsInfinity() || extendedNumber.IsNaN()) { 93 | throw new OverflowException("This object's value is out of range"); 94 | } 95 | try { 96 | var newDecimal = extendedNumber.RoundToPrecision( 97 | EContext.CliDecimal.WithTraps(EContext.FlagOverflow)); 98 | return EncodeDotNetDecimal( 99 | newDecimal.Mantissa.Abs(), 100 | -((int)newDecimal.Exponent), 101 | newDecimal.Mantissa.Sign < 0); 102 | } catch (ETrapException ex) { 103 | throw new OverflowException("This object's value is out of range", ex); 104 | } 105 | } 106 | ``` 107 | --------------------------------------------------------------------------------