├── .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 | [](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 |
--------------------------------------------------------------------------------